Merge pull request #1771 from PurpleI2P/openssl

recent changes
This commit is contained in:
orignal 2022-06-30 11:59:46 -04:00 committed by GitHub
commit d5e1d56fde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
170 changed files with 9752 additions and 3873 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
/build/build_mingw.cmd eol=crlf

View File

@ -4,15 +4,16 @@ on: [push, pull_request]
jobs: jobs:
build: build:
runs-on: macos-latest runs-on: macos-10.15
name: with UPnP name: with UPnP
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Test in FreeBSD - name: Test in FreeBSD
id: test id: test
uses: vmactions/freebsd-vm@v0.1.4 uses: vmactions/freebsd-vm@v0.1.5
with: with:
usesh: true usesh: true
mem: 2048
prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc prepare: pkg install -y devel/cmake devel/gmake devel/boost-libs security/openssl net/miniupnpc
run: | run: |
cd build cd build

View File

@ -8,14 +8,15 @@ defaults:
jobs: jobs:
build: build:
name: Building for ${{ matrix.arch }} name: Building using ${{ matrix.arch }} toolchain
runs-on: windows-latest runs-on: windows-latest
strategy: strategy:
fail-fast: true fail-fast: true
matrix: matrix:
include: [ include: [
{ msystem: MINGW64, arch: x86_64 }, { msystem: UCRT64, arch: ucrt-x86_64, arch_short: x64-ucrt },
{ msystem: MINGW32, arch: i686 } { msystem: MINGW64, arch: x86_64, arch_short: x64 },
{ msystem: MINGW32, arch: i686, arch_short: x86 }
] ]
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -25,11 +26,50 @@ jobs:
msystem: ${{ matrix.msystem }} msystem: ${{ matrix.msystem }}
install: base-devel mingw-w64-${{ matrix.arch }}-gcc mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc install: base-devel mingw-w64-${{ matrix.arch }}-gcc mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc
update: true update: true
- name: build application - name: Build application
run: | run: |
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
make USE_UPNP=yes DEBUG=no -j3 make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes -j3
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v2 uses: actions/upload-artifact@v2
with: with:
name: i2pd-${{ matrix.arch_short }}.exe
path: i2pd.exe
build-xp:
name: Building for Windows XP
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Setup MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: MINGW32
install: base-devel git mingw-w64-i686-gcc mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-miniupnpc
update: true
- name: Build WinXP-capable CRT packages
run: |
git clone https://github.com/msys2/MINGW-packages
pushd MINGW-packages
pushd mingw-w64-headers-git
sed -i 's/0x601/0x501/' PKGBUILD
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
pacman --noconfirm -U mingw-w64-i686-headers-git-*-any.pkg.tar.zst
popd
pushd mingw-w64-crt-git
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
pacman --noconfirm -U mingw-w64-i686-crt-git-*-any.pkg.tar.zst
popd
pushd mingw-w64-winpthreads-git
MINGW_ARCH=mingw32 makepkg-mingw -sCLf --noconfirm
pacman --noconfirm -U mingw-w64-i686-libwinpthread-git-*-any.pkg.tar.zst mingw-w64-i686-winpthreads-git-*-any.pkg.tar.zst
popd
popd
- name: Build application
run: |
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
make USE_UPNP=yes DEBUG=no USE_GIT_VERSION=yes USE_WINXP_FLAGS=yes -j3
- name: Upload artifacts
uses: actions/upload-artifact@v2
with:
name: i2pd-xp.exe
path: i2pd.exe path: i2pd.exe

View File

@ -49,7 +49,7 @@ jobs:
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install devscripts sudo apt-get install devscripts
debchange -v "`git describe --tags`-stretch" -M --distribution stretch "trunk build" debchange -v "`git describe --tags`-stretch" -b -M --distribution stretch "trunk build"
- uses: singingwolfboy/build-dpkg-stretch@v1 - uses: singingwolfboy/build-dpkg-stretch@v1
id: build id: build
with: with:
@ -73,7 +73,7 @@ jobs:
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install devscripts sudo apt-get install devscripts
debchange -v "`git describe --tags`-buster" -M --distribution buster "trunk build" debchange -v "`git describe --tags`-buster" -b -M --distribution buster "trunk build"
- uses: singingwolfboy/build-dpkg-buster@v1 - uses: singingwolfboy/build-dpkg-buster@v1
id: build id: build
with: with:

View File

@ -1,6 +1,11 @@
name: Build containers name: Build containers
on: [push] on:
push:
branches:
- openssl
tags:
- '*'
jobs: jobs:
docker: docker:
@ -58,6 +63,8 @@ jobs:
push: true push: true
tags: | tags: |
purplei2p/i2pd:latest purplei2p/i2pd:latest
purplei2p/i2pd:latest-release
purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}
ghcr.io/purplei2p/i2pd:latest ghcr.io/purplei2p/i2pd:latest
ghcr.io/purplei2p/i2pd:latest-release
ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }} ghcr.io/purplei2p/i2pd:release-${{ env.RELEASE_VERSION }}

1
.gitignore vendored
View File

@ -260,6 +260,7 @@ docs/generated
build/Makefile build/Makefile
# debian stuff # debian stuff
debian/i2pd.1.gz
.pc/ .pc/
# qt # qt

121
ChangeLog
View File

@ -1,6 +1,95 @@
# 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.42.1] - 2022-05-24
### Fixed
- Incorrect jump link in HTTP Proxy
## [2.42.0] - 2022-05-22
### Added
- Preliminary SSU2 implementation
- Tunnel length variance
- Localization to French
- Daily cleanup of obsolete peer profiles
- Ordered jump services list in HTTP proxy
- Win32 service
- Show port for local non-published SSU addresses in web console
### Changed
- Maximum RouterInfo length increased to 3K
- Skip unknown addresses in RouterInfo
- Don't pick own router for peer test
- Reseeds list
- Internal numeric id for families
- Use ipv6 preference only when netinet headers not used
- Close stream if delete requested
- Remove version from title in web console
- Drop MESHNET build option
- Set data path before initialization
- Don't show registration block in web console if token is not provided
### Fixed
- Encrypted LeaseSet for EdDSA signature
- Clients tunnels are not built if clock is not synced on start
- Incorrect processing of i2cp.dontPublishLeaseSet param
- UDP tunnels reload
- Build for LibreSSL 3.5.2
- Race condition in short tunnel build message
- Race condition in local RouterInfo buffer allocation
## [2.41.0] - 2022-02-20
### Added
- Clock syncronization through SSU
- Drop routers older than 6 months on start
- Localization to German
- Don't send streaming ack too frequently
- Select compatible outbound tunnel for I2CP messages
- Restart webconsole's acceptor in case of exception
### Changed
- Use builtin bitswap for endian on windows
- Send SessionCreated before connection close if clock skew
- Try another floodfill for publishing if no compatible tunnels found
- Reduce memory usage for RouterInfo structures
- Avoid duplicated addresses in RouterInfo. Check presence of netId and version
- Use TCP/IP sockets for I2CP on Android instead local sockets
- Return uptime as integer in I2PControl
- Reseed servers list/cerificates
- Webconsole's dark style colors
### Fixed
- Attempt to use Yggdrasil on start on Android
- Attempts to send peer tests to itself
- Severe packets drop in SSU
- Crash on tunnel tests
- Loading addressbook subscriptions from config
- Multiple I2CP session to the same destination
- Build on Apple Silicon
## [2.40.0] - 2021-11-29
### Added
- Keep alive parameter for client tunnels
- Support openssl 3.0.0
- Localization to Armenian
- Show git commit info in version
- Windows menu item for opening datadir
- Reseed if too few floodfills
- Don't publish old and replacing tunnel in LeaseSet
- Webconsole light/dark theme depending on system settings (via CSS)
### Changed
- Set gzip compression to false by default
- Build tunnel through ECIES routers only
- Removed ElGamal support for tunnels
- Moved webconsole resources to separate file
- Pick tunnels with compatible transport with another tunnel of floodfill
- Use common cleanup timer for all SSU sessions
- Reduced memory usage
- Reseed servers list
- i18n code called from ClientContext
### Fixed
- Tunnels reload
- Some typos in log messages
- Cleanup relay requests table
- Server tunnel is not published
- Build on GNU/Hurd. Disable pthread_setname_np
- Crash when incorrect sigtype used with blinding
## [2.39.0] - 2021-08-23 ## [2.39.0] - 2021-08-23
### Added ### Added
- Short tunnel build messages - Short tunnel build messages
@ -18,11 +107,11 @@
- Better distribution for random tunnel's peer selection - Better distribution for random tunnel's peer selection
- Yggdrasil reseed for v0.4, added two more - Yggdrasil reseed for v0.4, added two more
- Encryption type 0,4 by default for server tunnels - Encryption type 0,4 by default for server tunnels
- Handle i2cp.dontPublishLeaseSet param for all destinations - Handle i2cp.dontPublishLeaseSet param for all destinations
- reg.i2p for subscriptions - reg.i2p for subscriptions
- LeaseSet type 3 by default - LeaseSet type 3 by default
- Don't allocate payload buffer for every single ECIESx25519 message - Don't allocate payload buffer for every single ECIESx25519 message
- Prefer public ipv6 instead rfc4941 - Prefer public ipv6 instead rfc4941
- Optimal padding for one-time ECIESx25519 message - Optimal padding for one-time ECIESx25519 message
- Don't send datetime block for one-time ECIESx25519 message with one-time key - Don't send datetime block for one-time ECIESx25519 message with one-time key
- Router with expired introducer is still valid - Router with expired introducer is still valid
@ -46,7 +135,7 @@
## [2.38.0] - 2021-05-17 ## [2.38.0] - 2021-05-17
### Added ### Added
- Publish ipv6 introducers - Publish ipv6 introducers
- Bind ipv6 or yggdrasil NTCP2 acceptor to specified address - Bind ipv6 or yggdrasil NTCP2 acceptor to specified address
- Support .b32.i2p addresses and hostnames for SAM STREAM CREATE - Support .b32.i2p addresses and hostnames for SAM STREAM CREATE
- ipv6 peer tests - ipv6 peer tests
- Publish iexp param for introducers - Publish iexp param for introducers
@ -82,12 +171,12 @@
- Symmetric NAT network status error - Symmetric NAT network status error
- Bind server tunnel connection to specified address - Bind server tunnel connection to specified address
- lookuplocal BOB extended command - lookuplocal BOB extended command
- address4 and address6 parameters to bind outgoing connections to - address4 and address6 parameters to bind outgoing connections to
- Rekey of low-bandwidth routers to ECIES - Rekey of low-bandwidth routers to ECIES
- Popup notification windows when unable to parse config for Windows - Popup notification windows when unable to parse config for Windows
### Changed ### Changed
- Floodfills with "U" cap are not ignored anymore - Floodfills with "U" cap are not ignored anymore
- Check transports reachability between tunnel peers and between router and floodfill - Check transports reachability between tunnel peers and between router and floodfill
- NTCP2 and reseed HTTP proxy support authorization now - NTCP2 and reseed HTTP proxy support authorization now
- Show actual IP addresses for proxy connections - Show actual IP addresses for proxy connections
- Publish and handle SSU addreses without host - Publish and handle SSU addreses without host
@ -109,22 +198,22 @@
- Dump addressbook in hosts.txt format - Dump addressbook in hosts.txt format
- Request RouterInfo through exploratory tunnels if direct connection to fllodfill is not possible - Request RouterInfo through exploratory tunnels if direct connection to fllodfill is not possible
- Threads naming - Threads naming
- Check if public x25519 key is valid - Check if public x25519 key is valid
- ECIES-X25519-AEAD-Ratchet for shared local destination - ECIES-X25519-AEAD-Ratchet for shared local destination
- LeaseSet creation timeout for I2CP session - LeaseSet creation timeout for I2CP session
- Resend RouterInfo after some interval for longer NTCP2 sessions - Resend RouterInfo after some interval for longer NTCP2 sessions
- Select reachable router of inbound tunnel gateway - Select reachable router of inbound tunnel gateway
- Reseed if no compatible routers in netdb - Reseed if no compatible routers in netdb
- Refresh on swipe in Android webconsole - Refresh on swipe in Android webconsole
### Changed ### Changed
- reg.i2p for default addressbook instead inr.i2p - reg.i2p for default addressbook instead inr.i2p
- ECIES-x25519 (crypto type 4) for new routers - ECIES-x25519 (crypto type 4) for new routers
- Try to connect to all compatible addresses from peer's RouterInfo - Try to connect to all compatible addresses from peer's RouterInfo
- Replace LeaseSet completely if store type changes - Replace LeaseSet completely if store type changes
- Try ECIES-X25519-AEAD-Ratchet tag before ElGamal - Try ECIES-X25519-AEAD-Ratchet tag before ElGamal
- Don't detach ECIES-X25519-AEAD-Ratchet session from destination immediately - Don't detach ECIES-X25519-AEAD-Ratchet session from destination immediately
- Viewport and styles on error in HTTP proxy - Viewport and styles on error in HTTP proxy
- Don't create notification when Windows taskbar restarted - Don't create notification when Windows taskbar restarted
- Cumulative SSU ACK bitfields - Cumulative SSU ACK bitfields
- limit tunnel length to 8 hops - limit tunnel length to 8 hops
- Limit tunnels quantity to 16 - Limit tunnels quantity to 16
@ -157,7 +246,7 @@
- Transient signature length, if different from identity - Transient signature length, if different from identity
- Terminate I2CP session if destroyed - Terminate I2CP session if destroyed
- RouterInfo publishing confirmation - RouterInfo publishing confirmation
- Check if ECIES-X25519-AEAD-Ratchet session expired before generating more tags - Check if ECIES-X25519-AEAD-Ratchet session expired before generating more tags
- Correct block size for delivery type local for ECIES-X25519-AEAD-Ratchet - Correct block size for delivery type local for ECIES-X25519-AEAD-Ratchet
## [2.34.0] - 2020-10-27 ## [2.34.0] - 2020-10-27
@ -168,7 +257,7 @@
- Single thread for I2CP - Single thread for I2CP
- Shared transient destination between proxies - Shared transient destination between proxies
- Database lookups from ECIES destinations with ratchets response - Database lookups from ECIES destinations with ratchets response
- Handle WebDAV HTTP methods - Handle WebDAV HTTP methods
- Don't try to connect or build tunnels if offline - Don't try to connect or build tunnels if offline
- Validate IP when trying connect to remote peer - Validate IP when trying connect to remote peer
- Handle ICMP responses and WinAPI errors for SSU - Handle ICMP responses and WinAPI errors for SSU
@ -185,7 +274,7 @@
- Random crashes on I2CP session disconnect - Random crashes on I2CP session disconnect
- Stream through racthets hangs if first SYN was not acked - Stream through racthets hangs if first SYN was not acked
- Check "Last-Modified" instead "If-Modified-Since" for addressbook reponse - Check "Last-Modified" instead "If-Modified-Since" for addressbook reponse
- Trim behind ECIESx25519 tags - Trim behind ECIESx25519 tags
- Few bugs with Android main activity - Few bugs with Android main activity
- QT visual and layout issues - QT visual and layout issues
@ -196,11 +285,11 @@
- Multiple encryption keys through I2CP - Multiple encryption keys through I2CP
- Pre-calculated x25519 ephemeral keys - Pre-calculated x25519 ephemeral keys
- Change datagram routing path if nothing comes back in 10 seconds - Change datagram routing path if nothing comes back in 10 seconds
- Shared routing path for datagram session - Shared routing path for datagram session
### Changed ### Changed
- UDP tunnels send mix of repliable and raw datagrams in bulk - UDP tunnels send mix of repliable and raw datagrams in bulk
- Encrypt SSU packet again upon resend - Encrypt SSU packet again upon resend
- Start new tunnel message if remaining buffer is too small - Start new tunnel message if remaining buffer is too small
- Use LeaseSet2 for ECIES-X25519-AEAD-Ratchet automatically - Use LeaseSet2 for ECIES-X25519-AEAD-Ratchet automatically
- Save new ECIES-X25519-AEAD-Ratchet session with NSR tagset - Save new ECIES-X25519-AEAD-Ratchet session with NSR tagset
- Generate random padding lengths for ECIES-X25519-AEAD-Ratchet in bulk - Generate random padding lengths for ECIES-X25519-AEAD-Ratchet in bulk
@ -208,11 +297,11 @@
- Reseed servers list - Reseed servers list
### Fixed ### Fixed
- Don't connect through terminated SAM destination - Don't connect through terminated SAM destination
- Differentiate UDP server sessions by port - Differentiate UDP server sessions by port
- ECIES-X25519-AEAD-Ratchet through I2CP - ECIES-X25519-AEAD-Ratchet through I2CP
- Don't save invalid address to AddressBook - Don't save invalid address to AddressBook
- ECDSA signatures names in SAM - ECDSA signatures names in SAM
- AppArmor profile - AppArmor profile
## [2.32.1] - 2020-06-02 ## [2.32.1] - 2020-06-02
### Added ### Added

View File

@ -1,8 +1,10 @@
.DEFAULT_GOAL := all
SYS := $(shell $(CXX) -dumpmachine) SYS := $(shell $(CXX) -dumpmachine)
ifneq (, $(findstring darwin, $(SYS))) ifneq (, $(findstring darwin, $(SYS)))
SHARED_SUFFIX = dylib SHARED_SUFFIX = dylib
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS))) else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
SHARED_SUFFIX = dll SHARED_SUFFIX = dll
else else
SHARED_SUFFIX = so SHARED_SUFFIX = so
@ -27,11 +29,16 @@ DAEMON_SRC_DIR := daemon
# import source files lists # import source files lists
include filelist.mk include filelist.mk
USE_AESNI := $(or $(USE_AESNI),yes) USE_AESNI := $(or $(USE_AESNI),yes)
USE_STATIC := $(or $(USE_STATIC),no) USE_STATIC := $(or $(USE_STATIC),no)
USE_MESHNET := $(or $(USE_MESHNET),no) USE_UPNP := $(or $(USE_UPNP),no)
USE_UPNP := $(or $(USE_UPNP),no) DEBUG := $(or $(DEBUG),yes)
DEBUG := $(or $(DEBUG),yes)
# for debugging purposes only, when commit hash needed in trunk builds in i2pd version string
USE_GIT_VERSION := $(or $(USE_GIT_VERSION),no)
# for MacOS only, waiting for "1", not "yes"
HOMEBREW := $(or $(HOMEBREW),0)
ifeq ($(DEBUG),yes) ifeq ($(DEBUG),yes)
CXX_DEBUG = -g CXX_DEBUG = -g
@ -53,18 +60,19 @@ else ifneq (, $(findstring linux, $(SYS))$(findstring gnu, $(SYS)))
else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS))) else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.bsd include Makefile.bsd
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS))) else ifneq (, $(findstring mingw, $(SYS))$(findstring windows-gnu, $(SYS))$(findstring cygwin, $(SYS)))
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32NetState.cpp DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32App.cpp Win32/Win32Service.cpp Win32/Win32NetState.cpp
include Makefile.mingw include Makefile.mingw
else # not supported else # not supported
$(error Not supported platform) $(error Not supported platform)
endif endif
ifeq ($(USE_MESHNET),yes) ifeq ($(USE_GIT_VERSION),yes)
NEEDED_CXXFLAGS += -DMESHNET GIT_VERSION := $(shell git describe --tags)
NEEDED_CXXFLAGS += -DGITVER=\"$(GIT_VERSION)\"
endif endif
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) -I$(LANG_SRC_DIR) -DOPENSSL_SUPPRESS_DEPRECATED
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))

View File

@ -39,13 +39,19 @@ ifeq ($(USE_AESNI),yes)
endif endif
install: all install: all
install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd install -d ${PREFIX}/bin
install -m 755 ${I2PD} ${PREFIX}/bin/ install -m 755 ${I2PD} ${PREFIX}/bin
install -d ${PREFIX}/etc ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
@cp -R contrib/certificates ${PREFIX}/share/i2pd/ install -d ${PREFIX}/share ${PREFIX}/share/doc ${PREFIX}/share/doc/i2pd
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
@gzip debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1 install -d ${PREFIX}/share/i2pd
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/ @cp -R contrib/certificates ${PREFIX}/share/i2pd/
install -d ${PREFIX}/share/man ${PREFIX}/share/man/man1
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
install -d ${PREFIX}/var ${PREFIX}/var/lib ${PREFIX}/var/lib/i2pd
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/certificates
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf @ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt @ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf @ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf

View File

@ -62,3 +62,21 @@ ifneq (, $(findstring i386, $(SYS))$(findstring i686, $(SYS))$(findstring x86_64
NEEDED_CXXFLAGS += -D__AES__ -maes NEEDED_CXXFLAGS += -D__AES__ -maes
endif endif
endif endif
install: all
install -d ${PREFIX}/bin
install -m 755 ${I2PD} ${PREFIX}/bin
install -d ${PREFIX}/etc ${PREFIX}/etc/i2pd ${PREFIX}/etc/i2pd/tunnels.conf.d
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
install -d ${PREFIX}/share ${PREFIX}/share/doc ${PREFIX}/share/doc/i2pd
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
install -d ${PREFIX}/share/i2pd
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
install -d ${PREFIX}/share/man ${PREFIX}/share/man/man1
@gzip -kf debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
install -d ${PREFIX}/var ${PREFIX}/var/lib ${PREFIX}/var/lib/i2pd
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/certificates
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf.d ${PREFIX}/var/lib/i2pd/tunnels.d
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf

View File

@ -3,19 +3,11 @@ USE_WIN32_APP := yes
WINDRES = windres WINDRES = windres
CXXFLAGS := $(CXX_DEBUG) -DWIN32_LEAN_AND_MEAN -fPIC -msse CXXFLAGS := $(CXX_DEBUG) -fPIC -msse
INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32 INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32
LDFLAGS := ${LD_DEBUG} -static LDFLAGS := ${LD_DEBUG} -static
# detect proper flag for c++11 support by compilers NEEDED_CXXFLAGS += -std=c++17 -DWIN32_LEAN_AND_MEAN
CXXVER := $(shell $(CXX) -dumpversion)
ifeq ($(shell expr match ${CXXVER} "[4]\.[7-9]\|4\.1[0-9]\|[5-6]"),4) # gcc 4.7 - 6
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "[1,7-9]"),1) # gcc >= 7
NEEDED_CXXFLAGS += -std=c++17
else # not supported
$(error Compiler too old)
endif
# Boost libraries suffix # Boost libraries suffix
BOOST_SUFFIX = -mt BOOST_SUFFIX = -mt

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, The PurpleI2P Project * Copyright (c) 2013-2022, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -14,6 +14,7 @@
#include "Log.h" #include "Log.h"
#ifdef _WIN32 #ifdef _WIN32
#include "Win32Service.h"
#ifdef WIN32_APP #ifdef WIN32_APP
#include <windows.h> #include <windows.h>
#include "Win32App.h" #include "Win32App.h"
@ -39,6 +40,19 @@ namespace util
if (!Daemon_Singleton::init(argc, argv)) if (!Daemon_Singleton::init(argc, argv))
return false; return false;
if (isDaemon)
{
LogPrint(eLogDebug, "Daemon: running as service");
I2PService service((PSTR)SERVICE_NAME);
if (!I2PService::Run(service))
{
LogPrint(eLogError, "Daemon: Service failed to run w/err 0x%08lx\n", GetLastError());
return false;
}
return false;
}
return true; return true;
} }

View File

@ -25,7 +25,7 @@ BEGIN
VALUE "FileDescription", "C++ I2P daemon" VALUE "FileDescription", "C++ I2P daemon"
VALUE "FileVersion", I2PD_VERSION VALUE "FileVersion", I2PD_VERSION
VALUE "InternalName", CODENAME VALUE "InternalName", CODENAME
VALUE "LegalCopyright", "Copyright (C) 2013-2020, The PurpleI2P Project" VALUE "LegalCopyright", "Copyright (C) 2013-2022, The PurpleI2P Project"
VALUE "OriginalFilename", "i2pd" VALUE "OriginalFilename", "i2pd"
VALUE "ProductName", "Purple I2P" VALUE "ProductName", "Purple I2P"
VALUE "ProductVersion", I2P_VERSION VALUE "ProductVersion", I2P_VERSION

View File

@ -31,6 +31,7 @@
#define ID_RELOAD 2006 #define ID_RELOAD 2006
#define ID_ACCEPT_TRANSIT 2007 #define ID_ACCEPT_TRANSIT 2007
#define ID_DECLINE_TRANSIT 2008 #define ID_DECLINE_TRANSIT 2008
#define ID_DATADIR 2009
#define ID_TRAY_ICON 2050 #define ID_TRAY_ICON 2050
#define WM_TRAYICON (WM_USER + 1) #define WM_TRAYICON (WM_USER + 1)
@ -49,7 +50,8 @@ namespace win32
{ {
HMENU hPopup = CreatePopupMenu(); HMENU hPopup = CreatePopupMenu();
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_CONSOLE, "Open &console"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_CONSOLE, "Open &console");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "Show app"); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_DATADIR, "Open &datadir");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_APP, "&Show app");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About..."); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_STRING, ID_ABOUT, "&About...");
InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); InsertMenu (hPopup, -1, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
if(!i2p::context.AcceptsTunnels()) if(!i2p::context.AcceptsTunnels())
@ -303,6 +305,12 @@ namespace win32
SetTimer(hWnd, FRAME_UPDATE_TIMER, 3000, NULL); SetTimer(hWnd, FRAME_UPDATE_TIMER, 3000, NULL);
return 0; return 0;
} }
case ID_DATADIR:
{
std::string datadir(i2p::fs::GetUTF8DataDir());
ShellExecute(NULL, "explore", datadir.c_str(), NULL, NULL, SW_SHOWNORMAL);
return 0;
}
} }
break; break;
} }

View File

@ -32,7 +32,7 @@ void SubscribeToEvents()
Result = pNetworkListManager->IsConnectedToInternet(&IsConnect); Result = pNetworkListManager->IsConnectedToInternet(&IsConnect);
if (SUCCEEDED(Result)) { if (SUCCEEDED(Result)) {
i2p::transport::transports.SetOnline (true); i2p::transport::transports.SetOnline (true);
LogPrint(eLogInfo, "NetState: current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected"); LogPrint(eLogInfo, "NetState: Current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected");
} }
Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void **)&pCPContainer); Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void **)&pCPContainer);
@ -79,7 +79,7 @@ void UnSubscribeFromEvents()
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "NetState: received exception: ", ex.what ()); LogPrint (eLogError, "NetState: Received exception: ", ex.what ());
} }
} }

283
Win32/Win32Service.cpp Normal file
View File

@ -0,0 +1,283 @@
/*
* Copyright (c) 2013-2022, 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 "Win32Service.h"
#include <assert.h>
#include <windows.h>
#include "Daemon.h"
#include "Log.h"
I2PService *I2PService::s_service = NULL;
BOOL I2PService::isService()
{
BOOL bIsService = FALSE;
HWINSTA hWinStation = GetProcessWindowStation();
if (hWinStation != NULL)
{
USEROBJECTFLAGS uof = { 0 };
if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
{
bIsService = TRUE;
}
}
return bIsService;
}
BOOL I2PService::Run(I2PService &service)
{
s_service = &service;
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ service.m_name, ServiceMain },
{ NULL, NULL }
};
return StartServiceCtrlDispatcher(serviceTable);
}
void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv)
{
assert(s_service != NULL);
s_service->m_statusHandle = RegisterServiceCtrlHandler(
s_service->m_name, ServiceCtrlHandler);
if (s_service->m_statusHandle == NULL)
{
throw GetLastError();
}
s_service->Start(dwArgc, pszArgv);
}
void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl)
{
switch (dwCtrl)
{
case SERVICE_CONTROL_STOP: s_service->Stop(); break;
case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
case SERVICE_CONTROL_INTERROGATE: break;
default: break;
}
}
I2PService::I2PService(PSTR pszServiceName,
BOOL fCanStop,
BOOL fCanShutdown,
BOOL fCanPauseContinue)
{
m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName;
m_statusHandle = NULL;
m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_status.dwCurrentState = SERVICE_START_PENDING;
DWORD dwControlsAccepted = 0;
if (fCanStop)
dwControlsAccepted |= SERVICE_ACCEPT_STOP;
if (fCanShutdown)
dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
if (fCanPauseContinue)
dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
m_status.dwControlsAccepted = dwControlsAccepted;
m_status.dwWin32ExitCode = NO_ERROR;
m_status.dwServiceSpecificExitCode = 0;
m_status.dwCheckPoint = 0;
m_status.dwWaitHint = 0;
m_fStopping = FALSE;
// Create a manual-reset event that is not signaled at first to indicate
// the stopped signal of the service.
m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (m_hStoppedEvent == NULL)
{
throw GetLastError();
}
}
I2PService::~I2PService(void)
{
if (m_hStoppedEvent)
{
CloseHandle(m_hStoppedEvent);
m_hStoppedEvent = NULL;
}
}
void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
{
try
{
SetServiceStatus(SERVICE_START_PENDING);
OnStart(dwArgc, pszArgv);
SetServiceStatus(SERVICE_RUNNING);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Start error: ", dwError);
SetServiceStatus(SERVICE_STOPPED, dwError);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: failed to start: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_STOPPED);
}
}
void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
{
LogPrint(eLogInfo, "Win32Service: in OnStart (", EVENTLOG_INFORMATION_TYPE, ")");
Daemon.start();
_worker = new std::thread(std::bind(&I2PService::WorkerThread, this));
}
void I2PService::WorkerThread()
{
while (!m_fStopping)
{
::Sleep(1000); // Simulate some lengthy operations.
}
// Signal the stopped event.
SetEvent(m_hStoppedEvent);
}
void I2PService::Stop()
{
DWORD dwOriginalState = m_status.dwCurrentState;
try
{
SetServiceStatus(SERVICE_STOP_PENDING);
OnStop();
SetServiceStatus(SERVICE_STOPPED);
}
catch (DWORD dwError)
{
LogPrint(eLogInfo, "Win32Service: Stop error: ", dwError);
SetServiceStatus(dwOriginalState);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to stop: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(dwOriginalState);
}
}
void I2PService::OnStop()
{
// Log a service stop message to the Application log.
LogPrint(eLogInfo, "Win32Service: in OnStop (", EVENTLOG_INFORMATION_TYPE, ")");
Daemon.stop();
m_fStopping = TRUE;
if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
{
throw GetLastError();
}
_worker->join();
delete _worker;
}
void I2PService::Pause()
{
try
{
SetServiceStatus(SERVICE_PAUSE_PENDING);
OnPause();
SetServiceStatus(SERVICE_PAUSED);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Pause error: ", dwError);
SetServiceStatus(SERVICE_RUNNING);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to pause: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_RUNNING);
}
}
void I2PService::OnPause()
{
}
void I2PService::Continue()
{
try
{
SetServiceStatus(SERVICE_CONTINUE_PENDING);
OnContinue();
SetServiceStatus(SERVICE_RUNNING);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Continue error: ", dwError);
SetServiceStatus(SERVICE_PAUSED);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to resume: ", EVENTLOG_ERROR_TYPE);
SetServiceStatus(SERVICE_PAUSED);
}
}
void I2PService::OnContinue()
{
}
void I2PService::Shutdown()
{
try
{
OnShutdown();
SetServiceStatus(SERVICE_STOPPED);
}
catch (DWORD dwError)
{
LogPrint(eLogError, "Win32Service: Shutdown error: ", dwError);
}
catch (...)
{
LogPrint(eLogError, "Win32Service: Failed to shut down: ", EVENTLOG_ERROR_TYPE);
}
}
void I2PService::OnShutdown()
{
}
void I2PService::SetServiceStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
m_status.dwCurrentState = dwCurrentState;
m_status.dwWin32ExitCode = dwWin32ExitCode;
m_status.dwWaitHint = dwWaitHint;
m_status.dwCheckPoint =
((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED)) ?
0 : dwCheckPoint++;
::SetServiceStatus(m_statusHandle, &m_status);
}
//*****************************************************************************
void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService)
{
if (schSCManager)
{
CloseServiceHandle(schSCManager);
schSCManager = NULL;
}
if (schService)
{
CloseServiceHandle(schService);
schService = NULL;
}
}

63
Win32/Win32Service.h Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2013-2022, 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 WIN_32_SERVICE_H__
#define WIN_32_SERVICE_H__
#include <thread>
#include <windows.h>
#define SERVICE_NAME "i2pdService"
class I2PService
{
public:
I2PService(PSTR pszServiceName,
BOOL fCanStop = TRUE,
BOOL fCanShutdown = TRUE,
BOOL fCanPauseContinue = FALSE);
virtual ~I2PService(void);
static BOOL isService();
static BOOL Run(I2PService &service);
void Stop();
protected:
virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
virtual void OnStop();
virtual void OnPause();
virtual void OnContinue();
virtual void OnShutdown();
void SetServiceStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode = NO_ERROR,
DWORD dwWaitHint = 0);
private:
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);
void WorkerThread();
void Start(DWORD dwArgc, PSTR *pszArgv);
void Pause();
void Continue();
void Shutdown();
static I2PService* s_service;
PSTR m_name;
SERVICE_STATUS m_status;
SERVICE_STATUS_HANDLE m_statusHandle;
BOOL m_fStopping;
HANDLE m_hStoppedEvent;
std::thread* _worker;
};
#endif // WIN_32_SERVICE_H__

View File

@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 3.7)
# this addresses CMP0059 with CMake > 3.3 for PCH flags cmake_policy(VERSION 3.7)
cmake_policy(VERSION 2.8.12)
project("i2pd") project("i2pd")
# for debugging # for debugging
@ -18,14 +17,13 @@ option(WITH_LIBRARY "Build library" ON)
option(WITH_BINARY "Build binary" ON) option(WITH_BINARY "Build binary" ON)
option(WITH_STATIC "Static build" OFF) option(WITH_STATIC "Static build" OFF)
option(WITH_UPNP "Include support for UPnP client" OFF) option(WITH_UPNP "Include support for UPnP client" OFF)
option(WITH_PCH "Use precompiled header" OFF) option(WITH_GIT_VERSION "Use git commit info as version" OFF)
option(WITH_MESHNET "Build for cjdns test network" OFF)
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF) option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF) option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
# paths # paths
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules") set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
set(CMAKE_SOURCE_DIR "..") set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
#Handle paths nicely #Handle paths nicely
include(GNUInstallDirs) include(GNUInstallDirs)
@ -91,14 +89,20 @@ set(DAEMON_SRC
"${DAEMON_SRC_DIR}/UPnP.cpp" "${DAEMON_SRC_DIR}/UPnP.cpp"
) )
if(WITH_MESHNET)
add_definitions(-DMESHNET)
endif()
if(WITH_UPNP) if(WITH_UPNP)
add_definitions(-DUSE_UPNP) add_definitions(-DUSE_UPNP)
endif() endif()
if(WITH_GIT_VERSION)
include(GetGitRevisionDescription)
git_describe(GIT_VERSION)
add_definitions(-DGITVER="${GIT_VERSION}")
endif()
if(APPLE)
add_definitions(-DMAC_OSX)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT. # TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
@ -168,24 +172,13 @@ endif()
# libraries # libraries
# TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826
# use imported Threads::Threads instead
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
if(IOS) find_package(Threads REQUIRED)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1)
else()
find_package(Threads REQUIRED)
endif()
if(THREADS_HAVE_PTHREAD_ARG) # compile time flag
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
if(WITH_STATIC) if(WITH_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON) set(Boost_USE_STATIC_RUNTIME ON)
set(OPENSSL_USE_STATIC_LIBS ON)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*") if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
@ -200,23 +193,6 @@ else()
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK) add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
endif() endif()
if(WITH_PCH)
include_directories(BEFORE ${CMAKE_BINARY_DIR})
add_library(stdafx STATIC "${LIBI2PD_SRC_DIR}/stdafx.cpp")
string(TOUPPER ${CMAKE_BUILD_TYPE} BTU)
get_directory_property(DEFS DEFINITIONS)
string(REPLACE " " ";" FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTU}} ${DEFS}")
add_custom_command(TARGET stdafx PRE_BUILD
COMMAND ${CMAKE_CXX_COMPILER} ${FLAGS} -c ${CMAKE_CURRENT_SOURCE_DIR}/../libi2pd/stdafx.h -o ${CMAKE_BINARY_DIR}/stdafx.h.gch
)
target_compile_options(libi2pd PRIVATE -include libi2pd/stdafx.h)
target_compile_options(libi2pdclient PRIVATE -include libi2pd/stdafx.h)
target_compile_options(libi2pdlang PRIVATE -include libi2pd/stdafx.h)
target_link_libraries(libi2pd stdafx)
endif()
target_link_libraries(libi2pdclient libi2pd libi2pdlang)
find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED) find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
if(NOT DEFINED Boost_INCLUDE_DIRS) if(NOT DEFINED Boost_INCLUDE_DIRS)
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
@ -227,6 +203,10 @@ if(NOT DEFINED OPENSSL_INCLUDE_DIR)
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!") message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
endif() endif()
if(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0")
add_definitions(-DOPENSSL_SUPPRESS_DEPRECATED)
endif()
if(WITH_UPNP) if(WITH_UPNP)
find_package(MiniUPnPc REQUIRED) find_package(MiniUPnPc REQUIRED)
if(NOT MINIUPNPC_FOUND) if(NOT MINIUPNPC_FOUND)
@ -244,15 +224,7 @@ endif()
# load includes # load includes
include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
# warn if for meshnet include(CheckAtomic)
if(WITH_MESHNET)
message(STATUS "Building for testnet")
message(WARNING "This build will NOT work on mainline i2p")
endif()
if(NOT MSYS)
include(CheckAtomic)
endif()
# show summary # show summary
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
@ -269,8 +241,7 @@ message(STATUS " LIBRARY : ${WITH_LIBRARY}")
message(STATUS " BINARY : ${WITH_BINARY}") message(STATUS " BINARY : ${WITH_BINARY}")
message(STATUS " STATIC BUILD : ${WITH_STATIC}") message(STATUS " STATIC BUILD : ${WITH_STATIC}")
message(STATUS " UPnP : ${WITH_UPNP}") message(STATUS " UPnP : ${WITH_UPNP}")
message(STATUS " PCH : ${WITH_PCH}") message(STATUS " GIT VERSION : ${WITH_GIT_VERSION}")
message(STATUS " MESHNET : ${WITH_MESHNET}")
message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}") message(STATUS " ADDRSANITIZER : ${WITH_ADDRSANITIZER}")
message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}") message(STATUS " THREADSANITIZER : ${WITH_THREADSANITIZER}")
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
@ -282,31 +253,21 @@ if(WITH_BINARY)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static") set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
endif() endif()
if(WITH_PCH)
target_compile_options("${PROJECT_NAME}" PRIVATE -include libi2pd/stdafx.h)
endif()
if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now") set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now")
endif() endif()
if(WITH_UPNP)
set(UPNP_LIB ${MINIUPNPC_LIBRARY})
endif()
# FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04 # FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04
list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES) list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES)
if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*") if(${LAST_Boost_LIBRARIES} MATCHES ".*pthread.*")
list(REMOVE_AT Boost_LIBRARIES -1) list(REMOVE_AT Boost_LIBRARIES -1)
endif() endif()
if(WITH_STATIC) if(WITH_STATIC)
set(DL_LIB ${CMAKE_DL_LIBS}) set(DL_LIB ${CMAKE_DL_LIBS})
endif() endif()
target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY}) target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto ${MINIUPNPC_LIBRARY} ZLIB::ZLIB Threads::Threads ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient libi2pdlang ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}") set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")

View File

@ -2,26 +2,25 @@
setlocal enableextensions enabledelayedexpansion setlocal enableextensions enabledelayedexpansion
title Building i2pd title Building i2pd
REM Copyright (c) 2013-2020, The PurpleI2P Project REM Copyright (c) 2013-2022, The PurpleI2P Project
REM This file is part of Purple i2pd project and licensed under BSD3 REM This file is part of Purple i2pd project and licensed under BSD3
REM See full license text in LICENSE file at top of project tree REM See full license text in LICENSE file at top of project tree
REM To use that script, you must have installed in your MSYS installation these packages: REM To use that script, you must have installed in your MSYS installation these packages:
REM Base: git make zip REM Base: git make zip
REM x86_64: mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-gcc REM UCRT64: mingw-w64-ucrt-x86_64-boost mingw-w64-ucrt-x86_64-openssl mingw-w64-ucrt-x86_64-gcc
REM i686: mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-gcc REM MINGW32: mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-gcc
REM setting up variables for MSYS REM setting up variables for MSYS
REM Note: if you installed MSYS64 to different path, edit WD variable (only C:\msys64 needed to edit)! REM Note: if you installed MSYS64 to different path, edit WD variable (only C:\msys64 needed to edit)
set "WD=C:\msys64\usr\bin\"
set MSYS2_PATH_TYPE=inherit set MSYS2_PATH_TYPE=inherit
set CHERE_INVOKING=enabled_from_arguments set CHERE_INVOKING=enabled_from_arguments
REM set MSYSTEM=MSYS
set MSYSTEM=MINGW32 set MSYSTEM=MINGW32
set "WD=C:\msys64\usr\bin\"
set "xSH=%WD%bash -lc" set "xSH=%WD%bash -lc"
set "FILELIST=i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates contrib/tunnels.d" set "FILELIST=i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates contrib/tunnels.d contrib/webconsole"
REM detecting number of processors REM detecting number of processors
set /a threads=%NUMBER_OF_PROCESSORS% set /a threads=%NUMBER_OF_PROCESSORS%
@ -34,38 +33,73 @@ del /S build_*.log >> nul 2>&1
echo Receiving latest commit and cleaning up... echo Receiving latest commit and cleaning up...
%xSH% "git checkout contrib/* && git pull && make clean" > build\build.log 2>&1 %xSH% "git checkout contrib/* && git pull && make clean" > build\build.log 2>&1
echo.
REM set to variable current commit hash REM set to variable current commit hash
FOR /F "usebackq" %%a IN (`%xSH% 'git describe --tags'`) DO ( for /F "usebackq" %%a in (`%xSH% "git describe --tags"`) DO (
set tag=%%a set tag=%%a
) )
REM set to variable latest released tag
for /F "usebackq" %%b in (`%xSH% "git describe --abbrev=0"`) DO (
set reltag=%%b
)
echo Preparing configuration files and README for packaging...
%xSH% "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul %xSH% "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul
REM converting configuration files to DOS format (usable in default notepad) REM converting configuration files to DOS format (make usable in Windows Notepad)
%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/*" >> build\build.log 2>&1 %xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/* contrib/webconsole/style.css" >> build\build.log 2>&1
REM Prepare binary signing command if signing key and password provided
if defined SIGN (
echo Signing enabled
for %%X in (signtool.exe) do (set xSIGNTOOL=%%~$PATH:X)
if not defined xSIGNTOOL (
if not defined SIGNTOOL (
echo Error: Can't find signtool. Please provide path to binary using SIGNTOOL variable.
exit /b 1
) else (
set "xSIGNTOOL=%SIGNTOOL%"
)
)
if defined SIGNKEY (
set "xSIGNKEYOPTS=/f ^"%SIGNKEY%^""
)
if defined SIGNPASS (
set "xSIGNPASSOPTS=/p ^"%SIGNPASS%^""
)
set "xSIGNOPTS=sign /tr http://timestamp.digicert.com /td sha256 /fd sha256 %xSIGNKEYOPTS% %xSIGNPASSOPTS%"
)
REM starting building REM starting building
set MSYSTEM=MINGW32 set MSYSTEM=MINGW32
set bitness=32 set bitness=32
call :BUILDING call :BUILDING
set MSYSTEM=MINGW64 set MSYSTEM=UCRT64
set bitness=64 set bitness=64
call :BUILDING call :BUILDING
REM building for WinXP REM build for Windows XP
set "WD=C:\msys64-xp\usr\bin\" if exist C:\msys64-xp\ ( call :BUILDING_XP )
set MSYSTEM=MINGW32
set bitness=32
set "xSH=%WD%bash -lc"
call :BUILDING_XP
echo. echo.
REM compile installer REM compile installer
C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_TextVer="%tag%" /dI2Pd_Ver="%tag%.0" build\win_installer.iss >> build\build.log 2>&1 echo Building installer...
C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_TextVer="%tag%" /dI2Pd_Ver="%reltag%.0" build\win_installer.iss >> build\build.log 2>&1
REM Sign binary
if defined xSIGNOPTS (
"%xSIGNTOOL%" %xSIGNOPTS% build\setup_i2pd_v%tag%.exe
)
%xSH% "git checkout contrib/*" >> build\build.log 2>&1
del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul
echo Build complete... echo Build complete...
@ -74,13 +108,42 @@ exit /b 0
:BUILDING :BUILDING
%xSH% "make clean" >> nul %xSH% "make clean" >> nul
echo Building i2pd %tag% for win%bitness% echo Building i2pd %tag% for win%bitness%...
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build\build_win%bitness%_%tag%.log 2>&1 REM Build i2pd
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads%" > build\build_win%bitness%_%tag%.log 2>&1
REM Sign binary
if defined xSIGNOPTS (
"%xSIGNTOOL%" %xSIGNOPTS% i2pd.exe
)
REM Copy binary for installer and create distribution archive
%xSH% "cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST%" >> build\build_win%bitness%_%tag%.log 2>&1
REM Clean work directory
%xSH% "make clean" >> build\build_win%bitness%_%tag%.log 2>&1
goto EOF goto EOF
:BUILDING_XP :BUILDING_XP
%xSH% "make clean" >> nul set MSYSTEM=MINGW32
echo Building i2pd %tag% for winxp set bitness=32
%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build\build_winxp_%tag%.log 2>&1 set "WD=C:\msys64-xp\usr\bin\"
set "xSH=%WD%bash -lc"
:EOF %xSH% "make clean" >> nul
echo Building i2pd %tag% for winxp...
%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads%" > build\build_winxp_%tag%.log 2>&1
REM Sign binary
if defined xSIGNOPTS (
"%xSIGNTOOL%" %xSIGNOPTS% i2pd.exe
)
REM Copy binary for installer and create distribution archive
%xSH% "cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST%" >> build\build_winxp_%tag%.log 2>&1
REM Clean work directory
%xSH% "make clean" >> build\build_winxp_%tag%.log 2>&1
goto EOF
:EOF

View File

@ -0,0 +1,284 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_describe_working_tree(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the working tree (--dirty option),
# and adjusting the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# git_local_changes(<var>)
#
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
# Uses the return code of "git diff-index --quiet HEAD --".
# Does not regard untracked files.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2020 Ryan Pavlik <ryan.pavlik@gmail.com> <abiryan@ryand.net>
# http://academic.cleardefinition.com
#
# Copyright 2009-2013, Iowa State University.
# Copyright 2013-2020, Ryan Pavlik
# Copyright 2013-2020, Contributors
# SPDX-License-Identifier: BSL-1.0
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
# Function _git_find_closest_git_dir finds the next closest .git directory
# that is part of any directory in the path defined by _start_dir.
# The result is returned in the parent scope variable whose name is passed
# as variable _git_dir_var. If no .git directory can be found, the
# function returns an empty string via _git_dir_var.
#
# Example: Given a path C:/bla/foo/bar and assuming C:/bla/.git exists and
# neither foo nor bar contain a file/directory .git. This wil return
# C:/bla/.git
#
function(_git_find_closest_git_dir _start_dir _git_dir_var)
set(cur_dir "${_start_dir}")
set(git_dir "${_start_dir}/.git")
while(NOT EXISTS "${git_dir}")
# .git dir not found, search parent directories
set(git_previous_parent "${cur_dir}")
get_filename_component(cur_dir "${cur_dir}" DIRECTORY)
if(cur_dir STREQUAL git_previous_parent)
# We have reached the root directory, we are not in git
set(${_git_dir_var}
""
PARENT_SCOPE)
return()
endif()
set(git_dir "${cur_dir}/.git")
endwhile()
set(${_git_dir_var}
"${git_dir}"
PARENT_SCOPE)
endfunction()
function(get_git_head_revision _refspecvar _hashvar)
_git_find_closest_git_dir("${CMAKE_CURRENT_SOURCE_DIR}" GIT_DIR)
if("${ARGN}" STREQUAL "ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR")
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR TRUE)
else()
set(ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR FALSE)
endif()
if(NOT "${GIT_DIR}" STREQUAL "")
file(RELATIVE_PATH _relative_to_source_dir "${CMAKE_SOURCE_DIR}"
"${GIT_DIR}")
if("${_relative_to_source_dir}" MATCHES "[.][.]" AND NOT ALLOW_LOOKING_ABOVE_CMAKE_SOURCE_DIR)
# We've gone above the CMake root dir.
set(GIT_DIR "")
endif()
endif()
if("${GIT_DIR}" STREQUAL "")
set(${_refspecvar}
"GITDIR-NOTFOUND"
PARENT_SCOPE)
set(${_hashvar}
"GITDIR-NOTFOUND"
PARENT_SCOPE)
return()
endif()
# Check if the current source dir is a git submodule or a worktree.
# In both cases .git is a file instead of a directory.
#
if(NOT IS_DIRECTORY ${GIT_DIR})
# The following git command will return a non empty string that
# points to the super project working tree if the current
# source dir is inside a git submodule.
# Otherwise the command will return an empty string.
#
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse
--show-superproject-working-tree
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT "${out}" STREQUAL "")
# If out is empty, GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a submodule
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)$" "\\1" GIT_DIR_RELATIVE
${submodule})
string(STRIP ${GIT_DIR_RELATIVE} GIT_DIR_RELATIVE)
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE}
ABSOLUTE)
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
else()
# GIT_DIR/CMAKE_CURRENT_SOURCE_DIR is in a worktree
file(READ ${GIT_DIR} worktree_ref)
# The .git directory contains a path to the worktree information directory
# inside the parent git repo of the worktree.
#
string(REGEX REPLACE "gitdir: (.*)$" "\\1" git_worktree_dir
${worktree_ref})
string(STRIP ${git_worktree_dir} git_worktree_dir)
_git_find_closest_git_dir("${git_worktree_dir}" GIT_DIR)
set(HEAD_SOURCE_FILE "${git_worktree_dir}/HEAD")
endif()
else()
set(HEAD_SOURCE_FILE "${GIT_DIR}/HEAD")
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${HEAD_SOURCE_FILE}")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${HEAD_SOURCE_FILE}" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake" @ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar}
"${HEAD_REF}"
PARENT_SCOPE)
set(${_hashvar}
"${HEAD_HASH}"
PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var}
"HEAD-HASH-NOTFOUND"
PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --tags --always ${hash} ${ARGN}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_describe_working_tree _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" describe --dirty ${ARGN}
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var}
"${out}"
PARENT_SCOPE)
endfunction()
function(git_local_changes _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var}
"GIT-NOTFOUND"
PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var}
"HEAD-HASH-NOTFOUND"
PARENT_SCOPE)
return()
endif()
execute_process(
COMMAND "${GIT_EXECUTABLE}" diff-index --quiet HEAD --
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE res
OUTPUT_VARIABLE out
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
if(res EQUAL 0)
set(${_var}
"CLEAN"
PARENT_SCOPE)
else()
set(${_var}
"DIRTY"
PARENT_SCOPE)
endif()
endfunction()

View File

@ -0,0 +1,43 @@
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright 2009-2012, Iowa State University
# Copyright 2011-2015, Contributors
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
# SPDX-License-Identifier: BSL-1.0
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()

View File

@ -1,16 +1,30 @@
# Copyright (c) 2017-2022, 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
# Based on the Qt 5 processor detection code, so should be very accurate # Based on the Qt 5 processor detection code, so should be very accurate
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h # https://github.com/qt/qtbase/blob/dev/src/corelib/global/qprocessordetection.h
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64) # Currently handles arm (v5, v6, v7, v8), x86 (32/64), ia64, mips (32/64, mipsel, mips64el) and ppc (32/64)
# Regarding POWER/PowerPC, just as is noted in the Qt source, # Regarding POWER/PowerPC, just as is noted in the Qt source,
# "There are many more known variants/revisions that we do not handle/detect." # "There are many more known variants/revisions that we do not handle/detect."
set(archdetect_c_code " set(archdetect_c_code "
#if defined(__arm__) || defined(__TARGET_ARCH_ARM) #if defined(__arm__) || defined(__TARGET_ARCH_ARM)|| defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__)
#if defined(__ARM64_ARCH_8__) \\
|| defined(__aarch64__) \\
|| defined(__ARMv8__) \\
|| defined(__ARMv8_A__) \\
|| defined(_M_ARM64) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 8)
#error cmake_ARCH arm64
#if defined(__ARM_ARCH_7__) \\ #if defined(__ARM_ARCH_7__) \\
|| defined(__ARM_ARCH_7A__) \\ || defined(__ARM_ARCH_7A__) \\
|| defined(__ARM_ARCH_7R__) \\ || defined(__ARM_ARCH_7R__) \\
|| defined(__ARM_ARCH_7M__) \\ || defined(__ARM_ARCH_7M__) \\
|| defined(__ARM_ARCH_7S__) \\
|| defined(_ARM_ARCH_7) \\
|| defined(__CORE_CORTEXA__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7) || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
#error cmake_ARCH armv7 #error cmake_ARCH armv7
#elif defined(__ARM_ARCH_6__) \\ #elif defined(__ARM_ARCH_6__) \\
@ -23,6 +37,7 @@ set(archdetect_c_code "
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6) || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
#error cmake_ARCH armv6 #error cmake_ARCH armv6
#elif defined(__ARM_ARCH_5TEJ__) \\ #elif defined(__ARM_ARCH_5TEJ__) \\
|| defined(__ARM_ARCH_5TE__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5) || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
#error cmake_ARCH armv5 #error cmake_ARCH armv5
#else #else
@ -34,6 +49,18 @@ set(archdetect_c_code "
#error cmake_ARCH x86_64 #error cmake_ARCH x86_64
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
#error cmake_ARCH ia64 #error cmake_ARCH ia64
#elif defined(__mips) || defined(__mips__) || defined(_M_MRX000)
#if defined(_MIPS_ARCH_MIPS64) || defined(__mips64)
#if defined(__MIPSEL__)
#error cmake_ARCH mips64el
#else
#error cmake_ARCH mips64
#endif
#elif defined(__MIPSEL__)
#error cmake_ARCH mipsel
#else
#error cmake_ARCH mips
#endif
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\ #elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\ || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|| defined(_M_MPPC) || defined(_M_PPC) || defined(_M_MPPC) || defined(_M_PPC)
@ -47,7 +74,7 @@ set(archdetect_c_code "
#error cmake_ARCH unknown #error cmake_ARCH unknown
") ")
# Set ppc_support to TRUE before including this file or ppc and ppc64 # Set ppc_support to TRUE before including this file on ppc and ppc64
# will be treated as invalid architectures since they are no longer supported by Apple # will be treated as invalid architectures since they are no longer supported by Apple
function(target_architecture output_var) function(target_architecture output_var)
@ -67,12 +94,14 @@ function(target_architecture output_var)
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)
set(osx_arch_ppc TRUE) set(osx_arch_ppc TRUE)
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
set(osx_arch_ppc64 TRUE)
elseif("${osx_arch}" STREQUAL "i386") elseif("${osx_arch}" STREQUAL "i386")
set(osx_arch_i386 TRUE) set(osx_arch_i386 TRUE)
elseif("${osx_arch}" STREQUAL "x86_64") elseif("${osx_arch}" STREQUAL "x86_64")
set(osx_arch_x86_64 TRUE) set(osx_arch_x86_64 TRUE)
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support) elseif("${osx_arch}" STREQUAL "arm64")
set(osx_arch_ppc64 TRUE) set(osx_arch_arm64 TRUE)
else() else()
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}") message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
endif() endif()
@ -83,6 +112,10 @@ function(target_architecture output_var)
list(APPEND ARCH ppc) list(APPEND ARCH ppc)
endif() endif()
if(osx_arch_ppc64)
list(APPEND ARCH ppc64)
endif()
if(osx_arch_i386) if(osx_arch_i386)
list(APPEND ARCH i386) list(APPEND ARCH i386)
endif() endif()
@ -91,8 +124,8 @@ function(target_architecture output_var)
list(APPEND ARCH x86_64) list(APPEND ARCH x86_64)
endif() endif()
if(osx_arch_ppc64) if(osx_arch_arm64)
list(APPEND ARCH ppc64) list(APPEND ARCH arm64)
endif() endif()
else() else()
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}") file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")

View File

@ -1,8 +1,5 @@
#define I2Pd_AppName "i2pd" #define I2Pd_AppName "i2pd"
#define I2Pd_Publisher "PurpleI2P" #define I2Pd_Publisher "PurpleI2P"
; Get application version from compiled binary
; Disabled to use definition from command line
;#define I2Pd_ver GetFileVersionString(AddBackslash(SourcePath) + "..\i2pd_x64.exe")
[Setup] [Setup]
AppName={#I2Pd_AppName} AppName={#I2Pd_AppName}
@ -27,7 +24,7 @@ ExtraDiskSpaceRequired=15
AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2} AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2}
AppVerName={#I2Pd_AppName} AppVerName={#I2Pd_AppName}
AppCopyright=Copyright (c) 2013-2020, The PurpleI2P Project AppCopyright=Copyright (c) 2013-2022, The PurpleI2P Project
AppPublisherURL=http://i2pd.website/ AppPublisherURL=http://i2pd.website/
AppSupportURL=https://github.com/PurpleI2P/i2pd/issues AppSupportURL=https://github.com/PurpleI2P/i2pd/issues
AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases
@ -47,6 +44,7 @@ Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyif
Source: ..\contrib\tunnels.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist Source: ..\contrib\tunnels.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
Source: ..\contrib\certificates\*; DestDir: {userappdata}\i2pd\certificates; Flags: onlyifdoesntexist recursesubdirs createallsubdirs Source: ..\contrib\certificates\*; DestDir: {userappdata}\i2pd\certificates; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
Source: ..\contrib\tunnels.d\*; DestDir: {userappdata}\i2pd\tunnels.d; Flags: onlyifdoesntexist recursesubdirs createallsubdirs Source: ..\contrib\tunnels.d\*; DestDir: {userappdata}\i2pd\tunnels.d; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
Source: ..\contrib\webconsole\*; DestDir: {userappdata}\i2pd\webconsole; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
[Icons] [Icons]
Name: {group}\I2Pd; Filename: {app}\i2pd.exe Name: {group}\I2Pd; Filename: {app}\i2pd.exe

View File

@ -1,18 +0,0 @@
gen
tests
bin
libs
log*
obj
.gradle
.idea
.externalNativeBuild
ant.properties
local.properties
build.sh
android.iml
build
gradle
gradlew
gradlew.bat

View File

@ -1,74 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := i2pd
LOCAL_CPP_FEATURES := rtti exceptions
LOCAL_C_INCLUDES += $(IFADDRS_PATH) $(LIB_SRC_PATH) $(LIB_CLIENT_SRC_PATH) $(DAEMON_SRC_PATH)
LOCAL_STATIC_LIBRARIES := \
boost_system \
boost_date_time \
boost_filesystem \
boost_program_options \
crypto ssl \
miniupnpc
LOCAL_LDLIBS := -lz
LOCAL_SRC_FILES := $(IFADDRS_PATH)/ifaddrs.c \
$(wildcard $(LIB_SRC_PATH)/*.cpp)\
$(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp)\
$(DAEMON_SRC_PATH)/UnixDaemon.cpp \
$(DAEMON_SRC_PATH)/Daemon.cpp \
$(DAEMON_SRC_PATH)/UPnP.cpp \
$(DAEMON_SRC_PATH)/HTTPServer.cpp \
$(DAEMON_SRC_PATH)/I2PControl.cpp \
$(DAEMON_SRC_PATH)/i2pd.cpp
include $(BUILD_EXECUTABLE)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_system
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_system.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_date_time
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_filesystem
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := boost_program_options
LOCAL_SRC_FILES := $(BOOST_PATH)/boost-1_72_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a
LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost-1_72_0/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := crypto
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libcrypto.a
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ssl
LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/$(TARGET_ARCH_ABI)/lib/libssl.a
LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.1.1a-clang/include
LOCAL_STATIC_LIBRARIES := crypto
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := miniupnpc
LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a
LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include
include $(PREBUILT_STATIC_LIBRARY)

View File

@ -1,40 +0,0 @@
APP_ABI := all
#APP_ABI += x86
#APP_ABI += x86_64
#APP_ABI += armeabi-v7a
#APP_ABI += arm64-v8a
#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
APP_PLATFORM := android-14
NDK_TOOLCHAIN_VERSION := clang
APP_STL := c++_static
# Enable c++17 extensions in source code
APP_CPPFLAGS += -std=c++17 -fvisibility=default -fPIE
APP_CPPFLAGS += -DANDROID_BINARY -DANDROID -D__ANDROID__ -DUSE_UPNP
APP_LDFLAGS += -rdynamic -fPIE -pie
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
APP_CPPFLAGS += -DANDROID_ARM7A
endif
# Forcing debug optimization. Use `ndk-build NDK_DEBUG=1` instead.
#APP_OPTIM := debug
# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git -b boost-1_72_0
# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git
# git clone https://github.com/PurpleI2P/android-ifaddrs.git
# change to your own
I2PD_LIBS_PATH = /path/to/libraries
BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt
OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt
MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt
IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs
# don't change me
I2PD_SRC_PATH = $(PWD)/../..
LIB_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd
LIB_CLIENT_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd_client
DAEMON_SRC_PATH = $(I2PD_SRC_PATH)/daemon

View File

@ -1,2 +0,0 @@
archive
i2pd_*_android_binary.zip

View File

@ -1,48 +0,0 @@
#!/bin/bash
# Copyright (c) 2013-2020, 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
GITDESC=$(git describe --tags)
declare -A ABILIST=(
["armeabi-v7a"]="armv7l"
["arm64-v8a"]="aarch64"
["x86"]="x86"
["x86_64"]="x86_64"
)
# Remove old files and archives
if [ -d archive ]; then
rm -r archive
fi
if [ -f ../i2pd_*_android_binary.zip ]; then
rm i2pd_*_android_binary.zip
fi
# Prepare files for package
mkdir archive
for ABI in "${!ABILIST[@]}"; do
if [ -f ../android_binary_only/libs/${ABI}/i2pd ]; then
cp ../android_binary_only/libs/${ABI}/i2pd archive/i2pd-${ABILIST[$ABI]}
fi
done
cp i2pd archive/i2pd
cp -rH ../android/assets/certificates archive/
cp -rH ../android/assets/tunnels.conf.d archive/
cp -H ../android/assets/i2pd.conf archive/
cp -H ../android/assets/tunnels.conf archive/
# Compress files
cd archive
zip -r6 ../i2pd_${GITDESC}_android_binary.zip .
# Remove temporary folder
cd ..
rm -r archive

View File

@ -1,33 +0,0 @@
#!/bin/sh
# Copyright (c) 2013-2020, 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
#
# That script written for use with Termux.
# https://stackoverflow.com/a/246128
SOURCE="${0}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
arch=$(uname -m)
screenfind=$(which screen)
if [ -z $screenfind ]; then
echo "Can't find 'screen' installed. That script needs it!";
exit 1;
fi
if [ -z i2pd-$arch ]; then
echo "Can't find i2pd binary for your archtecture.";
exit 1;
fi
screen -AmdS i2pd ./i2pd-$arch --datadir=$DIR

View File

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICKDCCAc6gAwIBAgIUcPHZXtYSqGNRCD6z8gp79WUFtI0wCgYIKoZIzj0EAwIw
gZMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEPMA0GA1UEBwwGQXVzdGlu
MRgwFgYDVQQKDA9TdG9ybXlDbG91ZCBJbmMxIzAhBgNVBAMMGnN0b3JteWNsb3Vk
LmZhbWlseS5pMnAubmV0MSQwIgYJKoZIhvcNAQkBFhVhZG1pbkBzdG9ybXljbG91
ZC5vcmcwHhcNMjIwMzE5MTU1MjU2WhcNMzIwMzE2MTU1MjU2WjCBkzELMAkGA1UE
BhMCVVMxDjAMBgNVBAgMBVRleGFzMQ8wDQYDVQQHDAZBdXN0aW4xGDAWBgNVBAoM
D1N0b3JteUNsb3VkIEluYzEjMCEGA1UEAwwac3Rvcm15Y2xvdWQuZmFtaWx5Lmky
cC5uZXQxJDAiBgkqhkiG9w0BCQEWFWFkbWluQHN0b3JteWNsb3VkLm9yZzBZMBMG
ByqGSM49AgEGCCqGSM49AwEHA0IABFUli0hvJEmowNjJVjbKEIWBJhqe973S4VdL
cJuA5yY3dC4Y998abWEox7/Y1BhnBbpJuiodA341bXKkLMXQy/kwCgYIKoZIzj0E
AwIDSAAwRQIgD12F/TfY3iV1/WDF7BSKgbD5g2MfELUIy1dtUlJQuJUCIQD69mZw
V1Z9j2x0ZsuirS3i6AMfVyTDj0RFS3U1jeHzIQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFyzCCA7OgAwIBAgIRALWNWsnQ0Vmn/99iCNT7cdQwDQYJKoZIhvcNAQELBQAw
cTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGjAYBgNVBAMM
EWVjaGVsb24zQG1haWwuaTJwMB4XDTIxMTEyOTE5MzU1OVoXDTMxMTEyOTE5MzU1
OVowcTELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwG
A1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGjAYBgNV
BAMMEWVjaGVsb24zQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
CgKCAgEA3pccNiQWJUS1t3QHK7rBCNKAsM2dz4szN3+3SrDy1w+rOrK8Vt5aypPU
QYUQwG+odjEPacuoRtO/W14KJl5yAI3eQS+X/cYDXmxvfm4zx5JRumYptXwJD57G
rlPHnFvk8R+Hvh+/UyqgSAZ9ZaKjEzYK4AtbYEXtopaM4U2VYN8xKjvKyWlhPdxo
kI3//qcTlSqGHHeHrkItLG1LubM1EnPu+9zI2WN2zBBRcm8ZtWqHoqFJ1zgJr/49
nMK8Lnb3I54ctva8x5+gsSk4dbG/mMsOIZekFqYJJs3+u9w5fmOYI7v9GlQr7UhE
G3MwjJ5Cj1LmLVlz/4LApZrDSd2JvwIUdGL3UW8+blaTeCPKIRvmsTeRxo1gORMF
ZH0dg39722lK7ScwOlOUX9ggzRUlYCmvnjQJZGJEUoP68QxjlQfkXZyffmMfvm6K
V6mcZ5aHMGO1lYAl40kWNJ0jGpmxJqTDhNFDEKr0TlRGVxXGWzObEOrcJ8ysRMc1
x6oXQhh79HXZcKwhZaXLx23ZvVoTfhRm4JH0SSP6XqQm35j4NI1SllEsDns29wU3
Re4wOWJCCYlPG3CtY32CinwQRoVgtiJk18W8+Pxw7sBFq8sL5L0Z+5bB6nTkBfV6
7OrZGWL0i344zQE0e3yIsLih+5Wyqw6RSSMysenl3alnUB9EvE0CAwEAAaNeMFww
DgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAP
BgNVHRMBAf8EBTADAQH/MBoGA1UdDgQTBBFlY2hlbG9uM0BtYWlsLmkycDANBgkq
hkiG9w0BAQsFAAOCAgEAaUMnMYtNFBl9dFON6e4EjYo53Wknj61uIVO11dvLqjnh
7X6guPML+GgNZsPQGLu7Bqw4hVgy/cV5AlFc7SXOhzpaYo1ycpjg3Ws1VK2wrk7+
4bvUThNcS1KZVFDdRE62549rYNfYNfPxXvccOTW9meTCC1kLHerh65ySDr9J02O6
o5Mf685PgBasBH6dlosOLTtee2gRLNFcAluQYKerawS1gDys5239UNHPCqTgO+Od
FiKfl48OIOzPGLKEf4lXC+lkwZElewShrHhzd8aGueedTi0UHOtQuY7ocsofqXc8
OnyT/y2X6wn/YkzviKgfxYDSI7FJiUgXCPcT0jUNmuwR168yL5BfzoQmrCvlOOQg
P7ibdBJ6UkL8pRpv/SYpvaX/kf4agYtwh5IL9FzNCwNu54ZC6JilLUhYAU38Eolq
OZ/cGiMoSFQIeBPvB3cdsqEud9W4P+MqN5A76fMzdVV77lGsIS1eCGMceR3CjOiF
6SdAskcBZWhFiRNQweC0iv57/nPCeTCuNAqbZSHd7zC1AKhNmmsKSJUJQCGijcce
P8Gl0AFfZneN2bVEFvJ/zd71pD8ll1Gkju16bfdWn0V4NRaxFiXNr2bL+ah9blud
EXOomE3R6ow1QZk+Gnpy3wh9jfwlrJuFoANvHnv4WREbdjwr//71XjBri5p1wPE=
-----END CERTIFICATE-----

View File

@ -1,32 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFfzCCA2egAwIBAgIESg3kkzANBgkqhkiG9w0BAQ0FADBwMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQZWNoZWxvbkBtYWls
LmkycDAeFw0xNDA3MzExNjQ3MDJaFw0yNDA3MzAxNjQ3MDJaMHAxCzAJBgNVBAYT
AlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9u
eW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQDDBBlY2hlbG9uQG1h
aWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAmcEgLwwhzLNe
XLOMSrhwB8hWpOhfjo4s6S/wjBtjjUc8nI3D0hSn3HY26p0rvcvNEWexPUpPULmC
exGkU463nu7PiFONiORI1eJAiUFHibRiaA7Wboyo38pO73KirwjG07Y+Ua0jp+HS
+4FQ/I/9H/bPplReTOU/6hmRbgQ69U8nE68HzZHQxP68yVJ2rPHSXMPhF4R1h0G1
1mCAT+TgTsnwHNGF77XHJnY4/M4e2cgycEZjZow36C3t2mNDVkMgF19QQeb9WmLR
zREn3nq9BJqHpUkn9yWw0kKXTZSds+7UxESfzf3BzK0+hky2fh5H+qbYAo2lz4yj
81MXTAu+4RRkg4DBLlF+2dkclhwQLxxzvkRC6tPkn5i33Yltg7EfzA9IoQ05potJ
I+iOcF+aStfFgFj9u3B5UkcF4P0cH1QD3c6BK4hIezQYqRoPly1gHqg+XdwjG/dr
4as7HA9FTz3p2E8nClpIC1x3hfgwAdfd29aeBxO1WW/z99iMF7TBAF+u5T86XEW1
WpknqCbTli36yJ8a5fPWxZHrryBRJT5yLxejjFeadtutBSwljiVFq+Y38VqwFivq
VLiBt7IxAsZ8iilgfnnnAvBH6chWfSKb4H7kB4TJvDiV96QmmvoEaWYNHZozMhyK
tO3b5w+xqbJXyCLA3Q75jD0km76hjcECAwEAAaMhMB8wHQYDVR0OBBYEFAHQcAam
QRS/EUhuCSr9pB4Ux0rYMA0GCSqGSIb3DQEBDQUAA4ICAQBq1+1QLmgLAjrTg3tb
4XKgAVICQRoBDNUEobQg3pYeUX9eFNya2RxNljuvYpwT80ilGMPOXcjddmr5ngiK
dbGRcuuJk9MPEHtPaPT3+JJlvKQ3B3g2wva2Wz2OAyLZUGQs389K4nTbwh4QF0n2
aHFL8BHiD62hiKnCoNaW4ZovUNNvOxo9lMyAiaFU2gqQNcdad8hP9EAllbvbxDx9
Tjww2UbwQUIHS9rna4Tlu+f0hDXTWIutc2A51W2fJCb7L3+lYO7Wv55ND/WtryLZ
XpMp27+MpuEnN3kQmz/l9R0hIJsWc/x9GQkjm5wEaIZEyTtenqwRKGmVCtAj0Pgv
jn1L3/lWmrNq+OZHb/QeyfKtA3nXfQKVmT98ewQiK/S5i1xIAXCJPytOD887b/o1
cdurTmCiZMwgiQ+HLJqCg3MDa5mvKqRkRdZXfE6aQWEcSbpAhpV15R17q7L+Fg0W
shLSNucxyGNU8PjiC/nOmqfqUiPiMltJjPmscxBLim8foyxjakC4+6N6m+Jzgznj
PocBehFAfKYj66XEwzIBN7Z2uuXoYH9YptkocFjTzvchcryVulDWZ4FWxreUMhpM
4oyjjhSB4tB9clXlwMqg577q3D6Ms0zLTqsztyPN3zr6jGev3jpVq7Q1GOlciHPv
JNJOWTH/Vas1W6XlwGcOOAARTQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFgTCCA2mgAwIBAgIETWAY1DANBgkqhkiG9w0BAQ0FADBxMQswCQYDVQQGEwJY
WDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBAbWFp
bC5pMnAwHhcNMjExMjEzMTU0MDI3WhcNMzExMjExMTU0MDI3WjBxMQswCQYDVQQG
EwJYWDELMAkGA1UECAwCWFgxCzAJBgNVBAcMAlhYMR4wHAYDVQQKDBVJMlAgQW5v
bnltb3VzIE5ldHdvcmsxDDAKBgNVBAsMA0kyUDEaMBgGA1UEAwwRaGlkdXNlcjBA
bWFpbC5pMnAwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXnjJ8UQ0f
lHHpfPMiHofBPSuL4sbOJY6fOXwPhSg/h6THh9DS/ZWmJXQ3qRD0glDVtv4/Dr/9
ldGQ5eltF9iCFXCQlMEy2HjQrBKq0nsl7RpYK12cyMaod0kkzCUk9ITLi9CmHM3Z
gQZcmG8TWjFEpDR+idx/QkQt2pcO4vzWlDit3Vh4ivnbX5jGQHbsVjQEMQWxr+pX
dsS+YQpjZ6RBmrooGTPO8QDOOeYLAn0lCjmffc/kzIH9E/p4/O0rOpyhVYbdxUD1
5wkqN9l4yrtxmORG/PudnRQQ0r4TUq8vsxfGY0Euo9IbhgXF2Parel1ZhDxB1WZV
VwWtgLIh9jGA1UMa8SYKnEfp8LWNZ3b3mUUnZb3kMrLk6jGYRWNsHmamhd4mC7AZ
qf/8lOkEIw3bPd3YguCDRVcLui5BwIEZmqXg8uoESxfO/sW3pBrN/8M7MkTex9kN
vjitGDDXvenK27qmNgZxbBlX72yTSfys7XTYTLnxZC8AwdAo2Wz9Z6HhGiPonf2h
vZkc9ZxuE0jFIrsbJra4X7iyjXgi4vV4ARNg/9Ft6F4/OIbECgeDcBQqq4TlT2bZ
EfWVrBbqXoj5vNsLigIkd+AyUNwPYEcB5IFSiiOh98pC7BH3pg0m8U5YBjxe1i+9
EQOOG0Qtx+JigXZHu6bGE0Twy9zy+UzoKQIDAQABoyEwHzAdBgNVHQ4EFgQUGK1b
0DkL6aLalcfBc/Uj/SF08C0wDQYJKoZIhvcNAQENBQADggIBAMpXM82bJDpH1TlH
TvhU3Z7nfZdvEhOQfujaFUYiuNripuEKcFGn948+DvAG0FUN+uNlJoqOVs8D7InD
gWlA9zpqw5Cl5Hij/Wns9QbXuAHJeA23fVUoaM2A6v9ifcIQ1A+rDuRQAo6/64KW
ChTg2e99RBpfGOyqgeh7tLLe0lPPekVpKHFuXabokaKRDuBcVHcUL4tWXe3dcyqa
Ej/PJrrS+nWL0EGZ4q80CEd2LPuDzPxNGCJt/R7ZfadENWajcgcXGceh1QBzozrB
SL/Ya6wF9SrsB7V/r5wX0LM4ZdDaLWbtmUe5Op0h/ZMH25Sa8xAXVz+O9L6sWSoO
FaiYTOvAiyyPz+nsxKa3xYryDHno7eKSt+hGOcaurhxbdZaEFY/CegEc73tCt9xK
e9qF8O/WkDLmixuErw3f5en4IfzGR7p3lJAwW/8WD8C6HS39h/eE7dVZNaWgtQnZ
SgGjgZMTJqTcQ3aZmfuCZefxGFok8w6AIkdbnd1pdMBRjYu8aXgl2hQSB9ZADDE9
R5d3rXi0PkSFLIvsNjVa5KXrZk/tB0Hpfmepq7CufBqjP/LG9TieRoXzLYUKFF74
QRwjP+y7AJ+VDUTpY1NV1P+k+2raubU2bOnLF3zL5DtyoyieGPhyeMMvp0fRIxdg
bSl5VHgPXHNM8mcnndMAuzvl7jEK
-----END CERTIFICATE-----

View File

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIFzTCCA7WgAwIBAgIQeUqFi0fHNQopg6BZlBLhVzANBgkqhkiG9w0BAQsFADBy
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEbMBkGA1UEAwwS
aTJwLXJlc2VlZEBtazE2LmRlMB4XDTIyMDIwNTE3MzkzM1oXDTMyMDIwNTE3Mzkz
M1owcjELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwG
A1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxGzAZBgNV
BAMMEmkycC1yZXNlZWRAbWsxNi5kZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
AgoCggIBAMYxs2D2xpN/8blGawvAlU9DemHIxApOEwaLNfh8aAvqEdB41NTqcx4U
H8VchSormCfkCvezuMHO+K2HX7ihEZ1v6tbr6aX6hY9UZUyDDYsKmJoB1oKEhddv
5UYfcWPE2eSykdFsWgTQD6Z+cRQWHEoCzb7qc+Jrw6KcnHMD0VrmBrEQPzTBxMHW
4HC97PVkSLJTDArnS6ZiX4IbWRPw/mbpJT6EoVZo8J/it0pdn/X4KodEXDcnEMSe
VRulfZH/nSmOOvKhoHPckmgz/u66BlnuSYXEIB0KfDIcAlSYiPDxGnAemTozJYXA
UVMeFMs+YE5wiPgzzu+vpC31xtZLq0gyaCfgEi1P9j2ES/8pH3Gw6W2OH4kBx+jO
TBsfI+ph6qFZ3WWT23MRVyl3ATuI/GHdczTxD9JaOn74lLI+Hnu8wXnyztVWkTMB
4sAnzjdeHkvNDyQ10vSaN0HnGfg6zuAuUSqFQujFF8Vg8ZCcsh8GouWfzYDvi9mj
9pfxx8v6UCC719I4J9CgFjWnn2Hqez3fO8fFulY61VPyCCZp4gKWbI2SIQP/n5gz
ecYJRrJoem+rYfEQ/fwxROsvm3fCO4D6dt7ILRuX286GDIw2qSvP1zZVAioMwSj3
9CAjKLwD/BhTRiMOlpaVv6IWqjtevbiaIKvbHTnoxvkGsDqe3gJhAgMBAAGjXzBd
MA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw
DwYDVR0TAQH/BAUwAwEB/zAbBgNVHQ4EFAQSaTJwLXJlc2VlZEBtazE2LmRlMA0G
CSqGSIb3DQEBCwUAA4ICAQAb+x6XpJdjpVYw2bvWIUbatQJwq0YaEW5W61xGLgIG
a37oll3YZbSY9Vk+N1cE0f61L3ya4Ioz6zlH/MO2zUG/dEk8vqdgIPUYJvyF7wwF
w3/G4VMaDKOJx4bAZNmaiRFGYNhCOhCnZx6uZGrLNIJ2Dc+mflrGmGwYphtXVV3e
Iv+ki3gSRgfXuMfKi4B5bLPnz7XDe4TSmwZZSRac4ly4KqmZUyntqbilRxaGTej3
VYJ1tac8yppyk5N3VopMQNmBarNZG16wSOTD7CtKgn382jgRW8cR7BMeqhORivp0
ZnPJFhzh4uthdlPdXXo6lxfvZjfiwlDPytvEu2QBz3urTgopGqRLcTBnLucWg9li
OSy9z7hNEnIN3iIJJAwI1wBdDa7K0h3PFBbIUa7X2ybn81VeNSfO25Lo8YTZEKsc
wcThJrNV6qOQv8rM/7aXugi6+VzPlCR+18iKRbebCnlqGR2dT1zFtj3negtOkrjo
LH4H6VUr3q2Ie56IubS2hUKiUkDm0ckP3Vum35GGntyEAzl6uyog0hJFOJb3aq30
YQLzyVEOz8NnA+32oMRzJJdDxQ7pqG5fgq7EF4d++YSgEfdVXxvfgXQ6m3jAyC7Z
p/gX4rlxNsjeGU3Ds51wkmhH4IB1aSQr52PE6RaBhhh3SmADEv6S/3eGvE4F4MN5
2Q==
-----END CERTIFICATE-----

View File

@ -0,0 +1,33 @@
-----BEGIN CERTIFICATE-----
MIIFxzCCA6+gAwIBAgIQfKAV7rmoWA8jWpLfMtDQqzANBgkqhkiG9w0BAQsFADBw
MQswCQYDVQQGEwJYWDELMAkGA1UEBxMCWFgxCzAJBgNVBAkTAlhYMR4wHAYDVQQK
ExVJMlAgQW5vbnltb3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEZMBcGA1UEAwwQ
cmFtYmxlckBtYWlsLmkycDAeFw0yMTExMDYwNzEwMzJaFw0zMTExMDYwNzEwMzJa
MHAxCzAJBgNVBAYTAlhYMQswCQYDVQQHEwJYWDELMAkGA1UECRMCWFgxHjAcBgNV
BAoTFUkyUCBBbm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRkwFwYDVQQD
DBByYW1ibGVyQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKC
AgEAz4vQlIdjY56uqkFKWld9Oy3E8+06Ag9fUzBVleS2bdJfaFtmEa8xz6Pep7Bb
zJK0Q9t2CW7/xqIWuspWlYn5EYAS7BFiNOX70KX4PMpltj3C4Dpxpjll9LdydU2k
FquCflXNJESnBDdd0qDRMboMf4c9lTz0mTLwAtzInLwHGDrbxEiQ/YqPgPJreOXQ
anhjkpxJcgpLR+9od8EdLNKbShVWEeSBnYp0FcjnZKOb9KC2gjqP0sWdzlw3i1hh
CB38A7a03Q4yUcmxCw4ktM60d/2jCZ+G7KHwcbkfxDjl85r0UgEzgfF7LuIuxxmA
MNLH1eAACnLTl42O72EHdtD9VWWwZF2NuFgAzT3MEFnMKDk+OqZOeZQOEgkIfrNP
O5XYMYxHSWCf/dmSq36ZJwhC40k2S9ArS8BQNY8NvwZG5CSGDU52FKaHzFn6EwLE
4CpsrptUX2itXLaFUiNMw6I+eSgTO7x+gpahZVqpdRSQXmpE0xA5jP/DwPyt3ZVe
/4q4kn3imcSCxBP5NQHWfVszsruRkh9np4R0xVlT8UCwJmY8Yg8zwJG5UddTAck5
JavDsaXgWMwcZ/qQboZKlH/iAdQnbkte8Yd5GL5nmTeS+vwuluwmA/y9kUzSUhk+
86kA0eRJ1+e2HdA1/UOTRmyIoIeQ5/fhELMXzhksLcpMGTUCAwEAAaNdMFswDgYD
VR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAPBgNV
HRMBAf8EBTADAQH/MBkGA1UdDgQSBBByYW1ibGVyQG1haWwuaTJwMA0GCSqGSIb3
DQEBCwUAA4ICAQAxRdSTZGEblnNeVuRoEQq/a/6q4egFaOkzXCPKEnDzB5yvm83g
35ImquGFZkgaoc5qUAHVeBwOQrWgUI4xHPofnbM2VsgEUMz6h3ovobPNkN3+lRT5
30krd0y+A/Q895EHDu0lyf3BHMmtCWiKWQBttuc0dnmoLCRsQxgy+kYJCS/81jCM
4KNnyrtc6a/czqSq758CncjP2nErVucendsguQoA5JUw53YJ4FYHG/f9tYEkhm9C
D6u7L3vTUcMRUrRxSiJyNixH36nEwpM6DNHiPNc+CFKZ/Zx449R1GjcpDhTrXnWP
2H1r3cyKEM8a76VUEs2GQCaaglOR4N1goyqgYEjScf+/4VmARL3VUzfP8Oub70rM
t1fip5QD/4VDQuA/9C9g5Rr2nJ3K2jVnpSSKnBYFYf5z9RZdTOVXjXaEi72lWxpk
mjgK6c5EFOJxYoCaTbKX9Kz9ZIWVOVMrgHWwA/wDW+Qk5zgP9Ysau65xIp9P1RdB
qHgR5BcIrNky9RD8cIzxzMPCSMVgnf0eLFuHmG8uUl/xHHVRprf0pd7DYkQ44HWN
Z/g/gg3DaJdH7vvkShzgjt4iZrmOCHQIKkSGFRYZf0/Mpn6mgK9+grtO9osVgAQr
LBO+5LIxV/S5bcrzWQLOiMABTd2X/0PTOjuXpfinZ3rDSUiNFPq5kLLSlA==
-----END CERTIFICATE-----

View File

@ -81,7 +81,9 @@ ipv6 = false
## Bandwidth configuration ## Bandwidth configuration
## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec, ## L limit bandwidth to 32KBs/sec, O - to 256KBs/sec, P - to 2048KBs/sec,
## X - unlimited ## X - unlimited
## Default is X for floodfill, L for regular node ## Default is L (regular node) and X if floodfill mode enabled. If you want to
## share more bandwidth without floodfill mode, uncomment that line and adjust
## value to your possibilities
# bandwidth = L # bandwidth = L
## Max % of bandwidth limit for transit. 0-100. 100 by default ## Max % of bandwidth limit for transit. 0-100. 100 by default
# share = 100 # share = 100
@ -108,7 +110,8 @@ port = 7070
# user = i2pd # user = i2pd
# pass = changeme # pass = changeme
## Select webconsole language ## Select webconsole language
## Currently supported english (default), afrikaans, russian, turkmen, ukrainian and uzbek languages ## Currently supported english (default), afrikaans, armenian, french, german,
## russian, turkmen, ukrainian 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.39.0 Version: 2.42.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
@ -32,7 +32,7 @@ Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
C++ implementation of I2P. C++ implementation of I2P.
%prep %prep
%setup -q %setup -q -n i2pd-openssl
%build %build
@ -57,8 +57,14 @@ cd build
%endif %endif
%if 0%{?fedora} >= 35 %if 0%{?rhel} == 9
pushd redhat-linux-build pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
@ -71,10 +77,16 @@ pushd build
make %{?_smp_mflags} make %{?_smp_mflags}
%if 0%{?fedora} >= 33 %if 0%{?rhel} == 9
popd popd
%endif %endif
%if 0%{?fedora} >= 33
%if 0%{?fedora} < 37
popd
%endif
%endif
%if 0%{?mageia} > 7 %if 0%{?mageia} > 7
popd popd
%endif %endif
@ -82,8 +94,14 @@ popd
%install %install
pushd build pushd build
%if 0%{?fedora} >= 35 %if 0%{?rhel} == 9
pushd redhat-linux-build pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
@ -99,14 +117,14 @@ chrpath -d i2pd
%{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd %{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd %{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd %{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf %{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt %{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf %{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/i2pd %{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/i2pd.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/i2pd
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.service %{buildroot}%{_unitdir}/i2pd.service %{__install} -D -m 644 %{_builddir}/i2pd-openssl/contrib/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1 %{__install} -D -m 644 %{_builddir}/i2pd-openssl/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates %{__cp} -r %{_builddir}/i2pd-openssl/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d %{__cp} -r %{_builddir}/i2pd-openssl/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
@ -146,7 +164,20 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Mon Aug 24 2021 r4sas <r4sas@i2pmail.org> - 2.39.0-2 * Tue May 24 2022 r4sas <r4sas@i2pmail.org> - 2.42.1
- update to 2.42.1
* Sun May 22 2022 orignal <orignal@i2pmail.org> - 2.42.0
- update to 2.42.0
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
- update to 2.41.0
- fixed build on Fedora Copr over openssl trunk code
* Mon Nov 29 2021 orignal <i2porignal@yandex.ru> - 2.40.0
- update to 2.40.0
* Tue Aug 24 2021 r4sas <r4sas@i2pmail.org> - 2.39.0-2
- changed if statements to cover fedora 35 - changed if statements to cover fedora 35
* Mon Aug 23 2021 orignal <i2porignal@yandex.ru> - 2.39.0 * Mon Aug 23 2021 orignal <i2porignal@yandex.ru> - 2.39.0

View File

@ -1,6 +1,6 @@
Name: i2pd Name: i2pd
Version: 2.39.0 Version: 2.42.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
@ -54,8 +54,14 @@ cd build
%endif %endif
%endif %endif
%if 0%{?fedora} >= 35 %if 0%{?rhel} == 9
pushd redhat-linux-build pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
@ -68,10 +74,16 @@ pushd build
make %{?_smp_mflags} make %{?_smp_mflags}
%if 0%{?fedora} >= 33 %if 0%{?rhel} == 9
popd popd
%endif %endif
%if 0%{?fedora} >= 33
%if 0%{?fedora} < 37
popd
%endif
%endif
%if 0%{?mageia} > 7 %if 0%{?mageia} > 7
popd popd
%endif %endif
@ -79,8 +91,14 @@ popd
%install %install
pushd build pushd build
%if 0%{?fedora} >= 35 %if 0%{?rhel} == 9
pushd redhat-linux-build pushd redhat-linux-build
%endif
%if 0%{?fedora} >= 35
%if 0%{?fedora} < 37
pushd redhat-linux-build
%endif
%else %else
%if 0%{?fedora} >= 33 %if 0%{?fedora} >= 33
pushd %{_target_platform} pushd %{_target_platform}
@ -143,7 +161,19 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Mon Aug 24 2021 r4sas <r4sas@i2pmail.org> - 2.39.0-2 * Tue May 24 2022 r4sas <r4sas@i2pmail.org> - 2.42.1
- update to 2.42.1
* Sun May 22 2022 orignal <orignal@i2pmail.org> - 2.42.0
- update to 2.42.0
* Sun Feb 20 2022 r4sas <r4sas@i2pmail.org> - 2.41.0
- update to 2.41.0
* Mon Nov 29 2021 orignal <i2porignal@yandex.ru> - 2.40.0
- update to 2.40.0
* Tue Aug 24 2021 r4sas <r4sas@i2pmail.org> - 2.39.0-2
- changed if statements to cover fedora 35 - changed if statements to cover fedora 35
* Mon Aug 23 2021 orignal <i2porignal@yandex.ru> - 2.39.0 * Mon Aug 23 2021 orignal <i2porignal@yandex.ru> - 2.39.0

View File

@ -1,35 +1,65 @@
/*
* Copyright (c) 2021-2022, 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
*
******************************************************************
*
* This is style sheet for webconsole, with @media selectors for adaptive
* view on desktop and mobile devices, respecting preferred user's color
* scheme used in system/browser.
*
* Minified copy of that style sheet is bundled inside i2pd sources.
*/
:root {
--main-bg-color: #fafafa;
--main-text-color: #103456;
--main-link-color: #894c84;
--main-link-hover-color: #fafafa;
}
@media (prefers-color-scheme: dark) {
:root {
--main-bg-color: #242424;
--main-text-color: #17ab5c;
--main-link-color: #bf64b7;
--main-link-hover-color: #000000;
}
}
body { body {
font: 100%/1.5em sans-serif; font: 100%/1.5em sans-serif;
margin: 0; margin: 0;
padding: 1.5em; padding: 1.5em;
background: #FAFAFA; background: var(--main-bg-color);
color: #103456; color: var(--main-text-color);
} }
a, .slide label { a, .slide label {
text-decoration: none; text-decoration: none;
color: #894C84; color: var(--main-link-color);
} }
a:hover, .slide label:hover { a:hover, .slide label:hover, button[type=submit]:hover {
color: #FAFAFA; color: var(--main-link-hover-color);
background: #894C84; background: var(--main-link-color);
} }
a.button { a.button {
-webkit-appearance: button;
-moz-appearance: button;
appearance: button; appearance: button;
text-decoration: none; text-decoration: none;
padding: 0 5px; padding: 0 5px;
border: 1px solid #894C84; border: 1px solid var(--main-link-color);
} }
.header { .header {
font-size: 2.5em; font-size: 2.5em;
text-align: center; text-align: center;
margin: 1em 0; margin: 1em 0;
color: #894C84; color: var(--main-link-color);
} }
.wrapper { .wrapper {
@ -42,6 +72,7 @@ a.button {
display: block; display: block;
float: left; float: left;
overflow: hidden; overflow: hidden;
padding: 4px;
max-width: 12em; max-width: 12em;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -63,8 +94,9 @@ a.button {
.content { .content {
float: left; float: left;
font-size: 1em; font-size: 1em;
margin-left: 4em; margin-left: 2em;
max-width: 48em; padding: 4px;
max-width: 50em;
overflow: auto; overflow: auto;
} }
@ -87,7 +119,7 @@ a.button {
caption { caption {
font-size: 1.5em; font-size: 1.5em;
text-align: center; text-align: center;
color: #894C84; color: var(--main-link-color);
} }
table { table {
@ -105,6 +137,8 @@ table.services {
} }
textarea { textarea {
background-color: var(--main-bg-color);
color: var(--main-text-color);
word-break: break-all; word-break: break-all;
} }
@ -133,24 +167,45 @@ textarea {
color: #56B734; color: #56B734;
} }
button[type=submit] {
background-color: transparent;
color: var(--main-link-color);
text-decoration: none;
padding: 5px;
border: 1px solid var(--main-link-color);
font-size: 14px;
}
input, select, select option {
background-color: var(--main-bg-color);
color: var(--main-link-color);
padding: 5px;
border: 1px solid var(--main-link-color);
font-size: 14px;
}
input:focus, select:focus, select option:focus {
outline: none;
}
input[type=number]::-webkit-inner-spin-button {
-webkit-appearance: none;
}
@media screen and (max-width: 1150px) { /* adaptive style */ @media screen and (max-width: 1150px) { /* adaptive style */
.wrapper { .wrapper {
max-width: 58em; max-width: 58em;
} }
.menu {
max-width: 10em;
}
.content { .content {
margin-left: 2em; max-width: 40em;
max-width: 42em;
} }
} }
@media screen and (max-width: 980px) { @media screen and (max-width: 980px) {
body { body {
padding: 1.5em 0 0 0; font: 100%/1.2em sans-serif;
padding: 1.2em 0 0 0;
} }
.menu { .menu {
@ -178,9 +233,7 @@ textarea {
} }
a, .slide label { a, .slide label {
/* margin-right: 10px; */
display: block; display: block;
/* font-size: 18px; */
} }
.header { .header {
@ -193,13 +246,12 @@ textarea {
} }
a.button { a.button {
-webkit-appearance: button;
-moz-appearance: button;
appearance: button; appearance: button;
text-decoration: none; text-decoration: none;
margin-top: 10px; margin-top: 10px;
padding: 6px; padding: 6px;
border: 1px solid #894c84; border: 2px solid var(--main-link-color);
border-radius: 5px;
width: -webkit-fill-available; width: -webkit-fill-available;
} }
@ -207,8 +259,7 @@ textarea {
width: 35%; width: 35%;
text-align: center; text-align: center;
padding: 5px; padding: 5px;
border: 2px solid #ccc; border: 2px solid var(--main-link-color);
-webkit-border-radius: 5px;
border-radius: 5px; border-radius: 5px;
font-size: 18px; font-size: 18px;
} }
@ -221,17 +272,16 @@ textarea {
textarea { textarea {
width: -webkit-fill-available; width: -webkit-fill-available;
height: auto; height: auto;
padding:5px; padding: 5px;
border:2px solid #ccc; border: 2px solid var(--main-link-color);
-webkit-border-radius: 5px;
border-radius: 5px; border-radius: 5px;
font-size: 12px; font-size: 12px;
} }
button[type=submit] { button[type=submit] {
padding: 5px 15px; padding: 5px 15px;
background: #ccc; background: transparent;
border: 0 none; border: 2px solid var(--main-link-color);
cursor: pointer; cursor: pointer;
-webkit-border-radius: 5px; -webkit-border-radius: 5px;
border-radius: 5px; border-radius: 5px;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, 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
* *
@ -58,12 +58,16 @@ namespace util
bool Daemon_Singleton::IsService () const bool Daemon_Singleton::IsService () const
{ {
bool service = false; bool service = false;
#ifndef _WIN32
i2p::config::GetOption("service", service); i2p::config::GetOption("service", service);
#endif
return service; return service;
} }
void Daemon_Singleton::setDataDir(std::string path)
{
if (path != "")
DaemonDataDir = path;
}
bool Daemon_Singleton::init(int argc, char* argv[]) { bool Daemon_Singleton::init(int argc, char* argv[]) {
return init(argc, argv, nullptr); return init(argc, argv, nullptr);
} }
@ -73,8 +77,14 @@ namespace util
i2p::config::Init(); i2p::config::Init();
i2p::config::ParseCmdline(argc, argv); i2p::config::ParseCmdline(argc, argv);
std::string config; i2p::config::GetOption("conf", config); std::string config; i2p::config::GetOption("conf", config);
std::string datadir; i2p::config::GetOption("datadir", datadir); std::string datadir;
if(DaemonDataDir != "") {
datadir = DaemonDataDir;
} else {
i2p::config::GetOption("datadir", datadir);
}
i2p::fs::DetectDataDir(datadir, IsService()); i2p::fs::DetectDataDir(datadir, IsService());
i2p::fs::Init(); i2p::fs::Init();
@ -99,9 +109,9 @@ namespace util
certsdir = i2p::fs::GetCertsDir(); certsdir = i2p::fs::GetCertsDir();
std::string logs = ""; i2p::config::GetOption("log", logs); std::string logs = ""; i2p::config::GetOption("log", logs);
std::string logfile = ""; i2p::config::GetOption("logfile", logfile); std::string logfile = ""; i2p::config::GetOption("logfile", logfile);
std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel); std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);
bool logclftime; i2p::config::GetOption("logclftime", logclftime); bool logclftime; i2p::config::GetOption("logclftime", logclftime);
/* setup logging */ /* setup logging */
@ -118,26 +128,26 @@ namespace util
i2p::log::Logger().SetLogLevel(loglevel); i2p::log::Logger().SetLogLevel(loglevel);
if (logstream) { if (logstream) {
LogPrint(eLogInfo, "Log: will send messages to std::ostream"); LogPrint(eLogInfo, "Log: Sending messages to std::ostream");
i2p::log::Logger().SendTo (logstream); i2p::log::Logger().SendTo (logstream);
} else if (logs == "file") { } else if (logs == "file") {
if (logfile == "") if (logfile == "")
logfile = i2p::fs::DataDirPath("i2pd.log"); logfile = i2p::fs::DataDirPath("i2pd.log");
LogPrint(eLogInfo, "Log: will send messages to ", logfile); LogPrint(eLogInfo, "Log: Sending messages to ", logfile);
i2p::log::Logger().SendTo (logfile); i2p::log::Logger().SendTo (logfile);
#ifndef _WIN32 #ifndef _WIN32
} else if (logs == "syslog") { } else if (logs == "syslog") {
LogPrint(eLogInfo, "Log: will send messages to syslog"); LogPrint(eLogInfo, "Log: Sending messages to syslog");
i2p::log::Logger().SendTo("i2pd", LOG_DAEMON); i2p::log::Logger().SendTo("i2pd", LOG_DAEMON);
#endif #endif
} else { } else {
// use stdout -- default // use stdout -- default
} }
LogPrint(eLogNone, "i2pd v", VERSION, " starting"); LogPrint(eLogNone, "i2pd v", VERSION, " (", I2P_VERSION, ") starting...");
LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: Main config file: ", config);
LogPrint(eLogDebug, "FS: data directory: ", datadir); LogPrint(eLogDebug, "FS: Data directory: ", datadir);
LogPrint(eLogDebug, "FS: certificates directory: ", certsdir); LogPrint(eLogDebug, "FS: Certificates directory: ", certsdir);
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
@ -151,11 +161,7 @@ namespace util
bool ipv6; i2p::config::GetOption("ipv6", ipv6); bool ipv6; i2p::config::GetOption("ipv6", ipv6);
bool ipv4; i2p::config::GetOption("ipv4", ipv4); bool ipv4; i2p::config::GetOption("ipv4", ipv4);
#ifdef MESHNET
// manual override for meshnet
ipv4 = false;
ipv6 = true;
#endif
// ifname -> address // ifname -> address
std::string ifname; i2p::config::GetOption("ifname", ifname); std::string ifname; i2p::config::GetOption("ifname", ifname);
if (ipv4 && i2p::config::IsDefault ("address4")) if (ipv4 && i2p::config::IsDefault ("address4"))
@ -204,7 +210,7 @@ namespace util
uint16_t port; i2p::config::GetOption("port", port); uint16_t port; i2p::config::GetOption("port", port);
if (!i2p::config::IsDefault("port")) if (!i2p::config::IsDefault("port"))
{ {
LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port); LogPrint(eLogInfo, "Daemon: Accepting incoming connections at port ", port);
i2p::context.UpdatePort (port); i2p::context.UpdatePort (port);
} }
i2p::context.SetSupportsV6 (ipv6); i2p::context.SetSupportsV6 (ipv6);
@ -244,6 +250,18 @@ namespace util
if (!ipv4 && !ipv6) if (!ipv4 && !ipv6)
i2p::context.SetStatus (eRouterStatusMesh); i2p::context.SetStatus (eRouterStatusMesh);
} }
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
if (ssu2)
{
bool published; i2p::config::GetOption("ssu2.published", published);
if (published)
{
uint16_t ssu2port; i2p::config::GetOption("ssu2.port", ssu2port);
i2p::context.PublishSSU2Address (ssu2port, true, ipv4, ipv6); // publish
}
else
i2p::context.PublishSSU2Address (0, false, ipv4, ipv6); // unpublish
}
bool transit; i2p::config::GetOption("notransit", transit); bool transit; i2p::config::GetOption("notransit", transit);
i2p::context.SetAcceptsTunnels (!transit); i2p::context.SetAcceptsTunnels (!transit);
@ -252,7 +270,7 @@ namespace util
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
if (isFloodfill) { if (isFloodfill) {
LogPrint(eLogInfo, "Daemon: router will be floodfill"); LogPrint(eLogInfo, "Daemon: Router configured as floodfill");
i2p::context.SetFloodfill (true); i2p::context.SetFloodfill (true);
} }
else else
@ -267,7 +285,7 @@ namespace util
if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X') if (bandwidth[0] >= 'K' && bandwidth[0] <= 'X')
{ {
i2p::context.SetBandwidth (bandwidth[0]); i2p::context.SetBandwidth (bandwidth[0]);
LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps"); LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), "KBps");
} }
else else
{ {
@ -275,18 +293,18 @@ namespace util
if (value > 0) if (value > 0)
{ {
i2p::context.SetBandwidth (value); i2p::context.SetBandwidth (value);
LogPrint(eLogInfo, "Daemon: bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps"); LogPrint(eLogInfo, "Daemon: Bandwidth set to ", i2p::context.GetBandwidthLimit (), " KBps");
} }
else else
{ {
LogPrint(eLogInfo, "Daemon: unexpected bandwidth ", bandwidth, ". Set to 'low'"); LogPrint(eLogInfo, "Daemon: Unexpected bandwidth ", bandwidth, ". Set to 'low'");
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2); i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_LOW_BANDWIDTH2);
} }
} }
} }
else if (isFloodfill) else if (isFloodfill)
{ {
LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'"); LogPrint(eLogInfo, "Daemon: Floodfill bandwidth set to 'extra'");
i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2); i2p::context.SetBandwidth (i2p::data::CAPS_FLAG_EXTRA_BANDWIDTH2);
} }
else else
@ -301,12 +319,12 @@ namespace util
std::string family; i2p::config::GetOption("family", family); std::string family; i2p::config::GetOption("family", family);
i2p::context.SetFamily (family); i2p::context.SetFamily (family);
if (family.length () > 0) if (family.length () > 0)
LogPrint(eLogInfo, "Daemon: family set to ", family); LogPrint(eLogInfo, "Daemon: Router family set to ", family);
bool trust; i2p::config::GetOption("trust.enabled", trust); bool trust; i2p::config::GetOption("trust.enabled", trust);
if (trust) if (trust)
{ {
LogPrint(eLogInfo, "Daemon: explicit trust enabled"); LogPrint(eLogInfo, "Daemon: Explicit trust enabled");
std::string fam; i2p::config::GetOption("trust.family", fam); std::string fam; i2p::config::GetOption("trust.family", fam);
std::string routers; i2p::config::GetOption("trust.routers", routers); std::string routers; i2p::config::GetOption("trust.routers", routers);
bool restricted = false; bool restricted = false;
@ -336,18 +354,18 @@ namespace util
pos = comma + 1; pos = comma + 1;
} }
while (comma != std::string::npos); while (comma != std::string::npos);
LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routers"); LogPrint(eLogInfo, "Daemon: Setting restricted routes to use ", idents.size(), " trusted routers");
i2p::transport::transports.RestrictRoutesToRouters(idents); i2p::transport::transports.RestrictRoutesToRouters(idents);
restricted = idents.size() > 0; restricted = idents.size() > 0;
} }
if(!restricted) if(!restricted)
LogPrint(eLogError, "Daemon: no trusted routers of families specified"); LogPrint(eLogError, "Daemon: No trusted routers of families specified");
} }
bool hidden; i2p::config::GetOption("trust.hidden", hidden); bool hidden; i2p::config::GetOption("trust.hidden", hidden);
if (hidden) if (hidden)
{ {
LogPrint(eLogInfo, "Daemon: using hidden mode"); LogPrint(eLogInfo, "Daemon: Hidden mode enabled");
i2p::data::netdb.SetHidden(true); i2p::data::netdb.SetHidden(true);
} }
@ -360,7 +378,7 @@ namespace util
bool Daemon_Singleton::start() bool Daemon_Singleton::start()
{ {
i2p::log::Logger().Start(); i2p::log::Logger().Start();
LogPrint(eLogInfo, "Daemon: starting NetDB"); LogPrint(eLogInfo, "Daemon: Starting NetDB");
i2p::data::netdb.Start(); i2p::data::netdb.Start();
bool upnp; i2p::config::GetOption("upnp.enabled", upnp); bool upnp; i2p::config::GetOption("upnp.enabled", upnp);
@ -377,19 +395,20 @@ namespace util
} }
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ssu2; i2p::config::GetOption("ssu2.enabled", ssu2);
bool ssu; i2p::config::GetOption("ssu", ssu); bool ssu; i2p::config::GetOption("ssu", ssu);
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved); bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
LogPrint(eLogInfo, "Daemon: starting Transports"); LogPrint(eLogInfo, "Daemon: Starting Transports");
if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled"); if(!ssu) LogPrint(eLogInfo, "Daemon: SSU disabled");
if(!ntcp2) LogPrint(eLogInfo, "Daemon: ntcp2 disabled"); if(!ntcp2) LogPrint(eLogInfo, "Daemon: NTCP2 disabled");
i2p::transport::transports.SetCheckReserved(checkInReserved); i2p::transport::transports.SetCheckReserved(checkInReserved);
i2p::transport::transports.Start(ntcp2, ssu); i2p::transport::transports.Start(ntcp2, ssu, ssu2);
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2()) if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
LogPrint(eLogInfo, "Daemon: Transports started"); LogPrint(eLogInfo, "Daemon: Transports started");
else else
{ {
LogPrint(eLogError, "Daemon: failed to start Transports"); LogPrint(eLogError, "Daemon: Failed to start Transports");
/** shut down netdb right away */ /** shut down netdb right away */
i2p::transport::transports.Stop(); i2p::transport::transports.Stop();
i2p::data::netdb.Stop(); i2p::data::netdb.Stop();
@ -400,7 +419,7 @@ namespace util
if (http) { if (http) {
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
LogPrint(eLogInfo, "Daemon: starting webconsole at ", httpAddr, ":", httpPort); LogPrint(eLogInfo, "Daemon: Starting Webconsole at ", httpAddr, ":", httpPort);
try try
{ {
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort)); d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
@ -408,16 +427,16 @@ namespace util
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Daemon: failed to start webconsole: ", ex.what ()); LogPrint (eLogError, "Daemon: Failed to start Webconsole: ", ex.what ());
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ()); ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
} }
} }
LogPrint(eLogInfo, "Daemon: starting Tunnels"); LogPrint(eLogInfo, "Daemon: Starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
LogPrint(eLogInfo, "Daemon: starting Client"); LogPrint(eLogInfo, "Daemon: Starting Client");
i2p::client::context.Start (); i2p::client::context.Start ();
// I2P Control Protocol // I2P Control Protocol
@ -425,7 +444,7 @@ namespace util
if (i2pcontrol) { if (i2pcontrol) {
std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr); std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort); uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort);
LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort); LogPrint(eLogInfo, "Daemon: Starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
try try
{ {
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort)); d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
@ -433,7 +452,7 @@ namespace util
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Daemon: failed to start I2PControl: ", ex.what ()); LogPrint (eLogError, "Daemon: Failed to start I2PControl: ", ex.what ());
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ()); ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
} }
} }
@ -442,10 +461,10 @@ namespace util
bool Daemon_Singleton::stop() bool Daemon_Singleton::stop()
{ {
LogPrint(eLogInfo, "Daemon: shutting down"); LogPrint(eLogInfo, "Daemon: Shutting down");
LogPrint(eLogInfo, "Daemon: stopping Client"); LogPrint(eLogInfo, "Daemon: Stopping Client");
i2p::client::context.Stop(); i2p::client::context.Stop();
LogPrint(eLogInfo, "Daemon: stopping Tunnels"); LogPrint(eLogInfo, "Daemon: Stopping Tunnels");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();
if (d.UPnP) if (d.UPnP)
@ -460,18 +479,18 @@ namespace util
d.m_NTPSync = nullptr; d.m_NTPSync = nullptr;
} }
LogPrint(eLogInfo, "Daemon: stopping Transports"); LogPrint(eLogInfo, "Daemon: Stopping Transports");
i2p::transport::transports.Stop(); i2p::transport::transports.Stop();
LogPrint(eLogInfo, "Daemon: stopping NetDB"); LogPrint(eLogInfo, "Daemon: Stopping NetDB");
i2p::data::netdb.Stop(); i2p::data::netdb.Stop();
if (d.httpServer) { if (d.httpServer) {
LogPrint(eLogInfo, "Daemon: stopping HTTP Server"); LogPrint(eLogInfo, "Daemon: Stopping HTTP Server");
d.httpServer->Stop(); d.httpServer->Stop();
d.httpServer = nullptr; d.httpServer = nullptr;
} }
if (d.m_I2PControlService) if (d.m_I2PControlService)
{ {
LogPrint(eLogInfo, "Daemon: stopping I2PControl"); LogPrint(eLogInfo, "Daemon: Stopping I2PControl");
d.m_I2PControlService->Stop (); d.m_I2PControlService->Stop ();
d.m_I2PControlService = nullptr; d.m_I2PControlService = nullptr;
} }

View File

@ -20,27 +20,33 @@ namespace util
class Daemon_Singleton_Private; class Daemon_Singleton_Private;
class Daemon_Singleton class Daemon_Singleton
{ {
public: public:
virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream); virtual bool init (int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
virtual bool init(int argc, char* argv[]); virtual bool init (int argc, char* argv[]);
virtual bool start(); virtual bool start ();
virtual bool stop(); virtual bool stop ();
virtual void run () {}; virtual void run () {};
bool isDaemon; virtual void setDataDir (std::string path);
bool running;
protected: bool isDaemon;
bool running;
Daemon_Singleton(); protected:
virtual ~Daemon_Singleton();
bool IsService () const; Daemon_Singleton ();
virtual ~Daemon_Singleton ();
// d-pointer for httpServer, httpProxy, etc. bool IsService () const;
class Daemon_Singleton_Private;
Daemon_Singleton_Private &d; // d-pointer for httpServer, httpProxy, etc.
class Daemon_Singleton_Private;
Daemon_Singleton_Private &d;
private:
std::string DaemonDataDir;
}; };
#if defined(QT_GUI_LIB) // check if QT #if defined(QT_GUI_LIB) // check if QT

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, 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,7 @@ namespace http {
if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug") if (level == "none" || level == "error" || level == "warn" || level == "info" || level == "debug")
i2p::log::Logger().SetLogLevel(level); i2p::log::Logger().SetLogLevel(level);
else { else {
LogPrint(eLogError, "HTTPServer: unknown loglevel set attempted"); LogPrint(eLogError, "HTTPServer: Unknown loglevel set attempted");
return; return;
} }
i2p::log::Logger().Reopen (); i2p::log::Logger().Reopen ();
@ -182,7 +182,7 @@ namespace http {
" <meta charset=\"UTF-8\">\r\n" " <meta charset=\"UTF-8\">\r\n"
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n" " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n"
" <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n" " <link rel=\"shortcut icon\" href=\"" << itoopieFavicon << "\">\r\n"
" <title>Purple I2P " VERSION " Webconsole</title>\r\n"; " <title>Purple I2P Webconsole</title>\r\n";
GetStyles(s); GetStyles(s);
s << s <<
"</head>\r\n" "</head>\r\n"
@ -196,8 +196,10 @@ namespace http {
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">" << tr("LeaseSets") << "</a><br>\r\n"; s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">" << tr("LeaseSets") << "</a><br>\r\n";
s << s <<
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">" << tr("Tunnels") << "</a><br>\r\n";
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit Tunnels") << "</a><br>\r\n" if (i2p::context.AcceptsTunnels () || i2p::tunnel::tunnels.CountTransitTunnels())
s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">" << tr("Transit Tunnels") << "</a><br>\r\n";
s <<
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">" << tr ("Transports") << "</a><br>\r\n"
" <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n"; " <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">" << tr("I2P tunnels") << "</a><br>\r\n";
if (i2p::client::context.GetSAMBridge ()) if (i2p::client::context.GetSAMBridge ())
@ -295,10 +297,10 @@ namespace http {
s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n"; s << " (" << (double) i2p::transport::transports.GetTransitBandwidth () / 1024 << " " << tr(/* tr: Kibibit/s */ "KiB/s") << ")<br>\r\n";
s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n"; s << "<b>" << tr("Data path") << ":</b> " << i2p::fs::GetUTF8DataDir() << "<br>\r\n";
s << "<div class='slide'>"; s << "<div class='slide'>";
if((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) { if ((outputFormat == OutputFormatEnum::forWebConsole) || !includeHiddenContent) {
s << "<label for=\"slide-info\">" << tr("Hidden content. Press on text to see.") << "</label>\r\n<input type=\"checkbox\" id=\"slide-info\" />\r\n<div class=\"slidecontent\">\r\n"; s << "<label for=\"slide-info\">" << tr("Hidden content. Press on text to see.") << "</label>\r\n<input type=\"checkbox\" id=\"slide-info\" />\r\n<div class=\"slidecontent\">\r\n";
} }
if(includeHiddenContent) { if (includeHiddenContent) {
s << "<b>" << tr("Router Ident") << ":</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n"; s << "<b>" << tr("Router Ident") << ":</b> " << i2p::context.GetRouterInfo().GetIdentHashBase64() << "<br>\r\n";
if (!i2p::context.GetRouterInfo().GetProperty("family").empty()) if (!i2p::context.GetRouterInfo().GetProperty("family").empty())
s << "<b>" << tr("Router Family") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n"; s << "<b>" << tr("Router Family") << ":</b> " << i2p::context.GetRouterInfo().GetProperty("family") << "<br>\r\n";
@ -307,41 +309,42 @@ namespace http {
s << "<b>"<< tr("Our external address") << ":</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n"; s << "<b>"<< tr("Our external address") << ":</b>" << "<br>\r\n<table class=\"extaddr\"><tbody>\r\n";
for (const auto& address : i2p::context.GetRouterInfo().GetAddresses()) for (const auto& address : i2p::context.GetRouterInfo().GetAddresses())
{ {
s << "<tr>\r\n"; s << "<tr>\r\n<td>";
if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ())
{
s << "<td>NTCP2";
if (address->host.is_v6 ()) s << "v6";
s << "</td><td>" << tr("supported") << "</td>\r\n</tr>\r\n";
continue;
}
switch (address->transportStyle) switch (address->transportStyle)
{ {
case i2p::data::RouterInfo::eTransportNTCP: case i2p::data::RouterInfo::eTransportNTCP:
{ s << "NTCP2";
s << "<td>NTCP"; break;
if (address->IsPublishedNTCP2 ()) s << "2";
if (address->host.is_v6 ()) s << "v6";
s << "</td>\r\n";
break;
}
case i2p::data::RouterInfo::eTransportSSU: case i2p::data::RouterInfo::eTransportSSU:
{ s << "SSU";
s << "<td>SSU"; break;
if (address->host.is_v6 ()) case i2p::data::RouterInfo::eTransportSSU2:
s << "v6"; s << "SSU2";
s << "</td>\r\n"; break;
break;
}
default: default:
s << "<td>" << tr("Unknown") << "</td>\r\n"; s << tr("Unknown");
} }
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n</tr>\r\n"; if (address->IsV6 ())
{
if (address->IsV4 ()) s << "v4";
s << "v6";
}
s << "</td>\r\n";
if (address->published)
s << "<td>" << address->host.to_string() << ":" << address->port << "</td>\r\n";
else
{
s << "<td>" << tr("supported");
if (address->port)
s << " :" << address->port;
s << "</td>\r\n";
}
s << "</tr>\r\n";
} }
s << "</tbody></table>\r\n"; s << "</tbody></table>\r\n";
} }
s << "</div>\r\n</div>\r\n"; s << "</div>\r\n</div>\r\n";
if(outputFormat == OutputFormatEnum::forQtUi) { if (outputFormat == OutputFormatEnum::forQtUi) {
s << "<br>"; s << "<br>";
} }
s << "<b>" << tr("Routers") << ":</b> " << i2p::data::netdb.GetNumRouters () << " "; s << "<b>" << tr("Routers") << ":</b> " << i2p::data::netdb.GetNumRouters () << " ";
@ -355,7 +358,7 @@ namespace http {
s << "<b>" << tr("Client Tunnels") << ":</b> " << std::to_string(clientTunnelCount) << " "; s << "<b>" << tr("Client Tunnels") << ":</b> " << std::to_string(clientTunnelCount) << " ";
s << "<b>" << tr("Transit Tunnels") << ":</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n"; s << "<b>" << tr("Transit Tunnels") << ":</b> " << std::to_string(transitTunnelCount) << "<br>\r\n<br>\r\n";
if(outputFormat==OutputFormatEnum::forWebConsole) { if (outputFormat==OutputFormatEnum::forWebConsole) {
bool httpproxy = i2p::client::context.GetHttpProxy () ? true : false; bool httpproxy = i2p::client::context.GetHttpProxy () ? true : false;
bool socksproxy = i2p::client::context.GetSocksProxy () ? true : false; bool socksproxy = i2p::client::context.GetSocksProxy () ? true : false;
bool bob = i2p::client::context.GetBOBCommandChannel () ? true : false; bool bob = i2p::client::context.GetBOBCommandChannel () ? true : false;
@ -416,7 +419,7 @@ namespace http {
s << "</div>\r\n</div>\r\n"; s << "</div>\r\n</div>\r\n";
} }
if(dest->IsPublic()) if (dest->IsPublic() && token && !dest->IsEncryptedLeaseSet ())
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot); std::string webroot; i2p::config::GetOption("http.webroot", webroot);
auto base32 = dest->GetIdentHash ().ToBase32 (); auto base32 = dest->GetIdentHash ().ToBase32 ();
@ -430,7 +433,7 @@ namespace http {
"</form>\r\n<small>" << tr("<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "</small>\r\n</div>\r\n</div>\r\n<br>\r\n"; "</form>\r\n<small>" << tr("<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.") << "</small>\r\n</div>\r\n</div>\r\n<br>\r\n";
} }
if(dest->GetNumRemoteLeaseSets()) if (dest->GetNumRemoteLeaseSets())
{ {
s << "<div class='slide'><label for='slide-lease'><b>" << tr("LeaseSets") << ":</b> <i>" << dest->GetNumRemoteLeaseSets () s << "<div class='slide'><label for='slide-lease'><b>" << tr("LeaseSets") << ":</b> <i>" << dest->GetNumRemoteLeaseSets ()
<< "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n<table><thead><th>"<< tr("Address") << "</th><th>" << tr("Type") << "</th><th>" << tr("EncType") << "</th></thead><tbody class=\"tableitem\">"; << "</i></label>\r\n<input type=\"checkbox\" id=\"slide-lease\" />\r\n<div class=\"slidecontent\">\r\n<table><thead><th>"<< tr("Address") << "</th><th>" << tr("Type") << "</th><th>" << tr("EncType") << "</th></thead><tbody class=\"tableitem\">";
@ -446,8 +449,18 @@ namespace http {
s << "<b>" << tr("Inbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n"; s << "<b>" << tr("Inbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
for (auto & it : pool->GetInboundTunnels ()) { for (auto & it : pool->GetInboundTunnels ()) {
s << "<div class=\"listitem\">"; s << "<div class=\"listitem\">";
it->Print(s); // for each tunnel hop if not zero-hop
if(it->LatencyIsKnown()) if (it->GetNumHops ())
{
it->VisitTunnelHops(
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
{
s << "&#8658; " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
}
);
}
s << "&#8658; " << it->GetTunnelID () << ":me";
if (it->LatencyIsKnown())
s << " ( " << it->GetMeanLatency() << tr(/* tr: Milliseconds */ "ms") << " )"; s << " ( " << it->GetMeanLatency() << tr(/* tr: Milliseconds */ "ms") << " )";
ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ()); ShowTunnelDetails(s, it->GetState (), false, it->GetNumReceivedBytes ());
s << "</div>\r\n"; s << "</div>\r\n";
@ -456,8 +469,18 @@ namespace http {
s << "<b>" << tr("Outbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n"; s << "<b>" << tr("Outbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
for (auto & it : pool->GetOutboundTunnels ()) { for (auto & it : pool->GetOutboundTunnels ()) {
s << "<div class=\"listitem\">"; s << "<div class=\"listitem\">";
it->Print(s); s << it->GetTunnelID () << ":me &#8658;";
if(it->LatencyIsKnown()) // for each tunnel hop if not zero-hop
if (it->GetNumHops ())
{
it->VisitTunnelHops(
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
{
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " &#8658;";
}
);
}
if (it->LatencyIsKnown())
s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
ShowTunnelDetails(s, it->GetState (), false, it->GetNumSentBytes ()); ShowTunnelDetails(s, it->GetState (), false, it->GetNumSentBytes ());
s << "</div>\r\n"; s << "</div>\r\n";
@ -630,8 +653,17 @@ namespace http {
s << "<b>" << tr("Inbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n"; s << "<b>" << tr("Inbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) { for (auto & it : i2p::tunnel::tunnels.GetInboundTunnels ()) {
s << "<div class=\"listitem\">"; s << "<div class=\"listitem\">";
it->Print(s); if (it->GetNumHops ())
if(it->LatencyIsKnown()) {
it->VisitTunnelHops(
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
{
s << "&#8658; " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " ";
}
);
}
s << "&#8658; " << it->GetTunnelID () << ":me";
if (it->LatencyIsKnown())
s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumReceivedBytes ()); ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumReceivedBytes ());
s << "</div>\r\n"; s << "</div>\r\n";
@ -640,8 +672,18 @@ namespace http {
s << "<b>" << tr("Outbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n"; s << "<b>" << tr("Outbound tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) { for (auto & it : i2p::tunnel::tunnels.GetOutboundTunnels ()) {
s << "<div class=\"listitem\">"; s << "<div class=\"listitem\">";
it->Print(s); s << it->GetTunnelID () << ":me &#8658;";
if(it->LatencyIsKnown()) // for each tunnel hop if not zero-hop
if (it->GetNumHops ())
{
it->VisitTunnelHops(
[&s](std::shared_ptr<const i2p::data::IdentityEx> hopIdent)
{
s << " " << i2p::data::GetIdentHashAbbreviation (hopIdent->GetIdentHash ()) << " &#8658;";
}
);
}
if (it->LatencyIsKnown())
s << " ( " << it->GetMeanLatency() << tr("ms") << " )"; s << " ( " << it->GetMeanLatency() << tr("ms") << " )";
ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumSentBytes ()); ShowTunnelDetails(s, it->GetState (), (it->GetTunnelPool () == ExplPool), it->GetNumSentBytes ());
s << "</div>\r\n"; s << "</div>\r\n";
@ -713,7 +755,7 @@ namespace http {
void ShowTransitTunnels (std::stringstream& s) void ShowTransitTunnels (std::stringstream& s)
{ {
if(i2p::tunnel::tunnels.CountTransitTunnels()) if (i2p::tunnel::tunnels.CountTransitTunnels())
{ {
s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n"; s << "<b>" << tr("Transit Tunnels") << ":</b><br>\r\n<div class=\"list\">\r\n";
for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ()) for (const auto& it: i2p::tunnel::tunnels.GetTransitTunnels ())
@ -736,7 +778,7 @@ namespace http {
} }
template<typename Sessions> template<typename Sessions>
static void ShowNTCPTransports (std::stringstream& s, const Sessions& sessions, const std::string name) static void ShowTransportSessions (std::stringstream& s, const Sessions& sessions, const std::string name)
{ {
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: sessions ) for (const auto& it: sessions )
@ -749,6 +791,8 @@ namespace http {
<< it.second->GetRemoteEndpoint ().address ().to_string (); << it.second->GetRemoteEndpoint ().address ().to_string ();
if (!it.second->IsOutgoing ()) tmp_s << " &#8658; "; if (!it.second->IsOutgoing ()) tmp_s << " &#8658; ";
tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; tmp_s << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
if (it.second->GetRelayTag ())
tmp_s << " [itag:" << it.second->GetRelayTag () << "]";
tmp_s << "</div>\r\n" << std::endl; tmp_s << "</div>\r\n" << std::endl;
cnt++; cnt++;
} }
@ -760,6 +804,8 @@ namespace http {
<< "[" << it.second->GetRemoteEndpoint ().address ().to_string () << "]"; << "[" << it.second->GetRemoteEndpoint ().address ().to_string () << "]";
if (!it.second->IsOutgoing ()) tmp_s6 << " &#8658; "; if (!it.second->IsOutgoing ()) tmp_s6 << " &#8658; ";
tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]"; tmp_s6 << " [" << it.second->GetNumSentBytes () << ":" << it.second->GetNumReceivedBytes () << "]";
if (it.second->GetRelayTag ())
tmp_s6 << " [itag:" << it.second->GetRelayTag () << "]";
tmp_s6 << "</div>\r\n" << std::endl; tmp_s6 << "</div>\r\n" << std::endl;
cnt6++; cnt6++;
} }
@ -786,7 +832,7 @@ namespace http {
{ {
auto sessions = ntcp2Server->GetNTCP2Sessions (); auto sessions = ntcp2Server->GetNTCP2Sessions ();
if (!sessions.empty ()) if (!sessions.empty ())
ShowNTCPTransports (s, sessions, "NTCP2"); ShowTransportSessions (s, sessions, "NTCP2");
} }
auto ssuServer = i2p::transport::transports.GetSSUServer (); auto ssuServer = i2p::transport::transports.GetSSUServer ();
if (ssuServer) if (ssuServer)
@ -828,6 +874,13 @@ namespace http {
s << "</div>\r\n</div>\r\n"; s << "</div>\r\n</div>\r\n";
} }
} }
auto ssu2Server = i2p::transport::transports.GetSSU2Server ();
if (ssu2Server)
{
auto sessions = ssu2Server->GetSSU2Sessions ();
if (!sessions.empty ())
ShowTransportSessions (s, sessions, "SSU2");
}
} }
void ShowSAMSessions (std::stringstream& s) void ShowSAMSessions (std::stringstream& s)
@ -840,7 +893,7 @@ namespace http {
return; return;
} }
if(sam->GetSessions ().size ()) if (sam->GetSessions ().size ())
{ {
s << "<b>" << tr("SAM sessions") << ":</b><br>\r\n<div class=\"list\">\r\n"; s << "<b>" << tr("SAM sessions") << ":</b><br>\r\n<div class=\"list\">\r\n";
for (auto& it: sam->GetSessions ()) for (auto& it: sam->GetSessions ())
@ -1039,7 +1092,7 @@ namespace http {
if (expected == provided) return true; if (expected == provided) return true;
} }
LogPrint(eLogWarning, "HTTPServer: auth failure from ", m_Socket->remote_endpoint().address ()); LogPrint(eLogWarning, "HTTPServer: Auth failure from ", m_Socket->remote_endpoint().address ());
return false; return false;
} }
@ -1049,7 +1102,7 @@ namespace http {
std::string content; std::string content;
HTTPRes res; HTTPRes res;
LogPrint(eLogDebug, "HTTPServer: request: ", req.uri); LogPrint(eLogDebug, "HTTPServer: Request: ", req.uri);
if (needAuth && !CheckAuth(req)) { if (needAuth && !CheckAuth(req)) {
res.code = 401; res.code = 401;
@ -1057,6 +1110,7 @@ namespace http {
SendReply(res, content); SendReply(res, content);
return; return;
} }
bool strictheaders; bool strictheaders;
i2p::config::GetOption("http.strictheaders", strictheaders); i2p::config::GetOption("http.strictheaders", strictheaders);
if (strictheaders) if (strictheaders)
@ -1079,6 +1133,7 @@ namespace http {
return; return;
} }
} }
// HTML head start // HTML head start
ShowPageHead (s); ShowPageHead (s);
if (req.uri.find("page=") != std::string::npos) { if (req.uri.find("page=") != std::string::npos) {
@ -1199,7 +1254,7 @@ namespace http {
else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL)
{ {
i2p::context.SetAcceptsTunnels (true); i2p::context.SetAcceptsTunnels (true);
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
Daemon.gracefulShutdownInterval = 0; Daemon.gracefulShutdownInterval = 0;
#elif defined(WIN32_APP) #elif defined(WIN32_APP)
i2p::win32::StopGracefulShutdown (); i2p::win32::StopGracefulShutdown ();
@ -1231,7 +1286,7 @@ namespace http {
{ {
if (dest) if (dest)
{ {
if(dest->DeleteStream (streamID)) if (dest->DeleteStream (streamID))
s << "<b>" << tr("SUCCESS") << "</b>:&nbsp;" << tr("Stream closed") << "<br>\r\n<br>\r\n"; s << "<b>" << tr("SUCCESS") << "</b>:&nbsp;" << tr("Stream closed") << "<br>\r\n<br>\r\n";
else else
s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Stream not found or already was closed") << "<br>\r\n<br>\r\n"; s << "<b>" << tr("ERROR") << "</b>:&nbsp;" << tr("Stream not found or already was closed") << "<br>\r\n<br>\r\n";
@ -1377,7 +1432,7 @@ namespace http {
pass[i] = alnum[random[i] % (sizeof(alnum) - 1)]; pass[i] = alnum[random[i] % (sizeof(alnum) - 1)];
} }
i2p::config::SetOption("http.pass", pass); i2p::config::SetOption("http.pass", pass);
LogPrint(eLogInfo, "HTTPServer: password set to ", pass); LogPrint(eLogInfo, "HTTPServer: Password set to ", pass);
} }
m_IsRunning = true; m_IsRunning = true;
@ -1391,7 +1446,13 @@ namespace http {
void HTTPServer::Stop () void HTTPServer::Stop ()
{ {
m_IsRunning = false; m_IsRunning = false;
boost::system::error_code ec;
m_Acceptor.cancel(ec);
if (ec)
LogPrint (eLogDebug, "HTTPServer: Error while cancelling operations on acceptor: ", ec.message ());
m_Acceptor.close(); m_Acceptor.close();
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
{ {
@ -1412,7 +1473,7 @@ namespace http {
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "HTTPServer: runtime exception: ", ex.what ()); LogPrint (eLogError, "HTTPServer: Runtime exception: ", ex.what ());
} }
} }
} }
@ -1427,15 +1488,13 @@ namespace http {
void HTTPServer::HandleAccept(const boost::system::error_code& ecode, void HTTPServer::HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket) std::shared_ptr<boost::asio::ip::tcp::socket> newSocket)
{ {
if (ecode) if (!ecode)
CreateConnection(newSocket);
else
{ {
if(newSocket) newSocket->close(); if (newSocket) newSocket->close();
LogPrint(eLogError, "HTTP Server: error handling accept ", ecode.message()); LogPrint(eLogError, "HTTP Server: Error handling accept: ", ecode.message());
if(ecode != boost::asio::error::operation_aborted)
Accept();
return;
} }
CreateConnection(newSocket);
Accept (); Accept ();
} }

View File

@ -98,8 +98,8 @@ namespace http
void ShowSAMSessions (std::stringstream& s); void ShowSAMSessions (std::stringstream& s);
void ShowI2PTunnels (std::stringstream& s); void ShowI2PTunnels (std::stringstream& s);
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token); void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token);
void ShowSAMSession (std::stringstream& s, const std::string& id); void ShowSAMSession (std::stringstream& s, const std::string& id);
void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id); void ShowI2CPLocalDestination (std::stringstream& s, const std::string& id);
} // http } // http
} // i2p } // i2p

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -34,50 +34,58 @@ namespace http
// bundled style sheet // bundled style sheet
const std::string internalCSS = const std::string internalCSS =
"<style>\r\n" "<style>\r\n"
" body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n" ":root { --main-bg-color: #fafafa; --main-text-color: #103456; --main-link-color: #894c84; --main-link-hover-color: #fafafa; }\r\n"
" a, .slide label { text-decoration: none; color: #894C84; }\r\n" "@media (prefers-color-scheme: dark) { :root { --main-bg-color: #242424; --main-text-color: #17ab5c; --main-link-color: #bf64b7; --main-link-hover-color: #000000; } }\r\n"
" a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n" "body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: var(--main-bg-color); color: var(--main-text-color); }\r\n"
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n" "a, .slide label { text-decoration: none; color: var(--main-link-color); }\r\n"
" padding: 0 5px; border: 1px solid #894C84; }\r\n" "a:hover, .slide label:hover, button[type=submit]:hover { color: var(--main-link-hover-color); background: var(--main-link-color); }\r\n"
" .header { font-size: 2.5em; text-align: center; margin: 1em 0; color: #894C84; }\r\n" "a.button { appearance: button; text-decoration: none; padding: 0 5px; border: 1px solid var(--main-link-color); }\r\n"
" .wrapper { margin: 0 auto; padding: 1em; max-width: 64em; }\r\n" ".header { font-size: 2.5em; text-align: center; margin: 1em 0; color: var(--main-link-color); }\r\n"
" .menu { display: block; float: left; overflow: hidden; max-width: 12em; white-space: nowrap; text-overflow: ellipsis; }\r\n" ".wrapper { margin: 0 auto; padding: 1em; max-width: 64em; }\r\n"
" .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" ".menu { display: block; float: left; overflow: hidden; padding: 4px; max-width: 12em; white-space: nowrap; text-overflow: ellipsis ;}\r\n"
" .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" ".listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
" .content { float: left; font-size: 1em; margin-left: 4em; max-width: 48em; overflow: auto; }\r\n" ".tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
" .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n" ".content { float: left; font-size: 1em; margin-left: 2em; padding: 4px; max-width: 50em; overflow: auto; }\r\n"
" .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n" ".tunnel.established { color: #56B734; }\r\n"
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" ".tunnel.expiring { color: #D3AE3F; }\r\n"
" table { display: table; border-collapse: collapse; text-align: center; }\r\n" ".tunnel.failed { color: #D33F3F; }\r\n"
" table.extaddr { text-align: left; } table.services { width: 100%; }\r\n" ".tunnel.building { color: #434343; }\r\n"
" textarea { word-break: break-all; }\r\n" "caption { font-size: 1.5em; text-align: center; color: var(--main-link-color); }\r\n"
" .streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis;}\r\n" "table { display: table; border-collapse: collapse; text-align: center; }\r\n"
" .slide div.slidecontent, .slide [type=\"checkbox\"] { display: none; }\r\n" "table.extaddr { text-align: left; }\r\n"
" .slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n" "table.services { width: 100%; }\r\n"
" .disabled { color: #D33F3F; } .enabled { color: #56B734; }\r\n" "textarea { background-color: var(--main-bg-color); color: var(--main-text-color); word-break: break-all; }\r\n"
" @media screen and (max-width: 1150px) {\r\n" /* adaptive style */ ".streamdest { width: 120px; max-width: 240px; overflow: hidden; text-overflow: ellipsis; }\r\n"
" .wrapper { max-width: 58em; } .menu { max-width: 10em; }\r\n" ".slide div.slidecontent, .slide [type=\"checkbox\"] { display: none; }\r\n"
" .content { margin-left: 2em; max-width: 42em; }\r\n" ".slide [type=\"checkbox\"]:checked ~ div.slidecontent { display: block; margin-top: 0; padding: 0; }\r\n"
" }\r\n" ".disabled { color: #D33F3F; }\r\n"
" @media screen and (max-width: 980px) {\r\n" ".enabled { color: #56B734; }\r\n"
" body { padding: 1.5em 0 0 0; }\r\n" "button[type=submit] { background-color: transparent; color: var(--main-link-color); text-decoration: none;\r\n"
" .menu { width: 100%; max-width: unset; display: block; float: none; position: unset; font-size: 16px;\r\n" " padding: 5px; border: 1px solid var(--main-link-color); font-size: 14px; }\r\n"
" text-align: center; }\r\n" "input, select, select option { background-color: var(--main-bg-color); color: var(--main-link-color); padding: 5px;\r\n"
" .menu a, .commands a { display: inline-block; padding: 4px; }\r\n" " border: 1px solid var(--main-link-color); font-size: 14px; }\r\n"
" .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%;\r\n" "input:focus, select:focus, select option:focus { outline: none; }\r\n"
" text-align: center; }\r\n" "input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; }\r\n"
" a, .slide label { /* margin-right: 10px; */ display: block; /* font-size: 18px; */ }\r\n" "@media screen and (max-width: 1150px) { /* adaptive style */\r\n"
" .header { margin: unset; font-size: 1.5em; } small {display: block}\r\n" " .wrapper { max-width: 58em; }\r\n"
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none;\r\n" " .content { max-width: 40em; }\r\n"
" margin-top: 10px; padding: 6px; border: 1px solid #894c84; width: -webkit-fill-available; }\r\n" "}\r\n"
" input, select { width: 35%; text-align: center; padding: 5px;\r\n" "@media screen and (max-width: 980px) { body { font: 100%/1.2em sans-serif; padding: 1.2em 0 0 0; }\r\n"
" border: 2px solid #ccc; -webkit-border-radius: 5px; border-radius: 5px; font-size: 18px; }\r\n" " .menu { width: 100%; max-width: unset; display: block; float: none; position: unset; font-size: 16px; text-align: center; }\r\n"
" table.extaddr { margin: auto; text-align: unset; }\r\n" " .menu a, .commands a { display: inline-block; padding: 4px; }\r\n"
" textarea { width: -webkit-fill-available; height: auto; padding:5px; border:2px solid #ccc;\r\n" " .content { float: none; margin-left: unset; margin-top: 16px; max-width: 100%; width: 100%; text-align: center; }\r\n"
" -webkit-border-radius: 5px; border-radius: 5px; font-size: 12px; }\r\n" " a, .slide label { display: block; }\r\n"
" button[type=submit] { padding: 5px 15px; background: #ccc; border: 0 none; cursor: pointer;\r\n" " .header { margin: unset; font-size: 1.5em; }\r\n"
" -webkit-border-radius: 5px; border-radius: 5px; position: relative; height: 36px; display: -webkit-inline-box; margin-top: 10px; }\r\n" " small { display: block; }\r\n"
" }\r\n" " a.button { appearance: button; text-decoration: none; margin-top: 10px; padding: 6px; border: 2px solid var(--main-link-color);\r\n"
" border-radius: 5px; width: -webkit-fill-available; }\r\n"
" input, select { width: 35%; text-align: center; padding: 5px; border: 2px solid var(--main-link-color); border-radius: 5px; font-size: 18px; }\r\n"
" table.extaddr { margin: auto; text-align: unset; }\r\n"
" textarea { width: -webkit-fill-available; height: auto; padding: 5px; border: 2px solid var(--main-link-color);\r\n"
" border-radius: 5px; font-size: 12px; }\r\n"
" button[type=submit] { padding: 5px 15px; background: transparent; border: 2px solid var(--main-link-color); cursor: pointer;\r\n"
" border-radius: 5px; position: relative; height: 36px; display: -webkit-inline-box; margin-top: 10px; }\r\n"
"}\r\n"
"</style>\r\n"; "</style>\r\n";
// for external style sheet // for external style sheet

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2022, 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 <stdio.h> #include <stdio.h>
#include <sstream> #include <sstream>
#include <openssl/x509.h> #include <openssl/x509.h>
@ -48,39 +56,38 @@ namespace client
if (i2pcp_key.at(0) != '/') if (i2pcp_key.at(0) != '/')
i2pcp_key = i2p::fs::DataDirPath(i2pcp_key); i2pcp_key = i2p::fs::DataDirPath(i2pcp_key);
if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) { if (!i2p::fs::Exists (i2pcp_crt) || !i2p::fs::Exists (i2pcp_key)) {
LogPrint (eLogInfo, "I2PControl: creating new certificate for control connection"); LogPrint (eLogInfo, "I2PControl: Creating new certificate for control connection");
CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str()); CreateCertificate (i2pcp_crt.c_str(), i2pcp_key.c_str());
} else { } else {
LogPrint(eLogDebug, "I2PControl: using cert from ", i2pcp_crt); LogPrint(eLogDebug, "I2PControl: Using cert from ", i2pcp_crt);
} }
m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use); m_SSLContext.set_options (boost::asio::ssl::context::default_workarounds | boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::single_dh_use);
m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem); m_SSLContext.use_certificate_file (i2pcp_crt, boost::asio::ssl::context::pem);
m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem); m_SSLContext.use_private_key_file (i2pcp_key, boost::asio::ssl::context::pem);
// handlers // handlers
m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler; m_MethodHandlers["Authenticate"] = &I2PControlService::AuthenticateHandler;
m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler; m_MethodHandlers["Echo"] = &I2PControlService::EchoHandler;
m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler; m_MethodHandlers["I2PControl"] = &I2PControlService::I2PControlHandler;
m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler; m_MethodHandlers["RouterInfo"] = &I2PControlService::RouterInfoHandler;
m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler; m_MethodHandlers["RouterManager"] = &I2PControlService::RouterManagerHandler;
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler; m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler; m_MethodHandlers["ClientServicesInfo"] = &I2PControlService::ClientServicesInfoHandler;
// I2PControl // I2PControl
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler; m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
// RouterInfo // RouterInfo
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler; m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler; m_RouterInfoHandlers["i2p.router.version"] = &I2PControlService::VersionHandler;
m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler; m_RouterInfoHandlers["i2p.router.status"] = &I2PControlService::StatusHandler;
m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler; m_RouterInfoHandlers["i2p.router.netdb.knownpeers"] = &I2PControlService::NetDbKnownPeersHandler;
m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler; m_RouterInfoHandlers["i2p.router.netdb.activepeers"] = &I2PControlService::NetDbActivePeersHandler;
m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S; m_RouterInfoHandlers["i2p.router.net.bw.inbound.1s"] = &I2PControlService::InboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S; m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler; m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler; m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler;
&I2PControlService::TunnelsSuccessRateHandler;
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes; m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes; m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
@ -96,10 +103,10 @@ namespace client
// ClientServicesInfo // ClientServicesInfo
m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler; m_ClientServicesInfoHandlers["I2PTunnel"] = &I2PControlService::I2PTunnelInfoHandler;
m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler; m_ClientServicesInfoHandlers["HTTPProxy"] = &I2PControlService::HTTPProxyInfoHandler;
m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler; m_ClientServicesInfoHandlers["SOCKS"] = &I2PControlService::SOCKSInfoHandler;
m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler; m_ClientServicesInfoHandlers["SAM"] = &I2PControlService::SAMInfoHandler;
m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler; m_ClientServicesInfoHandlers["BOB"] = &I2PControlService::BOBInfoHandler;
m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler; m_ClientServicesInfoHandlers["I2CP"] = &I2PControlService::I2CPInfoHandler;
} }
I2PControlService::~I2PControlService () I2PControlService::~I2PControlService ()
@ -142,7 +149,7 @@ namespace client
try { try {
m_Service.run (); m_Service.run ();
} catch (std::exception& ex) { } catch (std::exception& ex) {
LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ()); LogPrint (eLogError, "I2PControl: Runtime exception: ", ex.what ());
} }
} }
} }
@ -160,10 +167,10 @@ namespace client
Accept (); Accept ();
if (ecode) { if (ecode) {
LogPrint (eLogError, "I2PControl: accept error: ", ecode.message ()); LogPrint (eLogError, "I2PControl: Accept error: ", ecode.message ());
return; return;
} }
LogPrint (eLogDebug, "I2PControl: new request from ", socket->lowest_layer ().remote_endpoint ()); LogPrint (eLogDebug, "I2PControl: New request from ", socket->lowest_layer ().remote_endpoint ());
Handshake (socket); Handshake (socket);
} }
@ -176,7 +183,7 @@ namespace client
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket) void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
{ {
if (ecode) { if (ecode) {
LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ()); LogPrint (eLogError, "I2PControl: Handshake error: ", ecode.message ());
return; return;
} }
//std::this_thread::sleep_for (std::chrono::milliseconds(5)); //std::this_thread::sleep_for (std::chrono::milliseconds(5));
@ -202,7 +209,7 @@ namespace client
{ {
if (ecode) if (ecode)
{ {
LogPrint (eLogError, "I2PControl: read error: ", ecode.message ()); LogPrint (eLogError, "I2PControl: Read error: ", ecode.message ());
return; return;
} }
else else
@ -225,7 +232,7 @@ namespace client
} }
if (ss.eof ()) if (ss.eof ())
{ {
LogPrint (eLogError, "I2PControl: malformed request, HTTP header expected"); LogPrint (eLogError, "I2PControl: Malformed request, HTTP header expected");
return; // TODO: return; // TODO:
} }
std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read std::streamoff rem = contentLength + ss.tellg () - bytes_transferred; // more bytes to read
@ -250,7 +257,7 @@ namespace client
} }
else else
{ {
LogPrint (eLogWarning, "I2PControl: unknown method ", method); LogPrint (eLogWarning, "I2PControl: Unknown method ", method);
response << "{\"id\":null,\"error\":"; response << "{\"id\":null,\"error\":";
response << "{\"code\":-32601,\"message\":\"Method not found\"},"; response << "{\"code\":-32601,\"message\":\"Method not found\"},";
response << "\"jsonrpc\":\"2.0\"}"; response << "\"jsonrpc\":\"2.0\"}";
@ -259,7 +266,7 @@ namespace client
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "I2PControl: exception when handle request: ", ex.what ()); LogPrint (eLogError, "I2PControl: Exception when handle request: ", ex.what ());
std::ostringstream response; std::ostringstream response;
response << "{\"id\":null,\"error\":"; response << "{\"id\":null,\"error\":";
response << "{\"code\":-32700,\"message\":\"" << ex.what () << "\"},"; response << "{\"code\":-32700,\"message\":\"" << ex.what () << "\"},";
@ -268,7 +275,7 @@ namespace client
} }
catch (...) catch (...)
{ {
LogPrint (eLogError, "I2PControl: handle request unknown exception"); LogPrint (eLogError, "I2PControl: Handle request unknown exception");
} }
} }
} }
@ -278,11 +285,16 @@ namespace client
ss << "\"" << name << "\":" << value; ss << "\"" << name << "\":" << value;
} }
void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const void I2PControlService::InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes) const
{ {
ss << "\"" << name << "\":"; ss << "\"" << name << "\":";
if (value.length () > 0) if (value.length () > 0)
ss << "\"" << value << "\""; {
if (quotes)
ss << "\"" << value << "\"";
else
ss << value;
}
else else
ss << "null"; ss << "null";
} }
@ -329,7 +341,7 @@ namespace client
std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf) std::shared_ptr<ssl_socket> socket, std::shared_ptr<I2PControlBuffer> buf)
{ {
if (ecode) { if (ecode) {
LogPrint (eLogError, "I2PControl: write error: ", ecode.message ()); LogPrint (eLogError, "I2PControl: Write error: ", ecode.message ());
} }
} }
@ -379,7 +391,7 @@ namespace client
void I2PControlService::PasswordHandler (const std::string& value) void I2PControlService::PasswordHandler (const std::string& value)
{ {
LogPrint (eLogWarning, "I2PControl: new password=", value, ", to make it persistent you should update your config!"); LogPrint (eLogWarning, "I2PControl: New password=", value, ", to make it persistent you should update your config!");
m_Password = value; m_Password = value;
m_Tokens.clear (); m_Tokens.clear ();
} }
@ -395,8 +407,8 @@ namespace client
auto it1 = m_RouterInfoHandlers.find (it->first); auto it1 = m_RouterInfoHandlers.find (it->first);
if (it1 != m_RouterInfoHandlers.end ()) if (it1 != m_RouterInfoHandlers.end ())
{ {
if (!first) results << ","; if (!first) results << ",";
else first = false; else first = false;
(this->*(it1->second))(results); (this->*(it1->second))(results);
} }
else else
@ -406,7 +418,7 @@ namespace client
void I2PControlService::UptimeHandler (std::ostringstream& results) void I2PControlService::UptimeHandler (std::ostringstream& results)
{ {
InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL)); InsertParam (results, "i2p.router.uptime", std::to_string (i2p::context.GetUptime ()*1000LL), false);
} }
void I2PControlService::VersionHandler (std::ostringstream& results) void I2PControlService::VersionHandler (std::ostringstream& results)
@ -466,7 +478,7 @@ namespace client
void I2PControlService::NetTotalSentBytes (std::ostringstream& results) void I2PControlService::NetTotalSentBytes (std::ostringstream& results)
{ {
InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ()); InsertParam (results, "i2p.router.net.total.sent.bytes", (double)i2p::transport::transports.GetTotalSentBytes ());
} }
@ -494,7 +506,7 @@ namespace client
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(1)); // 1 second to make sure response has been sent
m_ShutdownTimer.async_wait ( m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode) [](const boost::system::error_code& ecode)
{ {
Daemon.running = 0; Daemon.running = 0;
}); });
} }
@ -508,7 +520,7 @@ namespace client
m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second m_ShutdownTimer.expires_from_now (boost::posix_time::seconds(timeout + 1)); // + 1 second
m_ShutdownTimer.async_wait ( m_ShutdownTimer.async_wait (
[](const boost::system::error_code& ecode) [](const boost::system::error_code& ecode)
{ {
Daemon.running = 0; Daemon.running = 0;
}); });
} }
@ -577,11 +589,11 @@ namespace client
// save cert // save cert
if ((f = fopen (crt_path, "wb")) != NULL) { if ((f = fopen (crt_path, "wb")) != NULL) {
LogPrint (eLogInfo, "I2PControl: saving new cert to ", crt_path); LogPrint (eLogInfo, "I2PControl: Saving new cert to ", crt_path);
PEM_write_X509 (f, x509); PEM_write_X509 (f, x509);
fclose (f); fclose (f);
} else { } else {
LogPrint (eLogError, "I2PControl: can't write cert: ", strerror(errno)); LogPrint (eLogError, "I2PControl: Can't write cert: ", strerror(errno));
} }
// save key // save key
@ -590,12 +602,12 @@ namespace client
PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL); PEM_write_PrivateKey (f, pkey, NULL, NULL, 0, NULL, NULL);
fclose (f); fclose (f);
} else { } else {
LogPrint (eLogError, "I2PControl: can't write key: ", strerror(errno)); LogPrint (eLogError, "I2PControl: Can't write key: ", strerror(errno));
} }
X509_free (x509); X509_free (x509);
} else { } else {
LogPrint (eLogError, "I2PControl: can't create RSA key for certificate"); LogPrint (eLogError, "I2PControl: Can't create RSA key for certificate");
} }
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, 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
* *
@ -65,7 +65,7 @@ namespace client
void InsertParam (std::ostringstream& ss, const std::string& name, int value) const; void InsertParam (std::ostringstream& ss, const std::string& name, int value) const;
void InsertParam (std::ostringstream& ss, const std::string& name, double value) const; void InsertParam (std::ostringstream& ss, const std::string& name, double value) const;
void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value) const; void InsertParam (std::ostringstream& ss, const std::string& name, const std::string& value, bool quotes = true) const;
void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const; void InsertParam (std::ostringstream& ss, const std::string& name, const boost::property_tree::ptree& value) const;
// methods // methods

View File

@ -29,7 +29,7 @@ namespace transport
{ {
if (m_IsRunning) if (m_IsRunning)
{ {
LogPrint(eLogInfo, "UPnP: stopping"); LogPrint(eLogInfo, "UPnP: Stopping");
m_IsRunning = false; m_IsRunning = false;
m_Timer.cancel (); m_Timer.cancel ();
m_Service.stop (); m_Service.stop ();
@ -46,7 +46,7 @@ namespace transport
void UPnP::Start() void UPnP::Start()
{ {
m_IsRunning = true; m_IsRunning = true;
LogPrint(eLogInfo, "UPnP: starting"); LogPrint(eLogInfo, "UPnP: Starting");
m_Service.post (std::bind (&UPnP::Discover, this)); m_Service.post (std::bind (&UPnP::Discover, this));
std::unique_lock<std::mutex> l(m_StartedMutex); std::unique_lock<std::mutex> l(m_StartedMutex);
m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this))); m_Thread.reset (new std::thread (std::bind (&UPnP::Run, this)));
@ -72,7 +72,7 @@ namespace transport
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "UPnP: runtime exception: ", ex.what ()); LogPrint (eLogError, "UPnP: Runtime exception: ", ex.what ());
PortMapping (); PortMapping ();
} }
} }
@ -93,7 +93,7 @@ namespace transport
#endif #endif
isError = err != UPNPDISCOVER_SUCCESS; isError = err != UPNPDISCOVER_SUCCESS;
#else // MINIUPNPC_API_VERSION >= 8 #else // MINIUPNPC_API_VERSION >= 8
err = 0; err = 0;
m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0); m_Devlist = upnpDiscover (UPNP_RESPONSE_TIMEOUT, NULL, NULL, 0);
isError = m_Devlist == NULL; isError = m_Devlist == NULL;
@ -106,7 +106,7 @@ namespace transport
if (isError) if (isError)
{ {
LogPrint (eLogError, "UPnP: unable to discover Internet Gateway Devices: error ", err); LogPrint (eLogError, "UPnP: Unable to discover Internet Gateway Devices: error ", err);
return; return;
} }
@ -117,22 +117,22 @@ namespace transport
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);
if(err != UPNPCOMMAND_SUCCESS) if(err != UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: unable to get external address: error ", err); LogPrint (eLogError, "UPnP: Unable to get external address: error ", err);
return; return;
} }
else else
{ {
LogPrint (eLogError, "UPnP: found Internet Gateway Device ", m_upnpUrls.controlURL); LogPrint (eLogError, "UPnP: Found Internet Gateway Device ", m_upnpUrls.controlURL);
if (!m_externalIPAddress[0]) if (!m_externalIPAddress[0])
{ {
LogPrint (eLogError, "UPnP: found Internet Gateway Device doesn't know our external address"); LogPrint (eLogError, "UPnP: Found Internet Gateway Device doesn't know our external address");
return; return;
} }
} }
} }
else else
{ {
LogPrint (eLogError, "UPnP: unable to find valid Internet Gateway Device: error ", err); LogPrint (eLogError, "UPnP: Unable to find valid Internet Gateway Device: error ", err);
return; return;
} }
@ -183,7 +183,7 @@ namespace transport
err = CheckMapping (strPort.c_str (), strType.c_str ()); err = CheckMapping (strPort.c_str (), strType.c_str ());
if (err != UPNPCOMMAND_SUCCESS) // if mapping not found if (err != UPNPCOMMAND_SUCCESS) // if mapping not found
{ {
LogPrint (eLogDebug, "UPnP: possibly port ", strPort, " is not forwarded: return code ", err); LogPrint (eLogDebug, "UPnP: Port ", strPort, " is possibly not forwarded: return code ", err);
#if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS)) #if ((MINIUPNPC_API_VERSION >= 8) || defined (UPNPDISCOVER_SUCCESS))
err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL); err = UPNP_AddPortMapping (m_upnpUrls.controlURL, m_upnpData.first.servicetype, strPort.c_str (), strPort.c_str (), m_NetworkAddr, strDesc.c_str (), strType.c_str (), NULL, NULL);
@ -192,18 +192,18 @@ namespace transport
#endif #endif
if (err != UPNPCOMMAND_SUCCESS) if (err != UPNPCOMMAND_SUCCESS)
{ {
LogPrint (eLogError, "UPnP: port forwarding to ", m_NetworkAddr, ":", strPort, " failed: return code ", err); LogPrint (eLogError, "UPnP: Port forwarding to ", m_NetworkAddr, ":", strPort, " failed: return code ", err);
return; return;
} }
else else
{ {
LogPrint (eLogInfo, "UPnP: port successfully forwarded (", m_externalIPAddress ,":", strPort, " type ", strType, " -> ", m_NetworkAddr ,":", strPort ,")"); LogPrint (eLogInfo, "UPnP: Port successfully forwarded (", m_externalIPAddress ,":", strPort, " type ", strType, " -> ", m_NetworkAddr ,":", strPort ,")");
return; return;
} }
} }
else else
{ {
LogPrint (eLogDebug, "UPnP: external forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device"); LogPrint (eLogDebug, "UPnP: External forward from ", m_NetworkAddr, ":", strPort, " exists on current Internet Gateway Device");
return; return;
} }
} }
@ -225,7 +225,7 @@ namespace transport
} }
std::string strType (GetProto (address)), strPort (std::to_string (address->port)); std::string strType (GetProto (address)), strPort (std::to_string (address->port));
int err = UPNPCOMMAND_SUCCESS; int err = UPNPCOMMAND_SUCCESS;
err = CheckMapping (strPort.c_str (), strType.c_str ()); err = CheckMapping (strPort.c_str (), strType.c_str ());
if (err == UPNPCOMMAND_SUCCESS) if (err == UPNPCOMMAND_SUCCESS)
{ {

View File

@ -51,7 +51,7 @@ namespace transport
private: private:
void Discover (); void Discover ();
int CheckMapping (const char* port, const char* type); int CheckMapping (const char* port, const char* type);
void PortMapping (); void PortMapping ();
void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address); void TryPortMapping (std::shared_ptr<i2p::data::RouterInfo::Address> address);
void CloseMapping (); void CloseMapping ();
@ -80,7 +80,7 @@ namespace transport
} }
} }
#else // USE_UPNP #else // USE_UPNP
namespace i2p { namespace i2p {
namespace transport { namespace transport {
/* class stub */ /* class stub */

View File

@ -24,6 +24,7 @@
#include "Tunnel.h" #include "Tunnel.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "ClientContext.h" #include "ClientContext.h"
#include "Transports.h"
void handle_signal(int sig) void handle_signal(int sig)
{ {
@ -54,6 +55,14 @@ void handle_signal(int sig)
case SIGPIPE: case SIGPIPE:
LogPrint(eLogInfo, "SIGPIPE received"); LogPrint(eLogInfo, "SIGPIPE received");
break; break;
case SIGTSTP:
LogPrint(eLogInfo, "Daemon: Got SIGTSTP, disconnecting from network...");
i2p::transport::transports.SetOnline(false);
break;
case SIGCONT:
LogPrint(eLogInfo, "Daemon: Got SIGCONT, restoring connection to network...");
i2p::transport::transports.SetOnline(true);
break;
} }
} }
@ -72,7 +81,8 @@ namespace i2p
if (pid < 0) // error if (pid < 0) // error
{ {
LogPrint(eLogError, "Daemon: could not fork: ", strerror(errno)); LogPrint(eLogError, "Daemon: Could not fork: ", strerror(errno));
std::cerr << "i2pd: Could not fork: " << strerror(errno) << std::endl;
return false; return false;
} }
@ -81,13 +91,15 @@ namespace i2p
int sid = setsid(); int sid = setsid();
if (sid < 0) if (sid < 0)
{ {
LogPrint(eLogError, "Daemon: could not create process group."); LogPrint(eLogError, "Daemon: Could not create process group.");
std::cerr << "i2pd: Could not create process group." << std::endl;
return false; return false;
} }
std::string d = i2p::fs::GetDataDir(); std::string d = i2p::fs::GetDataDir();
if (chdir(d.c_str()) != 0) if (chdir(d.c_str()) != 0)
{ {
LogPrint(eLogError, "Daemon: could not chdir: ", strerror(errno)); LogPrint(eLogError, "Daemon: Could not chdir: ", strerror(errno));
std::cerr << "i2pd: Could not chdir: " << strerror(errno) << std::endl;
return false; return false;
} }
@ -102,14 +114,14 @@ namespace i2p
uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles); uint16_t nfiles; i2p::config::GetOption("limits.openfiles", nfiles);
getrlimit(RLIMIT_NOFILE, &limit); getrlimit(RLIMIT_NOFILE, &limit);
if (nfiles == 0) { if (nfiles == 0) {
LogPrint(eLogInfo, "Daemon: using system limit in ", limit.rlim_cur, " max open files"); LogPrint(eLogInfo, "Daemon: Using system limit in ", limit.rlim_cur, " max open files");
} else if (nfiles <= limit.rlim_max) { } else if (nfiles <= limit.rlim_max) {
limit.rlim_cur = nfiles; limit.rlim_cur = nfiles;
if (setrlimit(RLIMIT_NOFILE, &limit) == 0) { if (setrlimit(RLIMIT_NOFILE, &limit) == 0) {
LogPrint(eLogInfo, "Daemon: set max number of open files to ", LogPrint(eLogInfo, "Daemon: Set max number of open files to ",
nfiles, " (system limit is ", limit.rlim_max, ")"); nfiles, " (system limit is ", limit.rlim_max, ")");
} else { } else {
LogPrint(eLogError, "Daemon: can't set max number of open files: ", strerror(errno)); LogPrint(eLogError, "Daemon: Can't set max number of open files: ", strerror(errno));
} }
} else { } else {
LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max); LogPrint(eLogError, "Daemon: limits.openfiles exceeds system limit: ", limit.rlim_max);
@ -122,11 +134,11 @@ namespace i2p
if (cfsize <= limit.rlim_max) { if (cfsize <= limit.rlim_max) {
limit.rlim_cur = cfsize; limit.rlim_cur = cfsize;
if (setrlimit(RLIMIT_CORE, &limit) != 0) { if (setrlimit(RLIMIT_CORE, &limit) != 0) {
LogPrint(eLogError, "Daemon: can't set max size of coredump: ", strerror(errno)); LogPrint(eLogError, "Daemon: Can't set max size of coredump: ", strerror(errno));
} else if (cfsize == 0) { } else if (cfsize == 0) {
LogPrint(eLogInfo, "Daemon: coredumps disabled"); LogPrint(eLogInfo, "Daemon: coredumps disabled");
} else { } else {
LogPrint(eLogInfo, "Daemon: set max size of core files to ", cfsize / 1024, "Kb"); LogPrint(eLogInfo, "Daemon: Set max size of core files to ", cfsize / 1024, "Kb");
} }
} else { } else {
LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max); LogPrint(eLogError, "Daemon: limits.coresize exceeds system limit: ", limit.rlim_max);
@ -143,14 +155,16 @@ namespace i2p
pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600); pidFH = open(pidfile.c_str(), O_RDWR | O_CREAT, 0600);
if (pidFH < 0) if (pidFH < 0)
{ {
LogPrint(eLogError, "Daemon: could not create pid file ", pidfile, ": ", strerror(errno)); LogPrint(eLogError, "Daemon: Could not create pid file ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not create pid file " << pidfile << ": " << strerror(errno) << std::endl;
return false; return false;
} }
#ifndef ANDROID #ifndef ANDROID
if (lockf(pidFH, F_TLOCK, 0) != 0) if (lockf(pidFH, F_TLOCK, 0) != 0)
{ {
LogPrint(eLogError, "Daemon: could not lock pid file ", pidfile, ": ", strerror(errno)); LogPrint(eLogError, "Daemon: Could not lock pid file ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not lock pid file " << pidfile << ": " << strerror(errno) << std::endl;
return false; return false;
} }
#endif #endif
@ -159,12 +173,16 @@ namespace i2p
ftruncate(pidFH, 0); ftruncate(pidFH, 0);
if (write(pidFH, pid, strlen(pid)) < 0) if (write(pidFH, pid, strlen(pid)) < 0)
{ {
LogPrint(eLogError, "Daemon: could not write pidfile: ", strerror(errno)); LogPrint(eLogError, "Daemon: Could not write pidfile ", pidfile, ": ", strerror(errno));
std::cerr << "i2pd: Could not write pidfile " << pidfile << ": " << strerror(errno) << std::endl;
return false; return false;
} }
} }
gracefulShutdownInterval = 0; // not specified gracefulShutdownInterval = 0; // not specified
// handle signal TSTP
bool handleTSTP; i2p::config::GetOption("unix.handle_sigtstp", handleTSTP);
// Signal handler // Signal handler
struct sigaction sa; struct sigaction sa;
sa.sa_handler = handle_signal; sa.sa_handler = handle_signal;
@ -176,6 +194,11 @@ namespace i2p
sigaction(SIGTERM, &sa, 0); sigaction(SIGTERM, &sa, 0);
sigaction(SIGINT, &sa, 0); sigaction(SIGINT, &sa, 0);
sigaction(SIGPIPE, &sa, 0); sigaction(SIGPIPE, &sa, 0);
if (handleTSTP)
{
sigaction(SIGTSTP, &sa, 0);
sigaction(SIGCONT, &sa, 0);
}
return Daemon_Singleton::start(); return Daemon_Singleton::start();
} }

25
debian/changelog vendored
View File

@ -1,3 +1,28 @@
i2pd (2.42.1-1) unstable; urgency=medium
* updated to version 2.42.1/0.9.54
* remove -O3 optimization flag
-- r4sas <r4sas@i2pmail.org> Tue, 24 May 2022 12:00:00 +0000
i2pd (2.42.0-1) unstable; urgency=medium
* updated to version 2.42.0/0.9.54
-- orignal <orignal@i2pmail.org> Sun, 22 May 2022 16:00:00 +0000
i2pd (2.41.0-1) unstable; urgency=medium
* updated to version 2.41.0/0.9.53
-- r4sas <r4sas@i2pmail.org> Sun, 20 Feb 2022 13:00:00 +0000
i2pd (2.40.0-1) unstable; urgency=medium
* updated to version 2.40.0/0.9.52
-- orignal <orignal@i2pmail.org> Mon, 29 Nov 2021 16:00:00 +0000
i2pd (2.39.0-1) unstable; urgency=medium i2pd (2.39.0-1) unstable; urgency=medium
* updated to version 2.39.0/0.9.51 * updated to version 2.39.0/0.9.51

View File

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

9
debian/rules vendored
View File

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

215
i18n/Armenian.cpp Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2021, 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"
// Armenian localization file
namespace i2p
{
namespace i18n
{
namespace armenian // language namespace
{
// language name in lowercase
static std::string language = "armenian";
// 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
{
{"KiB", "ԿիԲ"},
{"MiB", "ՄիԲ"},
{"GiB", "ԳիԲ"},
{"building", "կառուցվում է"},
{"failed", "Անհաջող"},
{"expiring", "Լրանում է"},
{"established", "կարգավոյված է"},
{"unknown", "անհայտ"},
{"exploratory", "հետազոտոկան"},
{"<b>i2pd</b> webconsole", "Վեբ-կոնսոլ <b>i2pd</b>"},
{"Main page", "Գլխավոր էջ"},
{"Router commands", "Երթուղիչի հրահանգներ"},
{"Local Destinations", "Տեղական վերջնակետերը"},
{"LeaseSets", "ԼիզՍեթեր"},
{"Tunnels", "Թունելներ"},
{"Transit Tunnels", "Տարանցիկ թունելներ"},
{"Transports", "Տրանսպորտ"},
{"I2P tunnels", "I2P թունելներ"},
{"SAM sessions", "SAM նստաշրջաններ"},
{"ERROR", "ՍԽԱԼ"},
{"OK", "ԼԱՎ"},
{"Testing", "Փորձարկում"},
{"Firewalled", "Արգելափակված է դրսից"},
{"Unknown", "Անհայտ"},
{"Proxy", "Պրոկսի"},
{"Mesh", "MESH-ցանց"},
{"Error", "Սխալ"},
{"Clock skew", "Ոչ ճշգրիտ ժամանակ"},
{"Offline", "Օֆլայն"},
{"Symmetric NAT", "Սիմետրիկ NAT"},
{"Uptime", "Առկայություն"},
{"Network status", "Ցանցի կարգավիճակ"},
{"Network status v6", "Ցանցի կարգավիճակ v6"},
{"Stopping in", "Դադարում"},
{"Family", "Խմբատեսակ"},
{"Tunnel creation success rate", "Հաջողությամբ կառուցված թունելներ"},
{"Received", "Ստացվել է"},
{"KiB/s", "ԿիԲ/վ"},
{"Sent", "Ուղարկվել է"},
{"Transit", "Տարանցում"},
{"Data path", "Տվյալների ուղին"},
{"Hidden content. Press on text to see.", "Թաքցված բովանդակություն: Տեսնելու համար սեղմեկ տեքստին:"},
{"Router Ident", "Երթուղիչի նույնականացուցիչ"},
{"Router Family", "Երթուղիչի խումբը"},
{"Router Caps", "Երթուղիչի հատկություններ"},
{"Version", "Տարբերակ"},
{"Our external address", "Մեր արտաքին հասցեն"},
{"supported", "համատեղելի է"},
{"Routers", "Երթուղիչներ"},
{"Floodfills", "Floodfills-ներ"},
{"Client Tunnels", "Oգտատիրական թունելներ"},
{"Services", "Ծառայություններ"},
{"Enabled", "Միացված է"},
{"Disabled", "Անջատված է"},
{"Encrypted B33 address", "Գաղտնագրված B33 հասցեներ"},
{"Address registration line", "Հասցեի գրանցման տող"},
{"Domain", "Տիրույթ"},
{"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 գործիքակազմը"},
{"Address", "Հասցե"},
{"Type", "Տեսակը"},
{"EncType", "Գաղտնագրի տեսակը"},
{"Inbound tunnels", "Մուտքային թունելներ"},
{"ms", "մլվ"},
{"Outbound tunnels", "Ելքային թունելներ"},
{"Tags", "Թեգեր"},
{"Incoming", "Մուտքային"},
{"Outgoing", "ելքային"},
{"Destination", "Նշանակման վայր"},
{"Amount", "Քանակ"},
{"Incoming Tags", "Մուտքային պիտակներ"},
{"Tags sessions", "Նստաշրջանի պիտակներ"},
{"Status", "Կարգավիճակ"},
{"Local Destination", "Տեղական նշանակման կետ"},
{"Streams", "Հոսքեր"},
{"Close stream", "Փակել հոսքը"},
{"I2CP session not found", "I2CP նստաշրջանը գոյություն չունի"},
{"I2CP is not enabled", "I2CP միացված է"},
{"Invalid", "Անվավեր"},
{"Store type", "Պահեստավորման տեսակը"},
{"Expires", "Սպառվում է"},
{"Non Expired Leases", "Չսպառված Lease-եր"},
{"Gateway", "Դարպաս"},
{"TunnelID", "Թունելի ID"},
{"EndDate", "Ավարտ"},
{"not floodfill", "ոչ floodfill-ներ"},
{"Queue size", "Հերթի չափսը"},
{"Run peer test", "Գործարկել փորձարկումը"},
{"Decline transit tunnels", "Մերժել տարանցիկ թունելներ"},
{"Accept transit tunnels", "Ընդունել տարանցիկ թունելներ"},
{"Cancel graceful shutdown", "Չեղարկել սահուն անջատումը"},
{"Start graceful shutdown", "Սկսել սահուն անջատումը"},
{"Force shutdown", "Հարկադիր անջատում"},
{"Reload external CSS styles", "Վերաբեռնեք CSS ոճաթերթը"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b> Նշում․ </b> այստեղ կատարված ցանկացած գործողություն մշտական ​​չէ և չի փոխում ձեր կազմաձևման ֆայլերը։"},
{"Logging level", "Գրառման աստիճանը"},
{"Transit tunnels limit", "Տարանցիկ թունելների սահմանափակում"},
{"Change", "Փոփոխել"},
{"Change language", "Փոփոխել լեզուն"},
{"no transit tunnels currently built", "ընթացիկ կառուցված տարանցիկ թունելներ գոյություն չունեն"},
{"SAM disabled", "SAM-ն անջատված է"},
{"no sessions currently running", "ներկայումս գործող նստաշրջաններ գոյություն չունեն"},
{"SAM session not found", "SAM նստաշրջան գոյություն չունի"},
{"SAM Session", "SAM նստաշրջան"},
{"Server Tunnels", "Սերվերային թունելներ"},
{"Client Forwards", "Օգտատիրական փոխանցումներ"},
{"Server Forwards", "Սերվերային փոխանցումներ"},
{"Unknown page", "Անհայտ էջ"},
{"Invalid token", "Սխալ տոկեն"},
{"SUCCESS", "ՀԱՋՈՂՎԱԾ"},
{"Stream closed", "Հոսքն անջատված է"},
{"Stream not found or already was closed", "Հոսքը գոյություն չունի կամ արդեն ավարտված է"},
{"Destination not found", "Հասցեի վայրը չի գտնվել"},
{"StreamID can't be null", "StreamID-ն չի կարող լինել դատարկ"},
{"Return to destination page", "Վերադառնալ նախորդ էջի հասցե"},
{"You will be redirected in 5 seconds", "Դուք կտեղափոխվեք 5 վայրկյանից"},
{"Transit tunnels count must not exceed 65535", "Տարանցիկ թունելների քանակը չպետք է գերազանցի 65535-ը"},
{"Back to commands list", "Վերադառնալ հրահանգների ցուցակ"},
{"Register at reg.i2p", "Գրանցել reg.i2p-ում"},
{"Description", "Նկարագրություն"},
{"A bit information about service on domain", "Մի փոքր տեղեկատվություն տիրոիյթում գտնվող ծառայության մասին"},
{"Submit", "Ուղարկվել"},
{"Domain can't end with .b32.i2p", "Տիրույթը չպետք է վերջանա .b32.i2p-ով"},
{"Domain must end with .i2p", "Տիրույթը պետք է վերջանա .i2p-ով"},
{"Such destination is not found", "Այդիպսի հասցե գոյություն չունի"},
{"Unknown command", "Անհայտ հրահանգ"},
{"Command accepted", "Հրարահանգն ընդունված է"},
{"Proxy error", "Պրոկսի սխալ"},
{"Proxy info", "Պրոկսի տեղեկություն"},
{"Proxy error: Host not found", "Պրոկսի սխալ՝ նման հոսթ գոյություն չունի"},
{"Remote host not found in router's addressbook", "Դեպի հոսթ կատարված հարցումը գոյություն չունի երթուղիչի հասցեագրքում"},
{"You may try to find this host on jump services below", "Ստորև Դուք կարող եք գտնել այս հոսթը jump ծառայությունների միջոցով"},
{"Invalid request", "Սխալ հարցում"},
{"Proxy unable to parse your request", "Պրոկսին չի կարող հասկանալ Ձեր հարցումը"},
{"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", "Չհաջողվեց հայնտաբերեկ վայրի հասցեն նշված հարցմամբ"},
{"Outproxy failure", "Սխալ արտաքին պրոքսի"},
{"bad outproxy settings", "Սխալ արտաքին պրոկսի կարգավորումներ"},
{"not inside I2P network, but outproxy is not enabled", "Հարցումը I2P ցանցից դուրս է, բայց արտաքին պրոքսին միացված չէ"},
{"unknown outproxy url", "արտաքին պրոքսիի անհայտ URL"},
{"cannot resolve upstream proxy", "Չհաջողվեց որոշել վերադաս պրոկսին"},
{"hostname too long", "Հոսթի անունը չափազանց երկար է"},
{"cannot connect to upstream socks proxy", "չհաջողվեց միանալ վերադաս socks պրոկսիին"},
{"Cannot negotiate with socks proxy", "Չհաջողվեց պայմանավորվել վերադաս socks պրոկսիի հետ"},
{"CONNECT error", "Սխալ CONNECT հարցում"},
{"Failed to Connect", "Միանալ չhաջողվեց"},
{"socks proxy error", "Սխալ SOCKS պրոկսի"},
{"failed to send request to upstream", "Չհաջողվեց հարցումն ուղարկել վերադաս պրոկսիին"},
{"No Reply From socks proxy", "Բացակայում է պատասխանը SOCKS պրոկսի սերվերի կողմից"},
{"cannot connect", "Հնարավոր չե միանալ"},
{"http out proxy not implemented", "Արտաքին http պրոկսին դեռ իրականացված չէ"},
{"cannot connect to upstream http proxy", "Չհաջողվեց միանալ վերադաս http պրոկսի սերվերին"},
{"Host is down", "Հոսթն անհասանելի է"},
{"Can't create connection to requested host, it may be down. Please try again later.", "Հոսթի հետ կապը հաստատել չհաջողվեց, հնարավոր է այն անջատված է, փորձեք միանալ քիչ ուշ"},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
{"days", {"օր", "օր"}},
{"hours", {"ժամ", "ժամ"}},
{"minutes", {"րոպե", "րոպե"}},
{"seconds", {"վարկյան", "վարկյան"}},
{"", {"", ""}},
};
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

102
i18n/French.cpp Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2022, 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"
// French localization file
namespace i2p
{
namespace i18n
{
namespace french // language namespace
{
// language name in lowercase
static std::string language = "french";
// 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
{
{"KiB", "Kio"},
{"MiB", "Mio"},
{"GiB", "Gio"},
{"building", "En construction"},
{"failed", "echoué"},
{"expiring", "expiré"},
{"established", "établi"},
{"unknown", "inconnu"},
{"exploratory", "exploratoire"},
{"<b>i2pd</b> webconsole", "Console web <b>i2pd</b>"},
{"Main page", "Page principale"},
{"Router commands", "Commandes du routeur"},
{"Local Destinations", "Destinations locales"},
{"Tunnels", "Tunnels"},
{"Transit Tunnels", "Tunnels transitoires"},
{"I2P tunnels", "Tunnels I2P"},
{"SAM sessions", "Sessions SAM"},
{"ERROR", "ERREUR"},
{"OK", "OK"},
{"Firewalled", "Derrière un pare-feu"},
{"Error", "Erreur"},
{"Offline", "Hors ligne"},
{"Uptime", "Temps de fonctionnement"},
{"Network status", "État du réseau"},
{"Network status v6", "État du réseau v6"},
{"Stopping in", "Arrêt dans"},
{"Family", "Famille"},
{"Tunnel creation success rate", "Taux de succès de création de tunnels"},
{"Received", "Reçu"},
{"KiB/s", "kio/s"},
{"Sent", "Envoyé"},
{"Transit", "Transit"},
{"Hidden content. Press on text to see.", "Contenu caché. Cliquez sur le texte pour regarder."},
{"Router Ident", "Identifiant du routeur"},
{"Router Family", "Famille du routeur"},
{"Version", "Version"},
{"Our external address", "Notre adresse externe"},
{"Client Tunnels", "Tunnels clients"},
{"Services", "Services"},
{"Enabled", "Activé"},
{"Disabled", "Désactivé"},
{"Encrypted B33 address", "Adresse B33 chiffrée"},
{"Domain", "Domaine"},
{"<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"},
{"ms", "ms"},
{"Outbound tunnels", "Tunnels sortants"},
{"Destination", "Destination"},
{"Local Destination", "Destination locale"},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
{"days", {"jour", "jours"}},
{"hours", {"heure", "heures"}},
{"minutes", {"minute", "minutes"}},
{"seconds", {"seconde", "secondes"}},
{"", {"", ""}},
};
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

215
i18n/German.cpp Normal file
View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2022, 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"
// German localization file
namespace i2p
{
namespace i18n
{
namespace german // language namespace
{
// language name in lowercase
static std::string language = "german";
// 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
{
{"KiB", "KiB"},
{"MiB", "MiB"},
{"GiB", "GiB"},
{"building", "In Bau"},
{"failed", "fehlgeschlagen"},
{"expiring", "läuft ab in"},
{"established", "hergestellt"},
{"unknown", "Unbekannt"},
{"exploratory", "erforschende"},
{"<b>i2pd</b> webconsole", "<b>i2pd</b> Webkonsole"},
{"Main page", "Startseite"},
{"Router commands", "Router Befehle"},
{"Local Destinations", "Lokale Destination"},
{"LeaseSets", "LeaseSets"},
{"Tunnels", "Tunnel"},
{"Transit Tunnels", "Transittunnel"},
{"Transports", "Transporte"},
{"I2P tunnels", "I2P Tunnel"},
{"SAM sessions", "SAM Sitzungen"},
{"ERROR", "FEHLER"},
{"OK", "OK"},
{"Testing", "Testen"},
{"Firewalled", "Hinter eine Firewall"},
{"Unknown", "Unbekannt"},
{"Proxy", "Proxy"},
{"Mesh", "Mesh"},
{"Error", "Fehler"},
{"Clock skew", "Zeitabweichung"},
{"Offline", "Offline"},
{"Symmetric NAT", "Symmetrisches NAT"},
{"Uptime", "Laufzeit"},
{"Network status", "Netzwerkstatus"},
{"Network status v6", "Netzwerkstatus v6"},
{"Stopping in", "Stoppt in"},
{"Family", "Familie"},
{"Tunnel creation success rate", "Erfolgsrate der Tunnelerstellung"},
{"Received", "Eingegangen"},
{"KiB/s", "KiB/s"},
{"Sent", "Gesendet"},
{"Transit", "Transit"},
{"Data path", "Datenpfad"},
{"Hidden content. Press on text to see.", "Versteckter Inhalt. Klicke hier, um ihn zu sehen."},
{"Router Ident", "Routeridentität"},
{"Router Family", "Routerfamilie"},
{"Router Caps", "Routerattribute"},
{"Version", "Version"},
{"Our external address", "Unsere externe Adresse"},
{"supported", "unterstützt"},
{"Routers", "Router"},
{"Floodfills", "Floodfills"},
{"Client Tunnels", "Klienttunnel"},
{"Services", "Services"},
{"Enabled", "Aktiviert"},
{"Disabled", "Deaktiviert"},
{"Encrypted B33 address", "Verschlüsselte B33 Adresse"},
{"Address registration line", "Adresseregistrierungszeile"},
{"Domain", "Domain"},
{"Generate", "Generieren"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Hinweis:</b> Der resultierende String kann nur für die Registrierung einer 2LD Domain (beispiel.i2p) benutzt werden. Für die Registrierung von Subdomains kann i2pd-tools verwendet werden."},
{"Address", "Adresse"},
{"Type", "Typ"},
{"EncType", "Verschlüsselungstyp"},
{"Inbound tunnels", "Eingehende Tunnel"},
{"ms", "ms"},
{"Outbound tunnels", "Ausgehende Tunnel"},
{"Tags", "Tags"},
{"Incoming", "Eingehend"},
{"Outgoing", "Ausgehend"},
{"Destination", "Destination"},
{"Amount", "Anzahl"},
{"Incoming Tags", "Eingehende Tags"},
{"Tags sessions", "Tags Sitzungen"},
{"Status", "Status"},
{"Local Destination", "Lokale Destination"},
{"Streams", "Streams"},
{"Close stream", "Stream schließen"},
{"I2CP session not found", "I2CP Sitzung nicht gefunden"},
{"I2CP is not enabled", "I2CP ist nicht aktiviert"},
{"Invalid", "Ungültig"},
{"Store type", "Speichertyp"},
{"Expires", "Ablaufdatum"},
{"Non Expired Leases", "Nicht abgelaufene Leases"},
{"Gateway", "Gateway"},
{"TunnelID", "TunnelID"},
{"EndDate", "Enddatum"},
{"not floodfill", "kein Floodfill"},
{"Queue size", "Warteschlangengröße"},
{"Run peer test", "Peer-Test ausführen"},
{"Decline transit tunnels", "Transittunnel ablehnen"},
{"Accept transit tunnels", "Transittunnel akzeptieren"},
{"Cancel graceful shutdown", "Beende das kontrollierte herunterfahren"},
{"Start graceful shutdown", "Starte das kontrollierte Herunterfahren"},
{"Force shutdown", "Herunterfahren erzwingen"},
{"Reload external CSS styles", "Lade externe CSS-Styles neu"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Hinweis:</b> Alle hier durchgeführten Aktionen sind nicht dauerhaft und ändern die Konfigurationsdateien nicht."},
{"Logging level", "Protokollierungslevel"},
{"Transit tunnels limit", "Limit für Transittunnel"},
{"Change", "Verändern"},
{"Change language", "Sprache ändern"},
{"no transit tunnels currently built", "derzeit keine Transittunnel aufgebaut"},
{"SAM disabled", "SAM deaktiviert"},
{"no sessions currently running", "Derzeit keine laufenden Sitzungen"},
{"SAM session not found", "SAM Sitzung nicht gefunden"},
{"SAM Session", "SAM Sitzung"},
{"Server Tunnels", "Servertunnel"},
{"Client Forwards", "Klient-Weiterleitungen"},
{"Server Forwards", "Server-Weiterleitungen"},
{"Unknown page", "Unbekannte Seite"},
{"Invalid token", "Ungültiger Token"},
{"SUCCESS", "ERFOLGREICH"},
{"Stream closed", "Stream geschlossen"},
{"Stream not found or already was closed", "Stream nicht gefunden oder bereits geschlossen"},
{"Destination not found", "Destination nicht gefunden"},
{"StreamID can't be null", "StreamID kann nicht null sein"},
{"Return to destination page", "Zurück zur Destination-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 Kommandoliste"},
{"Register at reg.i2p", "Auf reg.i2p registrieren"},
{"Description", "Beschreibung"},
{"A bit information about service on domain", "Ein bisschen Informationen über den Service auf der Domain"},
{"Submit", "Einreichen"},
{"Domain can't end with .b32.i2p", "Domain kann nicht mit .b32.i2p enden"},
{"Domain must end with .i2p", "Domain muss mit .i2p enden"},
{"Such destination is not found", "Eine solche Destination konnte nicht gefunden werden"},
{"Unknown command", "Unbekannter Befehl"},
{"Command accepted", "Befehl akzeptiert"},
{"Proxy error", "Proxy-Fehler"},
{"Proxy info", "Proxy-Info"},
{"Proxy error: Host not found", "Proxy-Fehler: Host nicht gefunden"},
{"Remote host not found in router's addressbook", "Remote-Host nicht im Router Adressbuch gefunden"},
{"You may try to find this host on jump services below", "Vielleicht kannst du diesen Host auf einen der Jump-Services unten finden"},
{"Invalid request", "Ungültige Anfrage"},
{"Proxy unable to parse your request", "Proxy konnte die Anfrage nicht interpretieren"},
{"addresshelper is not supported", "addresshelper 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 Anhand der Anfrage den Destination-Host nicht erkennen"},
{"Outproxy failure", "Outproxy-Fehler"},
{"bad outproxy settings", "ungültige Outproxy-Einstellungen"},
{"not inside I2P network, but outproxy is not enabled", "nicht innerhalb des I2P-Netzwerks, aber Outproxy ist nicht aktiviert"},
{"unknown outproxy url", "unbekannte Outproxy-URL"},
{"cannot resolve upstream proxy", "kann den Upstream-Proxy nicht auflösen"},
{"hostname too long", "Hostname zu lang"},
{"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"},
{"CONNECT error", "CONNECT-Fehler"},
{"Failed to Connect", "Verbindung konnte nicht hergestellt werden"},
{"socks proxy error", "Socks-Proxy-Fehler"},
{"failed to send request to upstream", "Anfrage an den Upstream zu senden ist gescheitert"},
{"No Reply From socks proxy", "Keine Antwort vom Socks-Proxy"},
{"cannot connect", "kann nicht verbinden"},
{"http out proxy not implemented", "HTTP-Outproxy nicht implementiert"},
{"cannot connect to upstream http proxy", "Kann nicht zu Upstream-HTTP-Proxy verbinden"},
{"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 aufbaunen, vielleicht ist es offline. Versuche es später noch einmal."},
{"", ""},
};
static std::map<std::string, std::vector<std::string>> plurals
{
{"days", {"Tag", "Tage"}},
{"hours", {"Stunde", "Stunden"}},
{"minutes", {"Minute", "Minuten"}},
{"seconds", {"Sekunde", "Sekunden"}},
{"", {"", ""}},
};
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, 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
* *

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, 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
* *
@ -72,19 +72,25 @@ 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 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 german { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace russian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace turkmen { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace ukrainian { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); } namespace uzbek { std::shared_ptr<const i2p::i18n::Locale> GetLocale (); }
/** /**
* That map contains international language name lower-case and name in it's language * That map contains international language name lower-case, name in it's language and it's code
*/ */
static std::map<std::string, langData> languages static std::map<std::string, langData> languages
{ {
{ "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} }, { "afrikaans", {"Afrikaans", "af", i2p::i18n::afrikaans::GetLocale} },
{ "armenian", {"հայերէն", "hy", i2p::i18n::armenian::GetLocale} },
{ "english", {"English", "en", i2p::i18n::english::GetLocale} }, { "english", {"English", "en", i2p::i18n::english::GetLocale} },
{ "french", {"Français", "fr", i2p::i18n::french::GetLocale} },
{ "german", {"Deutsch", "de", i2p::i18n::german::GetLocale} },
{ "russian", {"русский язык", "ru", i2p::i18n::russian::GetLocale} }, { "russian", {"русский язык", "ru", i2p::i18n::russian::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} },

View File

@ -26,7 +26,7 @@ namespace russian // language namespace
// See for language plural forms here: // See for language plural forms here:
// https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html // https://localization-guide.readthedocs.io/en/latest/l10n/pluralforms.html
static int plural (int n) { static int plural (int n) {
return n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; return n % 10 == 1 && n % 100 != 11 ? 0 : n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2;
} }
static std::map<std::string, std::string> strings static std::map<std::string, std::string> strings

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, 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
* *
@ -198,7 +198,6 @@ namespace turkmen // language namespace
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
// ShowUptime
{"days", {"gün", "gün"}}, {"days", {"gün", "gün"}},
{"hours", {"sagat", "sagat"}}, {"hours", {"sagat", "sagat"}},
{"minutes", {"minut", "minut"}}, {"minutes", {"minut", "minut"}},

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2021, 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
* *
@ -34,20 +34,21 @@ namespace uzbek // language namespace
{"KiB", "KiB"}, {"KiB", "KiB"},
{"MiB", "MiB"}, {"MiB", "MiB"},
{"GiB", "GiB"}, {"GiB", "GiB"},
{"building", "qurilish"}, {"building", "yaratilmoqda"},
{"failed", "muvaffaqiyatsiz"}, {"failed", "muvaffaqiyatsiz"},
{"expiring", "muddati tugaydi"}, {"expiring", "muddati tugaydi"},
{"established", "aloqa o'rnatildi"}, {"established", "aloqa o'rnatildi"},
{"unknown", "noma'lum"}, {"unknown", "noma'lum"},
{"exploratory", "tadqiqiy"}, {"exploratory", "tadqiqiy"},
{"<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"},
{"Local Destinations", "Mahalliy joylanishlar"},
{"LeaseSets", "LeaseSets"}, {"LeaseSets", "LeaseSets"},
{"Tunnels", "Tunnellar"}, {"Tunnels", "Tunnellar"},
{"Transit Tunnels", "Tranzit Tunellar"}, {"Transit Tunnels", "Tranzit Tunellari"},
{"Transports", "Transportlar"}, {"Transports", "Transportlar"},
{"I2P tunnels", "I2P tunnellar"}, {"I2P tunnels", "I2P tunnellari"},
{"SAM sessions", "SAM sessiyalari"}, {"SAM sessions", "SAM sessiyalari"},
{"ERROR", "XATO"}, {"ERROR", "XATO"},
{"OK", "OK"}, {"OK", "OK"},
@ -70,25 +71,25 @@ namespace uzbek // language namespace
{"KiB/s", "KiB/s"}, {"KiB/s", "KiB/s"},
{"Sent", "Yuborilgan"}, {"Sent", "Yuborilgan"},
{"Transit", "Tranzit"}, {"Transit", "Tranzit"},
{"Data path", "Ma'lumotlar yo'li"}, {"Data path", "Ma'lumotlar joylanishi"},
{"Hidden content. Press on text to see.", "Yashirin tarkib. Ko'rish uchun matn ustida bosing."}, {"Hidden content. Press on text to see.", "Yashirin tarkib. Ko'rish uchun matn ustida bosing."},
{"Router Ident", "Router identifikatori"}, {"Router Ident", "Router identifikatori"},
{"Router Family", "Router Oila"}, {"Router Family", "Router oilasi"},
{"Router Caps", "Router bayroqlari"}, {"Router Caps", "Router Bayroqlari"},
{"Version", "Versiya"}, {"Version", "Versiya"},
{"Our external address", "Bizning tashqi manzilimiz"}, {"Our external address", "Bizning tashqi manzilimiz"},
{"supported", "qo'llab -quvvatlanadi"}, {"supported", "qo'llab-quvvatlanadi"},
{"Routers", "Routerlar"}, {"Routers", "Routerlar"},
{"Floodfills", "Floodfills"}, {"Floodfills", "Floodfills"},
{"Client Tunnels", "Mijoz tunellari"}, {"Client Tunnels", "Mijoz Tunellari"},
{"Services", "Xizmatlar"}, {"Services", "Xizmatlar"},
{"Enabled", "Yoqilgan"}, {"Enabled", "Yoqilgan"},
{"Disabled", "O'chirilgan"}, {"Disabled", "O'chirilgan"},
{"Encrypted B33 address", "Shifrlangan B33 manzil"}, {"Encrypted B33 address", "Shifrlangan B33 manzil"},
{"Address registration line", "Manzilni ro'yxatga olish liniyasi"}, {"Address registration line", "Manzilni ro'yxatga olish liniyasi"},
{"Domain", "Domen"}, {"Domain", "Domen"},
{"Generate", "Varatish"}, {"Generate", "Yaratish"},
{"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Eslatma:</b> natija satridan faqat 2LD domenlarini ro'yxatdan o'tkazish uchun foydalanish mumkin (example.i2p). Subdomenlarni ro'yxatdan o'tkazish uchun i2pd-tools dan foydalaning."}, {"<b>Note:</b> result string can be used only for registering 2LD domains (example.i2p). For registering subdomains please use i2pd-tools.", "<b>Eslatma:</b> natija satridan faqat 2LD domenlarini ro'yxatdan o'tkazish uchun foydalanish mumkin (example.i2p). Subdomenlarni ro'yxatdan o'tkazish uchun 'i2pd-tools'dan foydalaning."},
{"Address", "Manzil"}, {"Address", "Manzil"},
{"Type", "Turi"}, {"Type", "Turi"},
{"EncType", "ShifrlashTuri"}, {"EncType", "ShifrlashTuri"},
@ -99,10 +100,11 @@ namespace uzbek // language namespace
{"Incoming", "Kiruvchi"}, {"Incoming", "Kiruvchi"},
{"Outgoing", "Chiquvchi"}, {"Outgoing", "Chiquvchi"},
{"Destination", "Manzilgoh"}, {"Destination", "Manzilgoh"},
{"Amount", "Yig'indi"}, {"Amount", "Soni"},
{"Incoming Tags", "Kiruvchi teglar"}, {"Incoming Tags", "Kiruvchi teglar"},
{"Tags sessions", "Teglar sessiyalari"}, {"Tags sessions", "Teglar sessiyalari"},
{"Status", "Holat"}, {"Status", "Holat"},
{"Local Destination", "Mahalliy joylanish"},
{"Streams", "Strim"}, {"Streams", "Strim"},
{"Close stream", "Strimni o'chirish"}, {"Close stream", "Strimni o'chirish"},
{"I2CP session not found", "I2CP sessiyasi topilmadi"}, {"I2CP session not found", "I2CP sessiyasi topilmadi"},
@ -117,14 +119,15 @@ namespace uzbek // language namespace
{"not floodfill", "floodfill emas"}, {"not floodfill", "floodfill emas"},
{"Queue size", "Navbat hajmi"}, {"Queue size", "Navbat hajmi"},
{"Run peer test", "Sinovni boshlang"}, {"Run peer test", "Sinovni boshlang"},
{"Decline transit tunnels", "Tranzit tunnellarni 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 qiling"}, {"Cancel graceful shutdown", "Yumshoq to'xtashni bekor qilish"},
{"Start graceful shutdown", "Yumshoq to'xtashni boshlang"}, {"Start graceful shutdown", "Yumshoq to'xtashni boshlash"},
{"Force shutdown", "Bizning tashqi manzilimiz"}, {"Force shutdown", "Majburiy to'xtatish"},
{"Reload external CSS styles", "Tashqi CSS uslublarini qayta yuklang"}, {"Reload external CSS styles", "Tashqi CSS uslublarini qayta yuklang"},
{"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Eslatma:</b> bu erda qilingan har qanday harakat doimiy emas va konfiguratsiya fayllarini o'zgartirmaydi."}, {"<b>Note:</b> any action done here are not persistent and not changes your config files.", "<b>Eslatma:</b> shu yerda qilingan har qanday harakat doimiy emas va konfiguratsiya fayllarini o'zgartirmaydi."},
{"Transit tunnels limit", "Tranzit tunellar chegarasi"}, {"Logging level", "Jurnal darajasi"},
{"Transit tunnels limit", "Tranzit tunellarning chegarasi"},
{"Change", "O'zgartirish"}, {"Change", "O'zgartirish"},
{"Change language", "Tilni o'zgartirish"}, {"Change language", "Tilni o'zgartirish"},
{"no transit tunnels currently built", "qurilgan tranzit tunnellari yo'q"}, {"no transit tunnels currently built", "qurilgan tranzit tunnellari yo'q"},
@ -142,8 +145,8 @@ namespace uzbek // language namespace
{"Stream not found or already was closed", "Strim topilmadi yoki allaqachon yopilgan"}, {"Stream not found or already was closed", "Strim topilmadi yoki allaqachon yopilgan"},
{"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", "Belgilangan sahifaga qaytish"}, {"Return to destination page", "Manzilgoh sahifasiga qaytish"},
{"You will be redirected in 5 seconds", "Siz 5 soniyada qayta yo'naltirilasiz"}, {"You will be redirected in 5 seconds", "Siz 5 soniya ichida qayta yo'naltirilasiz"},
{"Transit tunnels count must not exceed 65535", "Tranzit tunnellar soni 65535 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"},
@ -159,29 +162,35 @@ namespace uzbek // language namespace
{"Proxy info", "Proksi ma'lumotlari"}, {"Proxy info", "Proksi ma'lumotlari"},
{"Proxy error: Host not found", "Proksi xatosi: Xost topilmadi"}, {"Proxy error: Host not found", "Proksi xatosi: Xost topilmadi"},
{"Remote host not found in router's addressbook", "Masofaviy xost yo'riqnoma manzillar kitobida topilmadi"}, {"Remote host not found in router's addressbook", "Masofaviy xost yo'riqnoma manzillar kitobida topilmadi"},
{"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 tahlil qila olmaydi"}, {"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", "Xost"}, {"Host", "Xost"},
{"added to router's addressbook from helper", "'helper'dan routerning 'addressbook'ga qo'shildi"},
{"Click here to proceed:", "Davom etish uchun shu yerni bosing:"},
{"Continue", "Davom etish"},
{"Addresshelper found", "Addresshelper topildi"}, {"Addresshelper found", "Addresshelper topildi"},
{"already in router's addressbook", "allaqachon 'addressbook'da yozilgan"},
{"Click here to update record:", "Yozuvni yangilash uchun shu yerni bosing:"},
{"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"},
{"not inside I2P network, but outproxy is not enabled", "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 proksi -serverni aniqlab olib bolmaydi"}, {"cannot resolve upstream proxy", "yuqoridagi 'proxy-server'ni aniqlab olib bolmayapti"},
{"hostname too long", "xost nomi juda uzun"}, {"hostname too long", "xost nomi juda uzun"},
{"cannot connect to upstream socks proxy", "yuqori soks proksi -serveriga ulanib bo'lmaydi"}, {"cannot connect to upstream socks proxy", "yuqori 'socks proxy'ga ulanib bo'lmayapti"},
{"Cannot negotiate with socks proxy", "Soks proksi 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", "Ulanmadi"}, {"Failed to Connect", "Ulanib bo'lmayapti"},
{"socks proxy error", "soks proksi xatosi"}, {"socks proxy error", "'socks proxy' xatosi"},
{"failed to send request to upstream", "yuqori http proksi-serveriga ulanib bo'lmadi"}, {"failed to send request to upstream", "yuqori http proksi-serveriga so'rovni uborib bo'lmadi"},
{"No Reply From socks proxy", "Soks-proksidan javob yo'q"}, {"No Reply From socks proxy", "'Socks proxy'dan javob yo'q"},
{"cannot connect", "ulab 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 proksi-serveriga ulanib bo'lmadi"}, {"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."},
{"", ""}, {"", ""},
@ -189,10 +198,10 @@ namespace uzbek // language namespace
static std::map<std::string, std::vector<std::string>> plurals static std::map<std::string, std::vector<std::string>> plurals
{ {
{"days", {"kun", "kunlar"}}, {"days", {"kun", "kun"}},
{"hours", {"soat", "soat"}}, {"hours", {"soat", "soat"}},
{"minutes", {"daqiqa", "daqiqalar"}}, {"minutes", {"daqiqa", "daqiqa"}},
{"seconds", {"soniya", "soniyalar"}}, {"seconds", {"soniya", "soniya"}},
{"", {"", ""}}, {"", {"", ""}},
}; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, 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
* *
@ -185,10 +185,7 @@ namespace data
if (InCount && !m) if (InCount && !m)
outCount = 3 * n; outCount = 3 * n;
else else
{
outCount = 0;
return 0; return 0;
}
ps = (unsigned char *)(InBuffer + InCount - 1); ps = (unsigned char *)(InBuffer + InCount - 1);
while ( *ps-- == P64 ) while ( *ps-- == P64 )
@ -196,7 +193,7 @@ namespace data
ps = (unsigned char *)InBuffer; ps = (unsigned char *)InBuffer;
if (outCount > len) if (outCount > len)
return -1; return 0;
pd = OutBuffer; pd = OutBuffer;
auto endOfOutBuffer = OutBuffer + outCount; auto endOfOutBuffer = OutBuffer + outCount;

View File

@ -24,8 +24,8 @@ namespace data {
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
/** /**
Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes * Compute the size for a buffer to contain encoded base64 given that the size of the input is input_size bytes
*/ */
size_t Base64EncodingBufferSize(const size_t input_size); size_t Base64EncodingBufferSize(const size_t input_size);
std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization std::string ToBase64Standard (const std::string& in); // using standard table, for Proxy-Authorization

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -99,7 +99,7 @@ namespace data
static size_t BlindECDSA (i2p::data::SigningKeyType sigType, const uint8_t * key, const uint8_t * seed, Fn blind, Args&&...args) static size_t BlindECDSA (i2p::data::SigningKeyType sigType, const uint8_t * key, const uint8_t * seed, Fn blind, Args&&...args)
// blind is BlindEncodedPublicKeyECDSA or BlindEncodedPrivateKeyECDSA // blind is BlindEncodedPublicKeyECDSA or BlindEncodedPrivateKeyECDSA
{ {
size_t publicKeyLength = 0; size_t publicKeyLength = 0;
EC_GROUP * group = nullptr; EC_GROUP * group = nullptr;
switch (sigType) switch (sigType)
{ {
@ -122,7 +122,7 @@ namespace data
break; break;
} }
default: default:
LogPrint (eLogError, "Blinding: signature type ", (int)sigType, " is not ECDSA"); LogPrint (eLogError, "Blinding: Signature type ", (int)sigType, " is not ECDSA");
} }
if (group) if (group)
{ {
@ -146,7 +146,10 @@ namespace data
m_PublicKey.resize (len); m_PublicKey.resize (len);
memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len); memcpy (m_PublicKey.data (), identity->GetSigningPublicKeyBuffer (), len);
m_SigType = identity->GetSigningKeyType (); m_SigType = identity->GetSigningKeyType ();
m_BlindedSigType = m_SigType; if (m_SigType == i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
m_BlindedSigType = i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519; // 7 -> 11
else
m_BlindedSigType = m_SigType;
} }
BlindedPublicKey::BlindedPublicKey (const std::string& b33): BlindedPublicKey::BlindedPublicKey (const std::string& b33):
@ -156,7 +159,7 @@ namespace data
size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40); size_t l = i2p::data::Base32ToByteStream (b33.c_str (), b33.length (), addr, 40);
if (l < 32) if (l < 32)
{ {
LogPrint (eLogError, "Blinding: malformed b33 ", b33); LogPrint (eLogError, "Blinding: Malformed b33 ", b33);
return; return;
} }
uint32_t checksum = crc32 (0, addr + 3, l - 3); uint32_t checksum = crc32 (0, addr + 3, l - 3);
@ -186,10 +189,10 @@ namespace data
memcpy (m_PublicKey.data (), addr + offset, len); memcpy (m_PublicKey.data (), addr + offset, len);
} }
else else
LogPrint (eLogError, "Blinding: public key in b33 address is too short for signature type ", (int)m_SigType); LogPrint (eLogError, "Blinding: Public key in b33 address is too short for signature type ", (int)m_SigType);
} }
else else
LogPrint (eLogError, "Blinding: unknown signature type ", (int)m_SigType, " in b33"); LogPrint (eLogError, "Blinding: Unknown signature type ", (int)m_SigType, " in b33");
} }
std::string BlindedPublicKey::ToB33 () const std::string BlindedPublicKey::ToB33 () const
@ -256,7 +259,7 @@ namespace data
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break; break;
default: default:
LogPrint (eLogError, "Blinding: can't blind signature type ", (int)m_SigType); LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
} }
return publicKeyLength; return publicKeyLength;
} }
@ -272,21 +275,21 @@ namespace data
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA384_P384:
case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521: case i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA512_P521:
publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub); publicKeyLength = BlindECDSA (m_SigType, priv, seed, BlindEncodedPrivateKeyECDSA, blindedPriv, blindedPub);
break; break;
case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_REDDSA_SHA512_ED25519:
i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub); i2p::crypto::GetEd25519 ()->BlindPrivateKey (priv, seed, blindedPriv, blindedPub);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break; break;
case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
{ {
uint8_t exp[64]; uint8_t exp[64];
i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp); i2p::crypto::Ed25519::ExpandPrivateKey (priv, exp);
i2p::crypto::GetEd25519 ()->BlindPrivateKey (exp, seed, blindedPriv, blindedPub); i2p::crypto::GetEd25519 ()->BlindPrivateKey (exp, seed, blindedPriv, blindedPub);
publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH; publicKeyLength = i2p::crypto::EDDSA25519_PUBLIC_KEY_LENGTH;
break; break;
} }
default: default:
LogPrint (eLogError, "Blinding: can't blind signature type ", (int)m_SigType); LogPrint (eLogError, "Blinding: Can't blind signature type ", (int)m_SigType);
} }
return publicKeyLength; return publicKeyLength;
} }
@ -324,7 +327,7 @@ namespace data
SHA256_Final ((uint8_t *)hash, &ctx); SHA256_Final ((uint8_t *)hash, &ctx);
} }
else else
LogPrint (eLogError, "Blinding: blinded key type ", (int)m_BlindedSigType, " is not supported"); LogPrint (eLogError, "Blinding: Blinded key type ", (int)m_BlindedSigType, " is not supported");
return hash; return hash;
} }

View File

@ -28,8 +28,8 @@ namespace data
const uint8_t * GetPublicKey () const { return m_PublicKey.data (); }; const uint8_t * GetPublicKey () const { return m_PublicKey.data (); };
size_t GetPublicKeyLen () const { return m_PublicKey.size (); }; size_t GetPublicKeyLen () const { return m_PublicKey.size (); };
SigningKeyType GetSigType () const { return m_SigType; }; SigningKeyType GetSigType () const { return m_SigType; };
SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; }; SigningKeyType GetBlindedSigType () const { return m_BlindedSigType; };
bool IsValid () const { return GetSigType (); }; // signature type 0 means invalid bool IsValid () const { return GetSigType (); }; // signature type 0 means invalid
void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes void GetSubcredential (const uint8_t * blinded, size_t len, uint8_t * subcredential) const; // 32 bytes

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, 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
* *
@ -61,7 +61,7 @@ namespace config {
("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)") ("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)")
("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)") ("notransit", bool_switch()->default_value(false), "Router will not accept transit tunnels at startup (default: disabled)")
("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)")
("bandwidth", value<std::string>()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("bandwidth", value<std::string>()->default_value(""), "Transit traffic bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)")
("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") ("share", value<int>()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)")
("ntcp", bool_switch()->default_value(false), "Ignored. Always false") ("ntcp", bool_switch()->default_value(false), "Ignored. Always false")
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
@ -78,9 +78,9 @@ namespace config {
("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)") ("limits.coresize", value<uint32_t>()->default_value(0), "Maximum size of corefile in Kb (0 - use system limit)")
("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)") ("limits.openfiles", value<uint16_t>()->default_value(0), "Maximum number of open files (0 - use system default)")
("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)") ("limits.transittunnels", value<uint16_t>()->default_value(2500), "Maximum active transit sessions (default:2500)")
("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Threshold to start probabilistic backoff with ntcp sessions (default: use system limit)") ("limits.ntcpsoft", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcphard", value<uint16_t>()->default_value(0), "Maximum number of ntcp sessions (default: use system limit)") ("limits.ntcphard", value<uint16_t>()->default_value(0), "Ignored")
("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Maximum number of threads used by NTCP DH worker (default: 1)") ("limits.ntcpthreads", value<uint16_t>()->default_value(1), "Ignored")
; ;
options_description httpserver("HTTP Server options"); options_description httpserver("HTTP Server options");
@ -109,6 +109,8 @@ namespace config {
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length") ("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity") ("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity") ("httpproxy.outbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy outbound tunnels quantity")
("httpproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy inbound tunnels length variance")
("httpproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "HTTP proxy outbound tunnels length variance")
("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels") ("httpproxy.latency.min", value<std::string>()->default_value("0"), "HTTP proxy min latency for tunnels")
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels") ("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels")
("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url") ("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url")
@ -130,6 +132,8 @@ namespace config {
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length") ("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity") ("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity") ("socksproxy.outbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy outbound tunnels quantity")
("socksproxy.inbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy inbound tunnels length variance")
("socksproxy.outbound.lengthVariance", value<std::string>()->default_value("0"), "SOCKS proxy outbound tunnels length variance")
("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels") ("socksproxy.latency.min", value<std::string>()->default_value("0"), "SOCKS proxy min latency for tunnels")
("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels") ("socksproxy.latency.max", value<std::string>()->default_value("0"), "SOCKS proxy max latency for tunnels")
("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy") ("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy")
@ -203,28 +207,36 @@ namespace config {
("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from") ("reseed.zipfile", value<std::string>()->default_value(""), "Path to local .zip file to reseed from")
("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks") ("reseed.proxy", value<std::string>()->default_value(""), "url for reseed proxy, supports http/socks")
("reseed.urls", value<std::string>()->default_value( ("reseed.urls", value<std::string>()->default_value(
"https://reseed.i2p-projekt.de/," "https://reseed2.i2p.net/,"
"https://reseed.diva.exchange/," "https://reseed.diva.exchange/,"
"https://reseed-fr.i2pd.xyz/," "https://reseed-fr.i2pd.xyz/,"
"https://reseed.memcpy.io/," "https://reseed.memcpy.io/,"
"https://reseed.onion.im/," "https://reseed.onion.im/,"
"https://i2pseed.creativecowpat.net:8443/," "https://i2pseed.creativecowpat.net:8443/,"
"https://reseed.i2pgit.org/," "https://reseed.i2pgit.org/,"
"https://i2p.novg.net/" "https://i2p.novg.net/,"
"https://banana.incognet.io/,"
"https://reseed-pl.i2pd.xyz/,"
"https://www2.mk16.de/"
), "Reseed URLs, separated by comma") ), "Reseed URLs, separated by comma")
("reseed.yggurls", value<std::string>()->default_value( ("reseed.yggurls", value<std::string>()->default_value(
"http://[324:71e:281a:9ed3::ace]:7070/," "http://[324:71e:281a:9ed3::ace]:7070/,"
"http://[301:65b9:c7cd:9a36::1]:18801/," "http://[301:65b9:c7cd:9a36::1]:18801/,"
"http://[320:8936:ec1a:31f1::216]/" "http://[320:8936:ec1a:31f1::216]/,"
"http://[306:3834:97b9:a00a::1]/,"
"http://[316:f9e0:f22e:a74f::216]/"
), "Reseed URLs through the Yggdrasil, separated by comma") ), "Reseed URLs through the Yggdrasil, separated by comma")
; ;
options_description addressbook("AddressBook options"); options_description addressbook("AddressBook options");
addressbook.add_options() addressbook.add_options()
("addressbook.enabled", value<bool>()->default_value(true), "Enable address book lookups and subscritions (default: enabled)")
("addressbook.defaulturl", value<std::string>()->default_value( ("addressbook.defaulturl", value<std::string>()->default_value(
"http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt" "http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/hosts.txt"
), "AddressBook subscription URL for initial setup") ), "AddressBook subscription URL for initial setup")
("addressbook.subscriptions", value<std::string>()->default_value("http://reg.i2p/hosts.txt"), "AddressBook subscriptions URLs, separated by comma") ("addressbook.subscriptions", value<std::string>()->default_value(
"http://reg.i2p/hosts.txt"
), "AddressBook subscriptions URLs, separated by comma")
("addressbook.hostsfile", value<std::string>()->default_value(""), "File to dump addresses in hosts.txt format"); ("addressbook.hostsfile", value<std::string>()->default_value(""), "File to dump addresses in hosts.txt format");
options_description trust("Trust options"); options_description trust("Trust options");
@ -260,6 +272,13 @@ namespace config {
("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport") ("ntcp2.proxy", value<std::string>()->default_value(""), "Proxy URL for NTCP2 transport")
; ;
options_description ssu2("SSU2 Options");
ssu2.add_options()
("ssu2.enabled", value<bool>()->default_value(false), "Enable SSU2 (default: disabled)")
("ssu2.published", value<bool>()->default_value(false), "Publish SSU2 (default: disabled)")
("ssu2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming SSU2 packets (default: auto)")
;
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), "Disable time sync (default: disabled)") ("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)")
@ -268,8 +287,9 @@ namespace config {
"1.pool.ntp.org," "1.pool.ntp.org,"
"2.pool.ntp.org," "2.pool.ntp.org,"
"3.pool.ntp.org" "3.pool.ntp.org"
), "Comma separated list of NTCP servers") ), "Comma separated list of NTP servers")
("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)") ("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)")
("nettime.frompeers", value<bool>()->default_value(true), "Sync clock from transport peers (default: enabled)")
; ;
options_description persist("Network information persisting options"); options_description persist("Network information persisting options");
@ -291,6 +311,13 @@ namespace config {
("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish") ("meshnets.yggaddress", value<std::string>()->default_value(""), "Yggdrasil address to publish")
; ;
#ifdef __linux__
options_description unix_specific("UNIX-specific options");
unix_specific.add_options()
("unix.handle_sigtstp", bool_switch()->default_value(false), "Handle SIGTSTP and SIGCONT signals (default: disabled)")
;
#endif
m_OptionsDesc m_OptionsDesc
.add(general) .add(general)
.add(limits) .add(limits)
@ -309,10 +336,14 @@ namespace config {
.add(websocket) // deprecated .add(websocket) // deprecated
.add(exploratory) .add(exploratory)
.add(ntcp2) .add(ntcp2)
.add(ssu2)
.add(nettime) .add(nettime)
.add(persist) .add(persist)
.add(cpuext) .add(cpuext)
.add(meshnets) .add(meshnets)
#ifdef __linux__
.add(unix_specific)
#endif
; ;
} }

View File

@ -29,16 +29,16 @@ namespace config {
extern boost::program_options::variables_map m_Options; extern boost::program_options::variables_map m_Options;
/** /**
* @brief Initialize list of acceptable parameters * @brief Initialize list of acceptable parameters
* *
* Should be called before any Parse* functions. * Should be called before any Parse* functions.
*/ */
void Init(); void Init();
/** /**
* @brief Parse cmdline parameters, and show help if requested * @brief Parse cmdline parameters, and show help if requested
* @param argc Cmdline arguments count, should be passed from main(). * @param argc Cmdline arguments count, should be passed from main().
* @param argv Cmdline parameters array, should be passed from main() * @param argv Cmdline parameters array, should be passed from main()
* *
* If --help is given in parameters, shows its list with description * If --help is given in parameters, shows its list with description
* and terminates the program with exitcode 0. * and terminates the program with exitcode 0.
@ -52,8 +52,8 @@ namespace config {
void ParseCmdline(int argc, char* argv[], bool ignoreUnknown = false); void ParseCmdline(int argc, char* argv[], bool ignoreUnknown = false);
/** /**
* @brief Load and parse given config file * @brief Load and parse given config file
* @param path Path to config file * @param path Path to config file
* *
* If error occurred when opening file path is points to, * If error occurred when opening file path is points to,
* we show the error message and terminate program. * we show the error message and terminate program.
@ -67,14 +67,14 @@ namespace config {
void ParseConfig(const std::string& path); void ParseConfig(const std::string& path);
/** /**
* @brief Used to combine options from cmdline, config and default values * @brief Used to combine options from cmdline, config and default values
*/ */
void Finalize(); void Finalize();
/** /**
* @brief Accessor to parameters by name * @brief Accessor to parameters by name
* @param name Name of the requested parameter * @param name Name of the requested parameter
* @param value Variable where to store option * @param value Variable where to store option
* @return this function returns false if parameter not found * @return this function returns false if parameter not found
* *
* Example: uint16_t port; GetOption("sam.port", port); * Example: uint16_t port; GetOption("sam.port", port);
@ -98,9 +98,9 @@ namespace config {
bool GetOptionAsAny(const std::string& name, boost::any& value); bool GetOptionAsAny(const std::string& name, boost::any& value);
/** /**
* @brief Set value of given parameter * @brief Set value of given parameter
* @param name Name of settable parameter * @param name Name of settable parameter
* @param value New parameter value * @param value New parameter value
* @return true if value set up successful, false otherwise * @return true if value set up successful, false otherwise
* *
* Example: uint16_t port = 2827; SetOption("bob.port", port); * Example: uint16_t port = 2827; SetOption("bob.port", port);
@ -116,8 +116,8 @@ namespace config {
} }
/** /**
* @brief Check is value explicitly given or default * @brief Check is value explicitly given or default
* @param name Name of checked parameter * @param name Name of checked parameter
* @return true if value set to default, false otherwise * @return true if value set to default, false otherwise
*/ */
bool IsDefault(const char *name); bool IsDefault(const char *name);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -389,7 +389,7 @@ namespace crypto
{ {
size_t len = 32; size_t len = 32;
EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len); EVP_PKEY_get_raw_public_key (m_Pkey, m_PublicKey, &len);
} }
#else #else
memcpy (m_PrivateKey, priv, 32); memcpy (m_PrivateKey, priv, 32);
if (calculatePublic) if (calculatePublic)
@ -440,7 +440,7 @@ namespace crypto
bn2buf (a, encrypted + 1, 256); bn2buf (a, encrypted + 1, 256);
encrypted[257] = 0; encrypted[257] = 0;
bn2buf (b, encrypted + 258, 256); bn2buf (b, encrypted + 258, 256);
BN_free (a); BN_free (a);
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
@ -1277,7 +1277,7 @@ namespace crypto
EVP_PKEY_CTX_set1_hkdf_key (pctx, tempKey, len); EVP_PKEY_CTX_set1_hkdf_key (pctx, tempKey, len);
} }
if (info.length () > 0) if (info.length () > 0)
EVP_PKEY_CTX_add1_hkdf_info (pctx, info.c_str (), info.length ()); EVP_PKEY_CTX_add1_hkdf_info (pctx, (const uint8_t *)info.c_str (), info.length ());
EVP_PKEY_derive (pctx, out, &outLen); EVP_PKEY_derive (pctx, out, &outLen);
EVP_PKEY_CTX_free (pctx); EVP_PKEY_CTX_free (pctx);
#else #else
@ -1295,7 +1295,7 @@ namespace crypto
} }
// Noise // Noise
void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len) void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len)
{ {
SHA256_CTX ctx; SHA256_CTX ctx;
@ -1305,13 +1305,23 @@ namespace crypto
SHA256_Final (m_H, &ctx); SHA256_Final (m_H, &ctx);
} }
void NoiseSymmetricState::MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs)
{
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
for (const auto& it: bufs)
SHA256_Update (&ctx, it.first, it.second);
SHA256_Final (m_H, &ctx);
}
void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret) void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret)
{ {
HKDF (m_CK, sharedSecret, 32, "", m_CK); HKDF (m_CK, sharedSecret, 32, "", m_CK);
// new ck is m_CK[0:31], key is m_CK[32:63] // new ck is m_CK[0:31], key is m_CK[32:63]
} }
static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck, static void InitNoiseState (NoiseSymmetricState& state, const uint8_t * ck,
const uint8_t * hh, const uint8_t * pub) const uint8_t * hh, const uint8_t * pub)
{ {
// pub is Bob's public static key, hh = SHA256(h) // pub is Bob's public static key, hh = SHA256(h)
@ -1320,23 +1330,23 @@ namespace crypto
SHA256_Init (&ctx); SHA256_Init (&ctx);
SHA256_Update (&ctx, hh, 32); SHA256_Update (&ctx, hh, 32);
SHA256_Update (&ctx, pub, 32); SHA256_Update (&ctx, pub, 32);
SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub) SHA256_Final (state.m_H, &ctx); // h = MixHash(pub) = SHA256(hh || pub)
} }
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub)
{ {
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
static const uint8_t hh[32] = static const uint8_t hh[32] =
{ {
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1,
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54
}; // hh = SHA256(protocol_name || 0) }; // hh = SHA256(protocol_name || 0)
InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0 InitNoiseState (state, (const uint8_t *)protocolName, hh, pub); // ck = protocol_name || 0
} }
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub)
{ {
static const uint8_t protocolNameHash[] = static const uint8_t protocolNameHash[32] =
{ {
0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed, 0x72, 0xe8, 0x42, 0xc5, 0x45, 0xe1, 0x80, 0x80, 0xd3, 0x9c, 0x44, 0x93, 0xbb, 0x91, 0xd7, 0xed,
0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71 0xf2, 0x28, 0x98, 0x17, 0x71, 0x21, 0x8c, 0x1f, 0x62, 0x4e, 0x20, 0x6f, 0x28, 0xd3, 0x2f, 0x71
@ -1346,8 +1356,23 @@ namespace crypto
0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5, 0x49, 0xff, 0x48, 0x3f, 0xc4, 0x04, 0xb9, 0xb2, 0x6b, 0x11, 0x94, 0x36, 0x72, 0xff, 0x05, 0xb5,
0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e 0x61, 0x27, 0x03, 0x31, 0xba, 0x89, 0xb8, 0xfc, 0x33, 0x15, 0x93, 0x87, 0x57, 0xdd, 0x3d, 0x1e
}; // SHA256 (protocolNameHash) }; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub); InitNoiseState (state, protocolNameHash, hh, pub);
} }
void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub)
{
static const uint8_t protocolNameHash[32] =
{
0xb1, 0x37, 0x22, 0x81, 0x74, 0x23, 0xa8, 0xfd, 0xf4, 0x2d, 0xf2, 0xe6, 0x0e, 0xd1, 0xed, 0xf4,
0x1b, 0x93, 0x07, 0x1d, 0xb1, 0xec, 0x24, 0xa3, 0x67, 0xf7, 0x84, 0xec, 0x27, 0x0d, 0x81, 0x32
}; // SHA256 ("Noise_XKchaobfse+hs1+hs2+hs3_25519_ChaChaPoly_SHA256")
static const uint8_t hh[32] =
{
0xdc, 0x85, 0xe6, 0xaf, 0x7b, 0x02, 0x65, 0x0c, 0xf1, 0xf9, 0x0d, 0x71, 0xfb, 0xc6, 0xd4, 0x53,
0xa7, 0xcf, 0x6d, 0xbf, 0xbd, 0x52, 0x5e, 0xa5, 0xb5, 0x79, 0x1c, 0x47, 0xb3, 0x5e, 0xbc, 0x33
}; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub);
}
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub)
{ {
@ -1361,9 +1386,9 @@ namespace crypto
0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32, 0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32,
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c 0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c
}; // SHA256 (protocolNameHash) }; // SHA256 (protocolNameHash)
InitNoiseState (state, protocolNameHash, hh, pub); InitNoiseState (state, protocolNameHash, hh, pub);
} }
// init and terminate // init and terminate
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes; /* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -29,21 +29,25 @@
#include "CPU.h" #include "CPU.h"
// recognize openssl version and features // recognize openssl version and features
#if ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL #if (defined(LIBRESSL_VERSION_NUMBER) && (LIBRESSL_VERSION_NUMBER >= 0x3050200fL)) // LibreSSL 3.5.2 and above
# define LEGACY_OPENSSL 1 # define LEGACY_OPENSSL 0
# define X509_getm_notBefore X509_get_notBefore #elif ((OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER)) // 1.0.2 and below or LibreSSL
# define X509_getm_notAfter X509_get_notAfter # define LEGACY_OPENSSL 1
# define X509_getm_notBefore X509_get_notBefore
# define X509_getm_notAfter X509_get_notAfter
#else #else
# define LEGACY_OPENSSL 0 # define LEGACY_OPENSSL 0
# if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1 # if (OPENSSL_VERSION_NUMBER >= 0x010101000) // 1.1.1
# define OPENSSL_HKDF 1 # define OPENSSL_HKDF 1
# define OPENSSL_EDDSA 1 # define OPENSSL_EDDSA 1
# define OPENSSL_X25519 1 # define OPENSSL_X25519 1
# define OPENSSL_SIPHASH 1 # if (OPENSSL_VERSION_NUMBER != 0x030000000) // 3.0.0, regression in SipHash
# endif # define OPENSSL_SIPHASH 1
# if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them # endif
# define OPENSSL_AEAD_CHACHA20_POLY1305 1 # endif
# endif # if !defined OPENSSL_NO_CHACHA && !defined OPENSSL_NO_POLY1305 // some builds might not include them
# define OPENSSL_AEAD_CHACHA20_POLY1305 1
# endif
#endif #endif
namespace i2p namespace i2p
@ -93,7 +97,7 @@ namespace crypto
bool IsElligatorIneligible () const { return m_IsElligatorIneligible; } bool IsElligatorIneligible () const { return m_IsElligatorIneligible; }
void SetElligatorIneligible () { m_IsElligatorIneligible = true; } void SetElligatorIneligible () { m_IsElligatorIneligible = true; }
private: private:
uint8_t m_PublicKey[32]; uint8_t m_PublicKey[32];
@ -104,11 +108,11 @@ namespace crypto
BN_CTX * m_Ctx; BN_CTX * m_Ctx;
uint8_t m_PrivateKey[32]; uint8_t m_PrivateKey[32];
#endif #endif
bool m_IsElligatorIneligible = false; // true if definitly ineligible bool m_IsElligatorIneligible = false; // true if definitely ineligible
}; };
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted); // 222 bytes data, 514 bytes encrypted
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data); // 514 bytes encrypted, 222 data
void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub); void GenerateElGamalKeyPair (uint8_t * priv, uint8_t * pub);
@ -315,13 +319,15 @@ namespace crypto
uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/; uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
void MixHash (const uint8_t * buf, size_t len); void MixHash (const uint8_t * buf, size_t len);
void MixKey (const uint8_t * sharedSecret); void MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs);
void MixKey (const uint8_t * sharedSecret);
}; };
void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router) void InitNoiseNState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_N (tunnels, router)
void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2) void InitNoiseXKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (NTCP2)
void InitNoiseXKState1 (NoiseSymmetricState& state, const uint8_t * pub); // Noise_XK (SSU2)
void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets) void InitNoiseIKState (NoiseSymmetricState& state, const uint8_t * pub); // Noise_IK (ratchets)
// init and terminate // init and terminate
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force); void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
void TerminateCrypto (); void TerminateCrypto ();
@ -379,7 +385,7 @@ inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
if (dh->p) BN_free (dh->p); if (dh->p) BN_free (dh->p);
if (dh->q) BN_free (dh->q); if (dh->q) BN_free (dh->q);
if (dh->g) BN_free (dh->g); if (dh->g) BN_free (dh->g);
dh->p = p; dh->q = q; dh->g = g; return 1; dh->p = p; dh->q = q; dh->g = g; return 1;
} }
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{ {

View File

@ -29,7 +29,7 @@ namespace crypto
public: public:
virtual ~CryptoKeyDecryptor () {}; virtual ~CryptoKeyDecryptor () {};
virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data) = 0; virtual bool Decrypt (const uint8_t * encrypted, uint8_t * data) = 0;
virtual size_t GetPublicKeyLen () const = 0; // we need it to set key in LS2 virtual size_t GetPublicKeyLen () const = 0; // we need it to set key in LS2
}; };

View File

@ -303,7 +303,7 @@ namespace datagram
} }
} }
if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ()) if (!m_RoutingSession || m_RoutingSession->IsTerminated () || !m_RoutingSession->IsReadyToSend ())
{ {
bool found = false; bool found = false;
for (auto& it: m_PendingRoutingSessions) for (auto& it: m_PendingRoutingSessions)
@ -324,7 +324,7 @@ namespace datagram
auto path = m_RoutingSession->GetSharedRoutingPath(); auto path = m_RoutingSession->GetSharedRoutingPath();
if (path && m_RoutingSession->IsRatchets () && if (path && m_RoutingSession->IsRatchets () &&
m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT) m_LastUse > m_RoutingSession->GetLastActivityTimestamp ()*1000 + DATAGRAM_SESSION_PATH_TIMEOUT)
{ {
m_RoutingSession->SetSharedRoutingPath (nullptr); m_RoutingSession->SetSharedRoutingPath (nullptr);
path = nullptr; path = nullptr;
@ -371,8 +371,6 @@ namespace datagram
{ {
// no current path, make one // no current path, make one
path = std::make_shared<i2p::garlic::GarlicRoutingPath>(); path = std::make_shared<i2p::garlic::GarlicRoutingPath>();
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel();
if (!path->outboundTunnel) return nullptr;
if (m_RemoteLeaseSet) if (m_RemoteLeaseSet)
{ {
@ -386,6 +384,11 @@ namespace datagram
} }
else else
return nullptr; return nullptr;
auto leaseRouter = i2p::data::netdb.FindRouter (path->remoteLease->tunnelGateway);
path->outboundTunnel = m_LocalDestination->GetTunnelPool()->GetNextOutboundTunnel(nullptr,
leaseRouter ? leaseRouter->GetCompatibleTransports (false) : (i2p::data::RouterInfo::CompatibleTransports)i2p::data::RouterInfo::eAllTransports);
if (!path->outboundTunnel) return nullptr;
} }
else else
{ {

View File

@ -117,12 +117,12 @@ namespace datagram
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendRawDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
// TODO: implement calls from other thread from SAM // TODO: implement calls from other thread from SAM
std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash & ident); std::shared_ptr<DatagramSession> GetSession(const i2p::data::IdentHash & ident);
void SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void SendDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort); void SendRawDatagram (std::shared_ptr<DatagramSession> session, const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort);
void FlushSendQueue (std::shared_ptr<DatagramSession> session); void FlushSendQueue (std::shared_ptr<DatagramSession> session);
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len, bool isRaw = false);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, The PurpleI2P Project * Copyright (c) 2013-2022, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -13,7 +13,6 @@
#include <vector> #include <vector>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include "Crypto.h" #include "Crypto.h"
#include "Config.h"
#include "Log.h" #include "Log.h"
#include "FS.h" #include "FS.h"
#include "Timestamp.h" #include "Timestamp.h"
@ -35,6 +34,8 @@ namespace client
int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY; int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY;
int outLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH; int outLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH;
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
int inVar = DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE;
int outVar = DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE;
int numTags = DEFAULT_TAGS_TO_SEND; int numTags = DEFAULT_TAGS_TO_SEND;
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers; std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
try try
@ -53,10 +54,16 @@ namespace client
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY); it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY);
if (it != params->end ()) if (it != params->end ())
outQty = std::stoi(it->second); outQty = std::stoi(it->second);
it = params->find (I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE);
if (it != params->end ())
inVar = std::stoi(it->second);
it = params->find (I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE);
if (it != params->end ())
outVar = std::stoi(it->second);
it = params->find (I2CP_PARAM_TAGS_TO_SEND); it = params->find (I2CP_PARAM_TAGS_TO_SEND);
if (it != params->end ()) if (it != params->end ())
numTags = std::stoi(it->second); numTags = std::stoi(it->second);
LogPrint (eLogInfo, "Destination: parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags"); LogPrint (eLogInfo, "Destination: Parameters for tunnel set to: ", inQty, " inbound (", inLen, " hops), ", outQty, " outbound (", outLen, " hops), ", numTags, " tags");
it = params->find (I2CP_PARAM_RATCHET_INBOUND_TAGS); it = params->find (I2CP_PARAM_RATCHET_INBOUND_TAGS);
if (it != params->end ()) if (it != params->end ())
SetNumRatchetInboundTags (std::stoi(it->second)); SetNumRatchetInboundTags (std::stoi(it->second));
@ -86,10 +93,8 @@ namespace client
if (it != params->end ()) if (it != params->end ())
{ {
// oveeride isPublic // oveeride isPublic
bool dontpublish = false; m_IsPublic = (it->second != "true");
i2p::config::GetOption (it->second, dontpublish); }
m_IsPublic = !dontpublish;
}
it = params->find (I2CP_PARAM_LEASESET_TYPE); it = params->find (I2CP_PARAM_LEASESET_TYPE);
if (it != params->end ()) if (it != params->end ())
m_LeaseSetType = std::stoi(it->second); m_LeaseSetType = std::stoi(it->second);
@ -112,7 +117,7 @@ namespace client
m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>()); m_LeaseSetPrivKey.reset (new i2p::data::Tag<32>());
if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32) if (m_LeaseSetPrivKey->FromBase64 (it->second) != 32)
{ {
LogPrint(eLogError, "Destination: invalid value i2cp.leaseSetPrivKey ", it->second); LogPrint(eLogError, "Destination: Invalid value i2cp.leaseSetPrivKey ", it->second);
m_LeaseSetPrivKey.reset (nullptr); m_LeaseSetPrivKey.reset (nullptr);
} }
} }
@ -120,10 +125,10 @@ namespace client
} }
catch (std::exception & ex) catch (std::exception & ex)
{ {
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what()); LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
} }
SetNumTags (numTags); SetNumTags (numTags);
m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty); m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (inLen, outLen, inQty, outQty, inVar, outVar);
if (explicitPeers) if (explicitPeers)
m_Pool->SetExplicitPeers (explicitPeers); m_Pool->SetExplicitPeers (explicitPeers);
if(params) if(params)
@ -136,7 +141,7 @@ namespace client
auto minlatency = std::stoi(itr->second); auto minlatency = std::stoi(itr->second);
if ( minlatency > 0 && maxlatency > 0 ) { if ( minlatency > 0 && maxlatency > 0 ) {
// set tunnel pool latency // set tunnel pool latency
LogPrint(eLogInfo, "Destination: requiring tunnel latency [", minlatency, "ms, ", maxlatency, "ms]"); LogPrint(eLogInfo, "Destination: Requiring tunnel latency [", minlatency, "ms, ", maxlatency, "ms]");
m_Pool->RequireLatency(minlatency, maxlatency); m_Pool->RequireLatency(minlatency, maxlatency);
} }
} }
@ -251,7 +256,7 @@ namespace client
} }
else else
{ {
LogPrint (eLogWarning, "Destination: remote LeaseSet expired"); LogPrint (eLogWarning, "Destination: Remote LeaseSet expired");
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex); std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
m_RemoteLeaseSets.erase (ident); m_RemoteLeaseSets.erase (ident);
return nullptr; return nullptr;
@ -331,6 +336,22 @@ namespace client
return true; return true;
} }
void LeaseSetDestination::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
{
struct
{
uint8_t k[32];
uint64_t t;
} data;
memcpy (data.k, key, 32);
data.t = tag;
auto s = shared_from_this ();
m_Service.post ([s,data](void)
{
s->AddECIESx25519Key (data.k, data.t);
});
}
void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) void LeaseSetDestination::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg)); m_Service.post (std::bind (&LeaseSetDestination::HandleGarlicMessage, shared_from_this (), msg));
@ -367,8 +388,8 @@ namespace client
HandleDatabaseSearchReplyMessage (payload, len); HandleDatabaseSearchReplyMessage (payload, len);
break; break;
case eI2NPShortTunnelBuildReply: // might come as garlic encrypted case eI2NPShortTunnelBuildReply: // might come as garlic encrypted
i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID)); i2p::HandleI2NPMessage (CreateI2NPMessage (typeID, payload, len, msgID));
break; break;
default: default:
LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID); LogPrint (eLogWarning, "Destination: Unexpected I2NP message type ", typeID);
return false; return false;
@ -395,8 +416,8 @@ namespace client
LogPrint (eLogDebug, "Destination: Remote LeaseSet"); LogPrint (eLogDebug, "Destination: Remote LeaseSet");
std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex); std::lock_guard<std::mutex> lock(m_RemoteLeaseSetsMutex);
auto it = m_RemoteLeaseSets.find (key); auto it = m_RemoteLeaseSets.find (key);
if (it != m_RemoteLeaseSets.end () && if (it != m_RemoteLeaseSets.end () &&
it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type it->second->GetStoreType () == buf[DATABASE_STORE_TYPE_OFFSET]) // update only if same type
{ {
leaseSet = it->second; leaseSet = it->second;
if (leaseSet->IsNewer (buf + offset, len - offset)) if (leaseSet->IsNewer (buf + offset, len - offset))
@ -487,7 +508,7 @@ namespace client
i2p::data::IdentHash peerHash (buf + 33 + i*32); i2p::data::IdentHash peerHash (buf + 33 + i*32);
if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash)) if (!request->excluded.count (peerHash) && !i2p::data::netdb.FindRouter (peerHash))
{ {
LogPrint (eLogInfo, "Destination: Found new floodfill, request it"); LogPrint (eLogInfo, "Destination: Found new floodfill, request it");
i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory i2p::data::netdb.RequestDestination (peerHash, nullptr, false); // through exploratory
} }
} }
@ -555,16 +576,9 @@ namespace client
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
return; return;
} }
auto outbound = m_Pool->GetNextOutboundTunnel (); if (!m_Pool->GetInboundTunnels ().size () || !m_Pool->GetOutboundTunnels ().size ())
if (!outbound)
{ {
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels"); LogPrint (eLogError, "Destination: Can't publish LeaseSet. Destination is not ready");
return;
}
auto inbound = m_Pool->GetNextInboundTunnel ();
if (!inbound)
{
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
return; return;
} }
auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills); auto floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
@ -574,6 +588,33 @@ namespace client
m_ExcludedFloodfills.clear (); m_ExcludedFloodfills.clear ();
return; return;
} }
auto outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
auto inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
if (!outbound || !inbound)
{
LogPrint (eLogInfo, "Destination: No compatible tunnels with ", floodfill->GetIdentHash ().ToBase64 (), ". Trying another floodfill");
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
floodfill = i2p::data::netdb.GetClosestFloodfill (leaseSet->GetIdentHash (), m_ExcludedFloodfills);
if (floodfill)
{
outbound = m_Pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false));
if (outbound)
{
inbound = m_Pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true));
if (!inbound)
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No inbound tunnels");
}
else
LogPrint (eLogError, "Destination: Can't publish LeaseSet. No outbound tunnels");
}
else
LogPrint (eLogError, "Destination: Can't publish LeaseSet, no more floodfills found");
if (!floodfill || !outbound || !inbound)
{
m_ExcludedFloodfills.clear ();
return;
}
}
m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); m_ExcludedFloodfills.insert (floodfill->GetIdentHash ());
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
@ -618,7 +659,7 @@ namespace client
auto ls = GetLeaseSetMt (); auto ls = GetLeaseSetMt ();
if (!ls) if (!ls)
{ {
LogPrint (eLogWarning, "Destination: couldn't verify LeaseSet for ", GetIdentHash().ToBase32()); LogPrint (eLogWarning, "Destination: Couldn't verify LeaseSet for ", GetIdentHash().ToBase32());
return; return;
} }
auto s = shared_from_this (); auto s = shared_from_this ();
@ -630,7 +671,7 @@ namespace client
if (*ls == *leaseSet) if (*ls == *leaseSet)
{ {
// we got latest LeasetSet // we got latest LeasetSet
LogPrint (eLogDebug, "Destination: published LeaseSet verified for ", s->GetIdentHash().ToBase32()); LogPrint (eLogDebug, "Destination: Published LeaseSet verified for ", s->GetIdentHash().ToBase32());
s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL)); s->m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_REGULAR_VERIFICATION_INTERNAL));
s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1)); s->m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, s, std::placeholders::_1));
return; return;
@ -639,7 +680,7 @@ namespace client
LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", s->GetIdentHash().ToBase32()); LogPrint (eLogDebug, "Destination: LeaseSet is different than just published for ", s->GetIdentHash().ToBase32());
} }
else else
LogPrint (eLogWarning, "Destination: couldn't find published LeaseSet for ", s->GetIdentHash().ToBase32()); LogPrint (eLogWarning, "Destination: Couldn't find published LeaseSet for ", s->GetIdentHash().ToBase32());
// we have to publish again // we have to publish again
s->Publish (); s->Publish ();
}); });
@ -751,10 +792,10 @@ 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 (); request->replyTunnel = m_Pool->GetNextInboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (true));
if (!request->replyTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no 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 (); request->outboundTunnel = m_Pool->GetNextOutboundTunnel (nullptr, nextFloodfill->GetCompatibleTransports (false));
if (!request->outboundTunnel) LogPrint (eLogError, "Destination: Can't send LeaseSet request, no 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)
@ -767,11 +808,11 @@ namespace client
uint8_t replyKey[32], replyTag[32]; uint8_t replyKey[32], replyTag[32];
RAND_bytes (replyKey, 32); // random session key RAND_bytes (replyKey, 32); // random session key
RAND_bytes (replyTag, isECIES ? 8 : 32); // random session tag RAND_bytes (replyTag, isECIES ? 8 : 32); // random session tag
if (isECIES) if (isECIES)
AddECIESx25519Key (replyKey, replyTag); AddECIESx25519Key (replyKey, replyTag);
else else
AddSessionKey (replyKey, replyTag); AddSessionKey (replyKey, replyTag);
auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest,
request->excluded, request->replyTunnel, replyKey, replyTag, isECIES)); request->excluded, request->replyTunnel, replyKey, replyTag, isECIES));
request->outboundTunnel->SendTunnelDataMsg ( request->outboundTunnel->SendTunnelDataMsg (
{ {
@ -866,8 +907,8 @@ namespace client
ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, ClientDestination::ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
bool isPublic, const std::map<std::string, std::string> * params): bool isPublic, const std::map<std::string, std::string> * params):
LeaseSetDestination (service, isPublic, params), LeaseSetDestination (service, isPublic, params),
m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY), m_Keys (keys), m_StreamingAckDelay (DEFAULT_INITIAL_ACK_DELAY),
m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS), m_IsStreamingAnswerPings (DEFAULT_ANSWER_PINGS),
m_DatagramDestination (nullptr), m_RefCounter (0), m_DatagramDestination (nullptr), m_RefCounter (0),
m_ReadyChecker(service) m_ReadyChecker(service)
@ -910,22 +951,22 @@ namespace client
for (auto& it: encryptionKeyTypes) for (auto& it: encryptionKeyTypes)
{ {
auto encryptionKey = new EncryptionKey (it); auto encryptionKey = new EncryptionKey (it);
if (isPublic) if (IsPublic ())
PersistTemporaryKeys (encryptionKey, isSingleKey); PersistTemporaryKeys (encryptionKey, isSingleKey);
else else
encryptionKey->GenerateKeys (); encryptionKey->GenerateKeys ();
encryptionKey->CreateDecryptor (); encryptionKey->CreateDecryptor ();
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
{ {
m_ECIESx25519EncryptionKey.reset (encryptionKey); m_ECIESx25519EncryptionKey.reset (encryptionKey);
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2 SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // Rathets must use LeaseSet2
} }
else else
m_StandardEncryptionKey.reset (encryptionKey); m_StandardEncryptionKey.reset (encryptionKey);
} }
if (isPublic) if (IsPublic ())
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
try try
@ -938,8 +979,8 @@ namespace client
m_StreamingAckDelay = std::stoi(it->second); m_StreamingAckDelay = std::stoi(it->second);
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS); it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
if (it != params->end ()) if (it != params->end ())
i2p::config::GetOption (it->second, m_IsStreamingAnswerPings); m_IsStreamingAnswerPings = (it->second == "true");
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2)
{ {
// authentication for encrypted LeaseSet // authentication for encrypted LeaseSet
@ -966,7 +1007,7 @@ namespace client
} }
catch (std::exception & ex) catch (std::exception & ex)
{ {
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what()); LogPrint(eLogError, "Destination: Unable to parse parameters for destination: ", ex.what());
} }
} }
@ -1042,7 +1083,7 @@ namespace client
LogPrint (eLogError, "Destination: Missing raw datagram destination"); LogPrint (eLogError, "Destination: Missing raw datagram destination");
break; break;
default: default:
LogPrint (eLogError, "Destination: Data: unexpected protocol ", buf[9]); LogPrint (eLogError, "Destination: Data: Unexpected protocol ", buf[9]);
} }
} }
@ -1050,7 +1091,7 @@ namespace client
{ {
if (!streamRequestComplete) if (!streamRequestComplete)
{ {
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream"); LogPrint (eLogError, "Destination: Request callback is not specified in CreateStream");
return; return;
} }
auto leaseSet = FindLeaseSet (dest); auto leaseSet = FindLeaseSet (dest);
@ -1074,7 +1115,7 @@ namespace client
{ {
if (!streamRequestComplete) if (!streamRequestComplete)
{ {
LogPrint (eLogError, "Destination: request callback is not specified in CreateStream"); LogPrint (eLogError, "Destination: Request callback is not specified in CreateStream");
return; return;
} }
auto s = GetSharedFromThis (); auto s = GetSharedFromThis ();
@ -1099,21 +1140,21 @@ namespace client
void ClientDestination::SendPing (const i2p::data::IdentHash& to) void ClientDestination::SendPing (const i2p::data::IdentHash& to)
{ {
if (m_StreamingDestination) if (m_StreamingDestination)
{ {
auto leaseSet = FindLeaseSet (to); auto leaseSet = FindLeaseSet (to);
if (leaseSet) if (leaseSet)
m_StreamingDestination->SendPing (leaseSet); m_StreamingDestination->SendPing (leaseSet);
else else
{ {
auto s = m_StreamingDestination; auto s = m_StreamingDestination;
RequestDestination (to, RequestDestination (to,
[s](std::shared_ptr<const i2p::data::LeaseSet> ls) [s](std::shared_ptr<const i2p::data::LeaseSet> ls)
{ {
if (ls) s->SendPing (ls); if (ls) s->SendPing (ls);
}); });
} }
} }
} }
void ClientDestination::SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to) void ClientDestination::SendPing (std::shared_ptr<const i2p::data::BlindedPublicKey> to)
{ {
@ -1122,9 +1163,9 @@ namespace client
[s](std::shared_ptr<const i2p::data::LeaseSet> ls) [s](std::shared_ptr<const i2p::data::LeaseSet> ls)
{ {
if (ls) s->SendPing (ls); if (ls) s->SendPing (ls);
}); });
} }
std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const std::shared_ptr<i2p::stream::StreamingDestination> ClientDestination::GetStreamingDestination (int port) const
{ {
if (port) if (port)
@ -1182,18 +1223,18 @@ namespace client
auto ret = it->second; auto ret = it->second;
m_StreamingDestinationsByPorts.erase (it); m_StreamingDestinationsByPorts.erase (it);
return ret; return ret;
} }
} }
return nullptr; return nullptr;
} }
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip) i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip)
{ {
if (m_DatagramDestination == nullptr) if (m_DatagramDestination == nullptr)
m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip); m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip);
return m_DatagramDestination; return m_DatagramDestination;
} }
std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const std::vector<std::shared_ptr<const i2p::stream::Stream> > ClientDestination::GetAllStreams () const
{ {
std::vector<std::shared_ptr<const i2p::stream::Stream> > ret; std::vector<std::shared_ptr<const i2p::stream::Stream> > ret;
@ -1282,7 +1323,7 @@ namespace client
if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor) if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor)
return m_StandardEncryptionKey->decryptor->Decrypt (encrypted, data); return m_StandardEncryptionKey->decryptor->Decrypt (encrypted, data);
else else
LogPrint (eLogError, "Destinations: decryptor is not set"); LogPrint (eLogError, "Destinations: Decryptor is not set");
return false; return false;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -53,6 +53,10 @@ namespace client
const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5; const int DEFAULT_INBOUND_TUNNELS_QUANTITY = 5;
const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity"; const char I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY[] = "outbound.quantity";
const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5; const int DEFAULT_OUTBOUND_TUNNELS_QUANTITY = 5;
const char I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE[] = "inbound.lengthVariance";
const int DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE = 0;
const char I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE[] = "outbound.lengthVariance";
const int DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE = 0;
const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers"; const char I2CP_PARAM_EXPLICIT_PEERS[] = "explicitPeers";
const int STREAM_REQUEST_TIMEOUT = 60; //in seconds const int STREAM_REQUEST_TIMEOUT = 60; //in seconds
const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend"; const char I2CP_PARAM_TAGS_TO_SEND[] = "crypto.tagsToSend";
@ -68,8 +72,8 @@ namespace client
const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64 const char I2CP_PARAM_LEASESET_PRIV_KEY[] = "i2cp.leaseSetPrivKey"; // PSK decryption key, base64
const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType"; const char I2CP_PARAM_LEASESET_AUTH_TYPE[] = "i2cp.leaseSetAuthType";
const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn const char I2CP_PARAM_LEASESET_CLIENT_DH[] = "i2cp.leaseSetClient.dh"; // group of i2cp.leaseSetClient.dh.nnn
const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn const char I2CP_PARAM_LEASESET_CLIENT_PSK[] = "i2cp.leaseSetClient.psk"; // group of i2cp.leaseSetClient.psk.nnn
// latency // latency
const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min"; const char I2CP_PARAM_MIN_TUNNEL_LATENCY[] = "latency.min";
const int DEFAULT_MIN_TUNNEL_LATENCY = 0; const int DEFAULT_MIN_TUNNEL_LATENCY = 0;
@ -80,7 +84,7 @@ namespace client
const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay"; const char I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY[] = "i2p.streaming.initialAckDelay";
const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds const int DEFAULT_INITIAL_ACK_DELAY = 200; // milliseconds
const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings"; const char I2CP_PARAM_STREAMING_ANSWER_PINGS[] = "i2p.streaming.answerPings";
const int DEFAULT_ANSWER_PINGS = true; const int DEFAULT_ANSWER_PINGS = true;
typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete; typedef std::function<void (std::shared_ptr<i2p::stream::Stream> stream)> StreamRequestComplete;
@ -134,12 +138,13 @@ namespace client
// override GarlicDestination // override GarlicDestination
bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag);
void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag);
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void SetLeaseSetUpdated (); void SetLeaseSetUpdated ();
bool IsPublic () const { return m_IsPublic; }; bool IsPublic () const { return m_IsPublic; };
void SetPublic (bool pub) { m_IsPublic = pub; }; void SetPublic (bool pub) { m_IsPublic = pub; };
protected: protected:
@ -251,7 +256,7 @@ namespace client
void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor); void AcceptOnce (const i2p::stream::StreamingDestination::Acceptor& acceptor);
int GetStreamingAckDelay () const { return m_StreamingAckDelay; } int GetStreamingAckDelay () const { return m_StreamingAckDelay; }
bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; } bool IsStreamingAnswerPings () const { return m_IsStreamingAnswerPings; }
// datagram // datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true); i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true);

View File

@ -90,24 +90,24 @@ namespace garlic
} }
void RatchetTagSet::DeleteSymmKey (int index) void RatchetTagSet::DeleteSymmKey (int index)
{ {
m_ItermediateSymmKeys.erase (index); m_ItermediateSymmKeys.erase (index);
} }
void ReceiveRatchetTagSet::Expire () void ReceiveRatchetTagSet::Expire ()
{ {
if (!m_ExpirationTimestamp) if (!m_ExpirationTimestamp)
m_ExpirationTimestamp = i2p::util::GetSecondsSinceEpoch () + ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT; m_ExpirationTimestamp = i2p::util::GetSecondsSinceEpoch () + ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT;
} }
bool ReceiveRatchetTagSet::IsExpired (uint64_t ts) const bool ReceiveRatchetTagSet::IsExpired (uint64_t ts) const
{ {
return m_ExpirationTimestamp && ts > m_ExpirationTimestamp; return m_ExpirationTimestamp && ts > m_ExpirationTimestamp;
} }
bool ReceiveRatchetTagSet::IsIndexExpired (int index) const bool ReceiveRatchetTagSet::IsIndexExpired (int index) const
{ {
return index < m_TrimBehindIndex; return index < m_TrimBehindIndex;
} }
bool ReceiveRatchetTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index) bool ReceiveRatchetTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index)
@ -115,21 +115,21 @@ namespace garlic
auto session = GetSession (); auto session = GetSession ();
if (!session) return false; if (!session) return false;
return session->HandleNextMessage (buf, len, shared_from_this (), index); return session->HandleNextMessage (buf, len, shared_from_this (), index);
} }
SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key): SymmetricKeyTagSet::SymmetricKeyTagSet (GarlicDestination * destination, const uint8_t * key):
ReceiveRatchetTagSet (nullptr), m_Destination (destination) ReceiveRatchetTagSet (nullptr), m_Destination (destination)
{ {
memcpy (m_Key, key, 32); memcpy (m_Key, key, 32);
Expire (); Expire ();
} }
bool SymmetricKeyTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index) bool SymmetricKeyTagSet::HandleNextMessage (uint8_t * buf, size_t len, int index)
{ {
if (len < 24) return false; if (len < 24) return false;
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); // n = 0 memset (nonce, 0, 12); // n = 0
size_t offset = 8; // first 8 bytes is reply tag used as AD size_t offset = 8; // first 8 bytes is reply tag used as AD
len -= 16; // poly1305 len -= 16; // poly1305
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len - offset, buf, 8, m_Key, nonce, buf + offset, len - offset, false)) // decrypt if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len - offset, buf, 8, m_Key, nonce, buf + offset, len - offset, false)) // decrypt
{ {
@ -137,33 +137,33 @@ namespace garlic
return false; return false;
} }
// we assume 1 I2NP block with delivery type local // we assume 1 I2NP block with delivery type local
if (offset + 3 > len) if (offset + 3 > len)
{ {
LogPrint (eLogWarning, "Garlic: Symmetric key tagset is too short ", len); LogPrint (eLogWarning, "Garlic: Symmetric key tagset is too short ", len);
return false; return false;
} }
if (buf[offset] != eECIESx25519BlkGalicClove) if (buf[offset] != eECIESx25519BlkGalicClove)
{ {
LogPrint (eLogWarning, "Garlic: Symmetric key tagset unexpected block ", (int)buf[offset]); LogPrint (eLogWarning, "Garlic: Symmetric key tagset unexpected block ", (int)buf[offset]);
return false; return false;
} }
offset++; offset++;
auto size = bufbe16toh (buf + offset); auto size = bufbe16toh (buf + offset);
offset += 2; offset += 2;
if (offset + size > len) if (offset + size > len)
{ {
LogPrint (eLogWarning, "Garlic: Symmetric key tagset block is too long ", size); LogPrint (eLogWarning, "Garlic: Symmetric key tagset block is too long ", size);
return false; return false;
} }
if (m_Destination) if (m_Destination)
m_Destination->HandleECIESx25519GarlicClove (buf + offset, size); m_Destination->HandleECIESx25519GarlicClove (buf + offset, size);
return true; return true;
} }
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS): ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSetNS):
GarlicRoutingSession (owner, true) GarlicRoutingSession (owner, true)
{ {
if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate); if (!attachLeaseSetNS) SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0; RAND_bytes (m_PaddingSizes, 32); m_NextPaddingSize = 0;
} }
@ -181,11 +181,11 @@ namespace garlic
{ {
bool ineligible = false; bool ineligible = false;
while (!ineligible) while (!ineligible)
{ {
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
ineligible = m_EphemeralKeys->IsElligatorIneligible (); ineligible = m_EphemeralKeys->IsElligatorIneligible ();
if (!ineligible) // we haven't tried it yet if (!ineligible) // we haven't tried it yet
{ {
if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys->GetPublicKey (), buf)) if (i2p::crypto::GetElligator ()->Encode (m_EphemeralKeys->GetPublicKey (), buf))
return true; // success return true; // success
// otherwise return back // otherwise return back
@ -194,7 +194,7 @@ namespace garlic
} }
else else
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys); i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
} }
// we still didn't find elligator eligible pair // we still didn't find elligator eligible pair
for (int i = 0; i < 25; i++) for (int i = 0; i < 25; i++)
{ {
@ -208,7 +208,7 @@ namespace garlic
// let NTCP2 use it // let NTCP2 use it
m_EphemeralKeys->SetElligatorIneligible (); m_EphemeralKeys->SetElligatorIneligible ();
i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys); i2p::transport::transports.ReuseX25519KeysPair (m_EphemeralKeys);
} }
} }
LogPrint (eLogError, "Garlic: Can't generate elligator eligible x25519 keys"); LogPrint (eLogError, "Garlic: Can't generate elligator eligible x25519 keys");
return false; return false;
@ -229,7 +229,7 @@ namespace garlic
// we are Bob // we are Bob
// KDF1 // KDF1
i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk i2p::crypto::InitNoiseIKState (GetNoiseState (), GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)); // bpk
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
{ {
LogPrint (eLogError, "Garlic: Can't decode elligator"); LogPrint (eLogError, "Garlic: Can't decode elligator");
@ -243,7 +243,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
// decrypt flags/static // decrypt flags/static
@ -267,7 +267,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice static key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
} }
else // all zeros flags else // all zeros flags
@ -280,13 +280,13 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
return false; return false;
} }
m_State = eSessionStateNewSessionReceived; m_State = eSessionStateNewSessionReceived;
if (isStatic) if (isStatic)
{ {
MixHash (buf, len); // h = SHA256(h || ciphertext) MixHash (buf, len); // h = SHA256(h || ciphertext)
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
} }
HandlePayload (payload.data (), len - 16, nullptr, 0); HandlePayload (payload.data (), len - 16, nullptr, 0);
return true; return true;
@ -314,7 +314,7 @@ namespace garlic
GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size); GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size);
break; break;
case eECIESx25519BlkNextKey: case eECIESx25519BlkNextKey:
LogPrint (eLogDebug, "Garlic: next key"); LogPrint (eLogDebug, "Garlic: Next key");
if (receiveTagset) if (receiveTagset)
HandleNextKey (buf + offset, size, receiveTagset); HandleNextKey (buf + offset, size, receiveTagset);
else else
@ -322,7 +322,7 @@ namespace garlic
break; break;
case eECIESx25519BlkAck: case eECIESx25519BlkAck:
{ {
LogPrint (eLogDebug, "Garlic: ack"); LogPrint (eLogDebug, "Garlic: Ack");
int numAcks = size >> 2; // /4 int numAcks = size >> 2; // /4
auto offset1 = offset; auto offset1 = offset;
for (auto i = 0; i < numAcks; i++) for (auto i = 0; i < numAcks; i++)
@ -334,24 +334,24 @@ namespace garlic
} }
case eECIESx25519BlkAckRequest: case eECIESx25519BlkAckRequest:
{ {
LogPrint (eLogDebug, "Garlic: ack request"); LogPrint (eLogDebug, "Garlic: Ack request");
m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index}); m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
break; break;
} }
case eECIESx25519BlkTermination: case eECIESx25519BlkTermination:
LogPrint (eLogDebug, "Garlic: termination"); LogPrint (eLogDebug, "Garlic: Termination");
if (GetOwner ()) if (GetOwner ())
GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey); GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey);
if (receiveTagset) receiveTagset->Expire (); if (receiveTagset) receiveTagset->Expire ();
break; break;
case eECIESx25519BlkDateTime: case eECIESx25519BlkDateTime:
LogPrint (eLogDebug, "Garlic: datetime"); LogPrint (eLogDebug, "Garlic: Datetime");
break; break;
case eECIESx25519BlkOptions: case eECIESx25519BlkOptions:
LogPrint (eLogDebug, "Garlic: options"); LogPrint (eLogDebug, "Garlic: Options");
break; break;
case eECIESx25519BlkPadding: case eECIESx25519BlkPadding:
LogPrint (eLogDebug, "Garlic: padding"); LogPrint (eLogDebug, "Garlic: Padding");
break; break;
default: default:
LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk); LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk);
@ -381,7 +381,7 @@ namespace garlic
newTagset->NextSessionTagRatchet (); newTagset->NextSessionTagRatchet ();
m_SendTagset = newTagset; m_SendTagset = newTagset;
m_SendForwardKey = false; m_SendForwardKey = false;
LogPrint (eLogDebug, "Garlic: next send tagset ", newTagset->GetTagSetID (), " created"); LogPrint (eLogDebug, "Garlic: Next send tagset ", newTagset->GetTagSetID (), " created");
} }
else else
LogPrint (eLogDebug, "Garlic: Unexpected next key ", keyID); LogPrint (eLogDebug, "Garlic: Unexpected next key ", keyID);
@ -424,7 +424,7 @@ namespace garlic
GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ? GenerateMoreReceiveTags (newTagset, (GetOwner () && GetOwner ()->GetNumRatchetInboundTags () > 0) ?
GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS); GetOwner ()->GetNumRatchetInboundTags () : ECIESX25519_MAX_NUM_GENERATED_TAGS);
receiveTagset->Expire (); receiveTagset->Expire ();
LogPrint (eLogDebug, "Garlic: next receive tagset ", tagsetID, " created"); LogPrint (eLogDebug, "Garlic: Next receive tagset ", tagsetID, " created");
} }
} }
@ -446,7 +446,7 @@ namespace garlic
m_NextSendRatchet->key = i2p::transport::transports.GetNextX25519KeysPair (); m_NextSendRatchet->key = i2p::transport::transports.GetNextX25519KeysPair ();
m_SendForwardKey = true; m_SendForwardKey = true;
LogPrint (eLogDebug, "Garlic: new send ratchet ", m_NextSendRatchet->newKey ? "new" : "old", " key ", m_NextSendRatchet->keyID, " created"); LogPrint (eLogDebug, "Garlic: New send ratchet ", m_NextSendRatchet->newKey ? "new" : "old", " key ", m_NextSendRatchet->keyID, " created");
} }
bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic) bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic)
@ -468,7 +468,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Bob static key"); LogPrint (eLogWarning, "Garlic: Incorrect Bob static key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
// encrypt flags/static key section // encrypt flags/static key section
uint8_t nonce[12]; uint8_t nonce[12];
@ -478,7 +478,7 @@ namespace garlic
fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD);
else else
{ {
memset (out + offset, 0, 32); // all zeros flags section memset (out + offset, 0, 32); // all zeros flags section
fs = out + offset; fs = out + offset;
} }
if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
@ -486,14 +486,14 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed "); LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed ");
return false; return false;
} }
MixHash (out + offset, 48); // h = SHA256(h || ciphertext) MixHash (out + offset, 48); // h = SHA256(h || ciphertext)
offset += 48; offset += 48;
// KDF2 // KDF2
if (isStatic) if (isStatic)
{ {
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk) GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk)
MixKey (sharedSecret); MixKey (sharedSecret);
} }
else else
CreateNonce (1, nonce); CreateNonce (1, nonce);
@ -503,10 +503,10 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
return false; return false;
} }
m_State = eSessionStateNewSessionSent; m_State = eSessionStateNewSessionSent;
if (isStatic) if (isStatic)
{ {
MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext) MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext)
if (GetOwner ()) if (GetOwner ())
{ {
@ -514,11 +514,11 @@ namespace garlic
InitNewSessionTagset (tagsetNsr); InitNewSessionTagset (tagsetNsr);
tagsetNsr->Expire (); // let non-replied session expire tagsetNsr->Expire (); // let non-replied session expire
GenerateMoreReceiveTags (tagsetNsr, ECIESX25519_NSR_NUM_GENERATED_TAGS); GenerateMoreReceiveTags (tagsetNsr, ECIESX25519_NSR_NUM_GENERATED_TAGS);
} }
} }
return true; return true;
} }
bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
// we are Bob // we are Bob
@ -534,7 +534,7 @@ namespace garlic
LogPrint (eLogError, "Garlic: Can't encode elligator"); LogPrint (eLogError, "Garlic: Can't encode elligator");
return false; return false;
} }
memcpy (m_NSREncodedKey, out + offset, 56); // for possible next NSR memcpy (m_NSREncodedKey, out + offset, 32); // for possible next NSR
memcpy (m_NSRH, m_H, 32); memcpy (m_NSRH, m_H, 32);
offset += 32; offset += 32;
// KDF for Reply Key Section // KDF for Reply Key Section
@ -545,13 +545,13 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice ephemeral key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk) if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret)) // sharedSecret = x25519(besk, apk)
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Alice static key"); LogPrint (eLogWarning, "Garlic: Incorrect Alice static key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (0, nonce); CreateNonce (0, nonce);
@ -584,10 +584,10 @@ namespace garlic
} }
m_State = eSessionStateNewSessionReplySent; m_State = eSessionStateNewSessionReplySent;
m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch (); m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch ();
return true; return true;
} }
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
// we are Bob and sent NSR already // we are Bob and sent NSR already
@ -618,7 +618,7 @@ namespace garlic
bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (uint8_t * buf, size_t len) bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (uint8_t * buf, size_t len)
{ {
// we are Alice // we are Alice
LogPrint (eLogDebug, "Garlic: reply received"); LogPrint (eLogDebug, "Garlic: Reply received");
const uint8_t * tag = buf; const uint8_t * tag = buf;
buf += 8; len -= 8; // tag buf += 8; len -= 8; // tag
uint8_t bepk[32]; // Bob's ephemeral key uint8_t bepk[32]; // Bob's ephemeral key
@ -637,7 +637,7 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Bob ephemeral key"); LogPrint (eLogWarning, "Garlic: Incorrect Bob ephemeral key");
return false; return false;
} }
MixKey (sharedSecret); MixKey (sharedSecret);
GetOwner ()->Decrypt (bepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk) GetOwner ()->Decrypt (bepk, sharedSecret, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk)
MixKey (sharedSecret); MixKey (sharedSecret);
@ -700,11 +700,11 @@ namespace garlic
uint64_t tag = m_SendTagset->GetNextSessionTag (); uint64_t tag = m_SendTagset->GetNextSessionTag ();
if (!tag) if (!tag)
{ {
LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset"); LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for send tagset");
if (GetOwner ()) if (GetOwner ())
GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey); GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey);
return false; return false;
} }
memcpy (out, &tag, 8); memcpy (out, &tag, 8);
// ad = The session tag, 8 bytes // ad = The session tag, 8 bytes
// ciphertext = ENCRYPT(k, n, payload, ad) // ciphertext = ENCRYPT(k, n, payload, ad)
@ -736,7 +736,7 @@ namespace garlic
} }
HandlePayload (payload, len - 16, receiveTagset, index); HandlePayload (payload, len - 16, receiveTagset, index);
if (GetOwner ()) if (GetOwner ())
{ {
int moreTags = 0; int moreTags = 0;
if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings? if (GetOwner ()->GetNumRatchetInboundTags () > 0) // override in settings?
{ {
@ -745,17 +745,17 @@ namespace garlic
index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind index -= GetOwner ()->GetNumRatchetInboundTags (); // trim behind
} }
else else
{ {
moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4 moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS; if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
moreTags -= (receiveTagset->GetNextIndex () - index); moreTags -= (receiveTagset->GetNextIndex () - index);
index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind index -= ECIESX25519_MAX_NUM_GENERATED_TAGS; // trim behind
} }
if (moreTags > 0) if (moreTags > 0)
GenerateMoreReceiveTags (receiveTagset, moreTags); GenerateMoreReceiveTags (receiveTagset, moreTags);
if (index > 0) if (index > 0)
receiveTagset->SetTrimBehind (index); receiveTagset->SetTrimBehind (index);
} }
return true; return true;
} }
@ -774,13 +774,13 @@ namespace garlic
#endif #endif
case eSessionStateEstablished: case eSessionStateEstablished:
if (receiveTagset->IsNS ()) if (receiveTagset->IsNS ())
{ {
// our of sequence NSR // our of sequence NSR
LogPrint (eLogDebug, "Garlic: check for out of order NSR with index ", index); LogPrint (eLogDebug, "Garlic: Check for out of order NSR with index ", index);
if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2) if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2)
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS); GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS);
return HandleNewOutgoingSessionReply (buf, len); return HandleNewOutgoingSessionReply (buf, len);
} }
else else
return HandleExistingSessionMessage (buf, len, receiveTagset, index); return HandleExistingSessionMessage (buf, len, receiveTagset, index);
case eSessionStateNew: case eSessionStateNew:
@ -792,7 +792,7 @@ namespace garlic
} }
return true; return true;
} }
std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
{ {
uint8_t * payload = GetOwner ()->GetPayloadBuffer (); uint8_t * payload = GetOwner ()->GetPayloadBuffer ();
@ -829,7 +829,7 @@ namespace garlic
if (!NewOutgoingSessionMessage (payload, len, buf, m->maxLen, false)) if (!NewOutgoingSessionMessage (payload, len, buf, m->maxLen, false))
return nullptr; return nullptr;
len += 96; len += 96;
break; break;
default: default:
return nullptr; return nullptr;
} }
@ -844,18 +844,18 @@ namespace garlic
{ {
m_State = eSessionStateOneTime; m_State = eSessionStateOneTime;
return WrapSingleMessage (msg); return WrapSingleMessage (msg);
} }
size_t ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload) size_t ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload)
{ {
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
size_t payloadLen = 0; size_t payloadLen = 0;
if (first) payloadLen += 7;// datatime if (first) payloadLen += 7;// datatime
if (msg) if (msg)
{ {
payloadLen += msg->GetPayloadLength () + 13; payloadLen += msg->GetPayloadLength () + 13;
if (m_Destination) payloadLen += 32; if (m_Destination) payloadLen += 32;
} }
if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT) if (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted && ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)
{ {
// resubmit non-confirmed LeaseSet // resubmit non-confirmed LeaseSet
@ -896,9 +896,9 @@ namespace garlic
paddingSize = m_PaddingSizes[m_NextPaddingSize++] & 0x0F; // 0 - 15 paddingSize = m_PaddingSizes[m_NextPaddingSize++] & 0x0F; // 0 - 15
if (m_NextPaddingSize >= 32) if (m_NextPaddingSize >= 32)
{ {
RAND_bytes (m_PaddingSizes, 32); RAND_bytes (m_PaddingSizes, 32);
m_NextPaddingSize = 0; m_NextPaddingSize = 0;
} }
if (delta > 3) if (delta > 3)
{ {
delta -= 3; delta -= 3;
@ -912,9 +912,9 @@ namespace garlic
{ {
if (payloadLen > I2NP_MAX_MESSAGE_SIZE) if (payloadLen > I2NP_MAX_MESSAGE_SIZE)
{ {
LogPrint (eLogError, "Garlic: payload length ", payloadLen, " is too long"); LogPrint (eLogError, "Garlic: Payload length ", payloadLen, " is too long");
return 0; return 0;
} }
m_LastSentTimestamp = ts; m_LastSentTimestamp = ts;
size_t offset = 0; size_t offset = 0;
// DateTime // DateTime
@ -993,7 +993,7 @@ namespace garlic
htobe16buf (payload + offset, paddingSize); offset += 2; htobe16buf (payload + offset, paddingSize); offset += 2;
memset (payload + offset, 0, paddingSize); offset += paddingSize; memset (payload + offset, 0, paddingSize); offset += paddingSize;
} }
} }
return payloadLen; return payloadLen;
} }
@ -1050,17 +1050,17 @@ namespace garlic
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags) void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int numTags)
{ {
if (GetOwner ()) if (GetOwner ())
{ {
for (int i = 0; i < numTags; i++) for (int i = 0; i < numTags; i++)
{ {
auto tag = GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset); auto tag = GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset);
if (!tag) if (!tag)
{ {
LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for receive tagset"); LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for receive tagset");
break; break;
} }
} }
} }
} }
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts) bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
@ -1073,9 +1073,9 @@ namespace garlic
RouterIncomingRatchetSession::RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState): RouterIncomingRatchetSession::RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState):
ECIESX25519AEADRatchetSession (&i2p::context, false) ECIESX25519AEADRatchetSession (&i2p::context, false)
{ {
SetLeaseSetUpdateStatus (eLeaseSetDoNotSend); SetLeaseSetUpdateStatus (eLeaseSetDoNotSend);
SetNoiseState (initState); SetNoiseState (initState);
} }
bool RouterIncomingRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len) bool RouterIncomingRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len)
{ {
@ -1088,12 +1088,12 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key"); LogPrint (eLogWarning, "Garlic: Incorrect N ephemeral public key");
return false; return false;
} }
m_CurrentNoiseState.MixKey (sharedSecret); m_CurrentNoiseState.MixKey (sharedSecret);
buf += 32; len -= 32; buf += 32; len -= 32;
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (0, nonce); CreateNonce (0, nonce);
std::vector<uint8_t> payload (len - 16); std::vector<uint8_t> payload (len - 16);
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_CurrentNoiseState.m_H, 32, if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_CurrentNoiseState.m_H, 32,
m_CurrentNoiseState.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt m_CurrentNoiseState.m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt
{ {
@ -1102,20 +1102,20 @@ namespace garlic
} }
HandlePayload (payload.data (), len - 16, nullptr, 0); HandlePayload (payload.data (), len - 16, nullptr, 0);
return true; return true;
} }
static size_t CreateGarlicPayload (std::shared_ptr<const I2NPMessage> msg, uint8_t * payload, static size_t CreateGarlicPayload (std::shared_ptr<const I2NPMessage> msg, uint8_t * payload,
bool datetime, size_t optimalSize) bool datetime, size_t optimalSize)
{ {
size_t len = 0; size_t len = 0;
if (datetime) if (datetime)
{ {
// DateTime // DateTime
payload[0] = eECIESx25519BlkDateTime; payload[0] = eECIESx25519BlkDateTime;
htobe16buf (payload + 1, 4); htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
len = 7; len = 7;
} }
// I2NP // I2NP
payload += len; payload += len;
uint16_t cloveSize = msg->GetPayloadLength () + 10; uint16_t cloveSize = msg->GetPayloadLength () + 10;
@ -1139,14 +1139,14 @@ namespace garlic
delta -= 3; delta -= 3;
if (paddingSize > delta) paddingSize %= delta; if (paddingSize > delta) paddingSize %= delta;
} }
payload[0] = eECIESx25519BlkPadding; payload[0] = eECIESx25519BlkPadding;
htobe16buf (payload + 1, paddingSize); htobe16buf (payload + 1, paddingSize);
if (paddingSize) memset (payload + 3, 0, paddingSize); if (paddingSize) memset (payload + 3, 0, paddingSize);
len += paddingSize + 3; len += paddingSize + 3;
} }
return len; return len;
} }
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag) std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag)
{ {
auto m = NewI2NPMessage (); auto m = NewI2NPMessage ();
@ -1188,8 +1188,8 @@ namespace garlic
{ {
LogPrint (eLogWarning, "Garlic: Incorrect Bob static key"); LogPrint (eLogWarning, "Garlic: Incorrect Bob static key");
return nullptr; return nullptr;
} }
noiseState.MixKey (sharedSecret); noiseState.MixKey (sharedSecret);
auto payload = buf + offset; auto payload = buf + offset;
size_t len = CreateGarlicPayload (msg, payload, true, 900); // 1003 - 32 eph key - 16 Poly1305 hash - 16 I2NP header - 4 garlic length - 35 router tunnel delivery size_t len = CreateGarlicPayload (msg, payload, true, 900); // 1003 - 32 eph key - 16 Poly1305 hash - 16 I2NP header - 4 garlic length - 35 router tunnel delivery
uint8_t nonce[12]; uint8_t nonce[12];
@ -1205,6 +1205,6 @@ namespace garlic
m->len += offset + 4; m->len += offset + 4;
m->FillI2NPMessageHeader (eI2NPGarlic); m->FillI2NPMessageHeader (eI2NPGarlic);
return m; return m;
} }
} }
} }

View File

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 2013-2021, The PurpleI2P Project * Copyright (c) 2013-2021, The PurpleI2P Project
* *
@ -28,7 +27,7 @@ namespace garlic
{ {
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after
const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of seconds we receive nothing and should restart if we can
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds const int ECIESX25519_SEND_EXPIRATION_TIMEOUT = 480; // in seconds
const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds const int ECIESX25519_RECEIVE_EXPIRATION_TIMEOUT = 600; // in seconds
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180 const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
@ -46,7 +45,7 @@ namespace garlic
RatchetTagSet () {}; RatchetTagSet () {};
virtual ~RatchetTagSet () {}; virtual ~RatchetTagSet () {};
void DHInitialize (const uint8_t * rootKey, const uint8_t * k); void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
void NextSessionTagRatchet (); void NextSessionTagRatchet ();
uint64_t GetNextSessionTag (); uint64_t GetNextSessionTag ();
@ -57,14 +56,14 @@ namespace garlic
int GetTagSetID () const { return m_TagSetID; }; int GetTagSetID () const { return m_TagSetID; };
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; }; void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
private: private:
i2p::data::Tag<64> m_SessionTagKeyData; i2p::data::Tag<64> m_SessionTagKeyData;
uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32]; uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32];
int m_NextIndex, m_NextSymmKeyIndex; int m_NextIndex, m_NextSymmKeyIndex;
std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys; std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys;
int m_TagSetID = 0; int m_TagSetID = 0;
}; };
@ -74,27 +73,27 @@ namespace garlic
{ {
public: public:
ReceiveRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false): ReceiveRatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session, bool isNS = false):
m_Session (session), m_IsNS (isNS) {}; m_Session (session), m_IsNS (isNS) {};
bool IsNS () const { return m_IsNS; }; bool IsNS () const { return m_IsNS; };
std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session; }; std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session; };
void SetTrimBehind (int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; }; void SetTrimBehind (int index) { if (index > m_TrimBehindIndex) m_TrimBehindIndex = index; };
int GetTrimBehind () const { return m_TrimBehindIndex; }; int GetTrimBehind () const { return m_TrimBehindIndex; };
void Expire (); void Expire ();
bool IsExpired (uint64_t ts) const; bool IsExpired (uint64_t ts) const;
virtual bool IsIndexExpired (int index) const; virtual bool IsIndexExpired (int index) const;
virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index); virtual bool HandleNextMessage (uint8_t * buf, size_t len, int index);
private: private:
int m_TrimBehindIndex = 0; int m_TrimBehindIndex = 0;
std::shared_ptr<ECIESX25519AEADRatchetSession> m_Session; std::shared_ptr<ECIESX25519AEADRatchetSession> m_Session;
bool m_IsNS; bool m_IsNS;
uint64_t m_ExpirationTimestamp = 0; uint64_t m_ExpirationTimestamp = 0;
}; };
class SymmetricKeyTagSet: public ReceiveRatchetTagSet class SymmetricKeyTagSet: public ReceiveRatchetTagSet
{ {
@ -104,13 +103,13 @@ namespace garlic
bool IsIndexExpired (int index) const { return false; }; bool IsIndexExpired (int index) const { return false; };
bool HandleNextMessage (uint8_t * buf, size_t len, int index); bool HandleNextMessage (uint8_t * buf, size_t len, int index);
private: private:
GarlicDestination * m_Destination; GarlicDestination * m_Destination;
uint8_t m_Key[32]; uint8_t m_Key[32];
}; };
enum ECIESx25519BlockType enum ECIESx25519BlockType
{ {
eECIESx25519BlkDateTime = 0, eECIESx25519BlkDateTime = 0,
@ -128,7 +127,7 @@ namespace garlic
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02; const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04; const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
private i2p::crypto::NoiseSymmetricState, private i2p::crypto::NoiseSymmetricState,
public std::enable_shared_from_this<ECIESX25519AEADRatchetSession> public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
{ {
@ -158,10 +157,10 @@ namespace garlic
bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int index = 0); bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<ReceiveRatchetTagSet> receiveTagset, int index = 0);
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<I2NPMessage> WrapOneTimeMessage (std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapOneTimeMessage (std::shared_ptr<const I2NPMessage> msg);
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
void Terminate () { m_IsTerminated = true; } void Terminate () { m_IsTerminated = true; }
void SetDestination (const i2p::data::IdentHash& dest) // TODO: void SetDestination (const i2p::data::IdentHash& dest) // TODO:
{ {
@ -171,19 +170,19 @@ namespace garlic
bool CheckExpired (uint64_t ts); // true is expired bool CheckExpired (uint64_t ts); // true is expired
bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; } bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; }
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); } bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
bool IsRatchets () const { return true; }; bool IsRatchets () const { return true; };
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; }; bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
bool IsTerminated () const { return m_IsTerminated; } bool IsTerminated () const { return m_IsTerminated; }
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; }; uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
protected: protected:
i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; }; i2p::crypto::NoiseSymmetricState& GetNoiseState () { return *this; };
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; }; void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
void CreateNonce (uint64_t seqn, uint8_t * nonce); void CreateNonce (uint64_t seqn, uint8_t * nonce);
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index); void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
private: private:
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
@ -198,7 +197,7 @@ namespace garlic
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
size_t CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload); size_t CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first, uint8_t * payload);
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len); size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len);
size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len); size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len);
@ -213,7 +212,7 @@ namespace garlic
uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys; std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
SessionState m_State = eSessionStateNew; SessionState m_State = eSessionStateNew;
uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds) uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0, // incoming (in seconds)
m_LastSentTimestamp = 0; // in milliseconds m_LastSentTimestamp = 0; // in milliseconds
std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset; std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRSendTagset;
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
@ -221,7 +220,7 @@ namespace garlic
bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false; bool m_SendReverseKey = false, m_SendForwardKey = false, m_IsTerminated = false;
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet; std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
uint8_t m_PaddingSizes[32], m_NextPaddingSize; uint8_t m_PaddingSizes[32], m_NextPaddingSize;
public: public:
// for HTTP only // for HTTP only
@ -230,7 +229,7 @@ namespace garlic
{ {
return m_Destination ? *m_Destination : i2p::data::IdentHash (); return m_Destination ? *m_Destination : i2p::data::IdentHash ();
} }
}; };
// single session for all incoming messages // single session for all incoming messages
class RouterIncomingRatchetSession: public ECIESX25519AEADRatchetSession class RouterIncomingRatchetSession: public ECIESX25519AEADRatchetSession
@ -240,12 +239,12 @@ namespace garlic
RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState); RouterIncomingRatchetSession (const i2p::crypto::NoiseSymmetricState& initState);
bool HandleNextMessage (const uint8_t * buf, size_t len); bool HandleNextMessage (const uint8_t * buf, size_t len);
i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; }; i2p::crypto::NoiseSymmetricState& GetCurrentNoiseState () { return m_CurrentNoiseState; };
private: private:
i2p::crypto::NoiseSymmetricState m_CurrentNoiseState; i2p::crypto::NoiseSymmetricState m_CurrentNoiseState;
}; };
std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag); std::shared_ptr<I2NPMessage> WrapECIESX25519Message (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);
std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey); std::shared_ptr<I2NPMessage> WrapECIESX25519MessageForRouter (std::shared_ptr<const I2NPMessage> msg, const uint8_t * routerPublicKey);
} }

View File

@ -33,7 +33,7 @@ namespace crypto
BN_add (l, l, tmp); BN_add (l, l, tmp);
BN_sub_word (two_252_2, 2); // 2^252 - 2 BN_sub_word (two_252_2, 2); // 2^252 - 2
// -121665*inv(121666) // -121665*inv(121666)
d = BN_new (); d = BN_new ();
BN_set_word (tmp, 121666); BN_set_word (tmp, 121666);
BN_mod_inverse (tmp, tmp, q, ctx); BN_mod_inverse (tmp, tmp, q, ctx);
@ -61,7 +61,7 @@ namespace crypto
BN_mod (By, By, q, ctx); // % q BN_mod (By, By, q, ctx); // % q
// precalculate Bi256 table // precalculate Bi256 table
Bi256Carry = { Bx, By }; // B Bi256Carry = { Bx, By }; // B
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
{ {
Bi256[i][0] = Bi256Carry; // first point Bi256[i][0] = Bi256Carry; // first point
@ -215,7 +215,7 @@ namespace crypto
if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); } if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); }
if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); } if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); }
BN_mul (t3, t1, t2, ctx); BN_mul (t3, t1, t2, ctx);
BN_mul (t3, t3, d, ctx); // C = d*t1*t2 BN_mul (t3, t3, d, ctx); // C = d*t1*t2
if (p1.z) if (p1.z)
{ {
@ -264,9 +264,9 @@ namespace crypto
else else
{ {
BN_mul (t2, p.x, p.y, ctx); // t = x*y BN_mul (t2, p.x, p.y, ctx); // t = x*y
BN_sqr (t2, t2, ctx); // t2 = t^2 BN_sqr (t2, t2, ctx); // t2 = t^2
} }
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2 BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
if (p.z) if (p.z)
BN_sqr (z2, p.z, ctx); // z2 = D = z^2 BN_sqr (z2, p.z, ctx); // z2 = D = z^2
else else
@ -349,7 +349,7 @@ namespace crypto
BN_mod_inverse (y, p.z, q, ctx); BN_mod_inverse (y, p.z, q, ctx);
BN_mod_mul (x, p.x, y, q, ctx); // x = x/z BN_mod_mul (x, p.x, y, q, ctx); // x = x/z
BN_mod_mul (y, p.y, y, q, ctx); // y = y/z BN_mod_mul (y, p.y, y, q, ctx); // y = y/z
return EDDSAPoint{x, y}; return EDDSAPoint{x, y};
} }
else else
return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)}; return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)};
@ -506,13 +506,13 @@ namespace crypto
std::swap (z2, z3); std::swap (z2, z3);
} }
BN_mod_inverse (z2, z2, q, ctx); BN_mod_inverse (z2, z2, q, ctx);
BIGNUM * res = BN_new (); // not from ctx BIGNUM * res = BN_new (); // not from ctx
BN_mod_mul(res, x2, z2, q, ctx); BN_mod_mul(res, x2, z2, q, ctx);
BN_CTX_end (ctx); BN_CTX_end (ctx);
return res; return res;
} }
void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const void Ed25519::ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
{ {
BIGNUM * p1 = DecodeBN<32> (p); BIGNUM * p1 = DecodeBN<32> (p);
uint8_t k[32]; uint8_t k[32];
@ -524,7 +524,7 @@ namespace crypto
BN_free (p1); BN_free (n); BN_free (q1); BN_free (p1); BN_free (n); BN_free (q1);
} }
void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const void Ed25519::ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const
{ {
BIGNUM *p1 = BN_new (); BN_set_word (p1, 9); BIGNUM *p1 = BN_new (); BN_set_word (p1, 9);
uint8_t k[32]; uint8_t k[32];

View File

@ -85,8 +85,8 @@ namespace crypto
EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const;
void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const;
#if !OPENSSL_X25519 #if !OPENSSL_X25519
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
#endif #endif
void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 void BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32
void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32 void BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub); // for encrypted LeaseSet2, pub - 32, seed - 64, blinded - 32

View File

@ -189,7 +189,7 @@ namespace crypto
// assume a < p, so don't check for a % p = 0, but a = 0 only // assume a < p, so don't check for a % p = 0, but a = 0 only
if (BN_is_zero(a)) return 0; if (BN_is_zero(a)) return 0;
BIGNUM * r = BN_CTX_get (ctx); BIGNUM * r = BN_CTX_get (ctx);
BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p BN_mod_exp (r, a, p12, p, ctx); // r = a^((p-1)/2) mod p
if (BN_is_word(r, 1)) if (BN_is_word(r, 1))
return 1; return 1;
else if (BN_is_zero(r)) else if (BN_is_zero(r))

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, 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
* *
@ -60,10 +60,38 @@ namespace fs {
} }
void DetectDataDir(const std::string & cmdline_param, bool isService) { void DetectDataDir(const std::string & cmdline_param, bool isService) {
// with 'datadir' option
if (cmdline_param != "") { if (cmdline_param != "") {
dataDir = cmdline_param; dataDir = cmdline_param;
return; return;
} }
#if !defined(MAC_OSX) && !defined(ANDROID)
// with 'service' option
if (isService) {
#ifdef _WIN32
wchar_t commonAppData[MAX_PATH];
if(SHGetFolderPathW(NULL, CSIDL_COMMON_APPDATA, NULL, 0, commonAppData) != S_OK)
{
#ifdef WIN32_APP
MessageBox(NULL, TEXT("Unable to get common AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
#else
fprintf(stderr, "Error: Unable to get common AppData path!");
#endif
exit(1);
}
else
{
dataDir = boost::filesystem::wpath(commonAppData).string() + "\\" + appName;
}
#else
dataDir = "/var/lib/" + appName;
#endif
return;
}
#endif
// detect directory as usual
#ifdef _WIN32 #ifdef _WIN32
wchar_t localAppData[MAX_PATH]; wchar_t localAppData[MAX_PATH];
@ -117,12 +145,10 @@ namespace fs {
dataDir = std::string (ext) + "/" + appName; dataDir = std::string (ext) + "/" + appName;
return; return;
} }
#endif #endif // ANDROID
// otherwise use /data/files // use /home/user/.i2pd or /tmp/i2pd
char *home = getenv("HOME"); char *home = getenv("HOME");
if (isService) { if (home != NULL && strlen(home) > 0) {
dataDir = "/var/lib/" + appName;
} else if (home != NULL && strlen(home) > 0) {
dataDir = std::string(home) + "/." + appName; dataDir = std::string(home) + "/." + appName;
} else { } else {
dataDir = "/tmp/" + appName; dataDir = "/tmp/" + appName;

View File

@ -83,8 +83,8 @@ namespace fs {
/** /**
* @brief Set datadir either from cmdline option or using autodetection * @brief Set datadir either from cmdline option or using autodetection
* @param cmdline_param Value of cmdline parameter --datadir=<something> * @param cmdline_param Value of cmdline parameter --datadir=<something>
* @param isService Value of cmdline parameter --service * @param isService Value of cmdline parameter --service
* *
* Examples of autodetected paths: * Examples of autodetected paths:
* *
@ -93,11 +93,11 @@ namespace fs {
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/ * Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/
* Unix: /var/lib/i2pd/ (system=1) >> ~/.i2pd/ or /tmp/i2pd/ * Unix: /var/lib/i2pd/ (system=1) >> ~/.i2pd/ or /tmp/i2pd/
*/ */
void DetectDataDir(const std::string & cmdline_datadir, bool isService = false); void DetectDataDir(const std::string & cmdline_datadir, bool isService = false);
/** /**
* @brief Set certsdir either from cmdline option or using autodetection * @brief Set certsdir either from cmdline option or using autodetection
* @param cmdline_param Value of cmdline parameter --certsdir=<something> * @param cmdline_param Value of cmdline parameter --certsdir=<something>
* *
* Examples of autodetected paths: * Examples of autodetected paths:
* *
@ -106,7 +106,7 @@ namespace fs {
* Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/certificates * Mac: /Library/Application Support/i2pd/ or ~/Library/Application Support/i2pd/certificates
* Unix: /var/lib/i2pd/certificates (system=1) >> ~/.i2pd/ or /tmp/i2pd/certificates * Unix: /var/lib/i2pd/certificates (system=1) >> ~/.i2pd/ or /tmp/i2pd/certificates
*/ */
void SetCertsDir(const std::string & cmdline_certsdir); void SetCertsDir(const std::string & cmdline_certsdir);
/** /**
* @brief Create subdirectories inside datadir * @brief Create subdirectories inside datadir
@ -115,7 +115,7 @@ namespace fs {
/** /**
* @brief Get list of files in directory * @brief Get list of files in directory
* @param path Path to directory * @param path Path to directory
* @param files Vector to store found files * @param files Vector to store found files
* @return true on success and false if directory not exists * @return true on success and false if directory not exists
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, The PurpleI2P Project * Copyright (c) 2013-2022, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -88,7 +88,7 @@ namespace data
} }
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
if (verifier && cn) if (verifier && cn)
m_SigningKeys[cn] = verifier; m_SigningKeys.emplace (cn, std::make_pair(verifier, m_SigningKeys.size () + 1));
} }
SSL_free (ssl); SSL_free (ssl);
} }
@ -121,7 +121,7 @@ namespace data
} }
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident, bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key) const char * signature, const char * key) const
{ {
uint8_t buf[100], signatureBuf[64]; uint8_t buf[100], signatureBuf[64];
size_t len = family.length (), signatureLen = strlen (signature); size_t len = family.length (), signatureLen = strlen (signature);
@ -137,11 +137,19 @@ namespace data
Base64ToByteStream (signature, signatureLen, signatureBuf, 64); Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
auto it = m_SigningKeys.find (family); auto it = m_SigningKeys.find (family);
if (it != m_SigningKeys.end ()) if (it != m_SigningKeys.end ())
return it->second->Verify (buf, len, signatureBuf); return it->second.first->Verify (buf, len, signatureBuf);
// TODO: process key // TODO: process key
return true; return true;
} }
FamilyID Families::GetFamilyID (const std::string& family) const
{
auto it = m_SigningKeys.find (family);
if (it != m_SigningKeys.end ())
return it->second.second;
return 0;
}
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident) std::string CreateFamilySignature (const std::string& family, const IdentHash& ident)
{ {
auto filename = i2p::fs::DataDirPath("family", (family + ".key")); auto filename = i2p::fs::DataDirPath("family", (family + ".key"));

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, 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
* *
@ -19,6 +19,7 @@ namespace i2p
{ {
namespace data namespace data
{ {
typedef int FamilyID;
class Families class Families
{ {
public: public:
@ -27,7 +28,8 @@ namespace data
~Families (); ~Families ();
void LoadCertificates (); void LoadCertificates ();
bool VerifyFamily (const std::string& family, const IdentHash& ident, bool VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key = nullptr); const char * signature, const char * key = nullptr) const;
FamilyID GetFamilyID (const std::string& family) const;
private: private:
@ -35,7 +37,7 @@ namespace data
private: private:
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys; std::map<std::string, std::pair<std::shared_ptr<i2p::crypto::Verifier>, FamilyID> > m_SigningKeys; // family -> (verifier, id)
}; };
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident); std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -271,7 +271,7 @@ namespace garlic
(*numCloves)++; (*numCloves)++;
} }
} }
if (msg) // clove message ifself if presented if (msg) // clove message itself if presented
{ {
size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false);
(*numCloves)++; (*numCloves)++;
@ -293,14 +293,14 @@ namespace garlic
size_t size = 0; size_t size = 0;
if (isDestination) if (isDestination)
{ {
buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination
size++; size++;
memcpy (buf + size, m_Destination->GetIdentHash (), 32); memcpy (buf + size, m_Destination->GetIdentHash (), 32);
size += 32; size += 32;
} }
else else
{ {
buf[size] = 0;// delivery instructions flag local buf[size] = 0;// delivery instructions flag local
size++; size++;
} }
@ -452,7 +452,7 @@ namespace garlic
{ {
it.second->Terminate (); it.second->Terminate ();
it.second->SetOwner (nullptr); it.second->SetOwner (nullptr);
} }
m_ECIESx25519Sessions.clear (); m_ECIESx25519Sessions.clear ();
m_ECIESx25519Tags.clear (); m_ECIESx25519Tags.clear ();
} }
@ -470,27 +470,32 @@ namespace garlic
uint64_t t; uint64_t t;
memcpy (&t, tag, 8); memcpy (&t, tag, 8);
AddECIESx25519Key (key, t); AddECIESx25519Key (key, t);
} }
void GarlicDestination::AddECIESx25519Key (const uint8_t * key, uint64_t tag) void GarlicDestination::AddECIESx25519Key (const uint8_t * key, uint64_t tag)
{ {
auto tagset = std::make_shared<SymmetricKeyTagSet>(this, key); auto tagset = std::make_shared<SymmetricKeyTagSet>(this, key);
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{0, tagset}); m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{0, tagset});
} }
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
{ {
AddSessionKey (key, tag); AddSessionKey (key, tag);
return true; return true;
} }
void GarlicDestination::SubmitECIESx25519Key (const uint8_t * key, uint64_t tag)
{
AddECIESx25519Key (key, tag);
}
void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg) void GarlicDestination::HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg)
{ {
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
uint32_t length = bufbe32toh (buf); uint32_t length = bufbe32toh (buf);
if (length > msg->GetLength ()) if (length > msg->GetLength ())
{ {
LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ()); LogPrint (eLogWarning, "Garlic: Message length ", length, " exceeds I2NP message length ", msg->GetLength ());
return; return;
} }
auto mod = length & 0x0f; // %16 auto mod = length & 0x0f; // %16
@ -498,10 +503,10 @@ namespace garlic
bool found = false; bool found = false;
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
// try ECIESx25519 tag // try ECIESx25519 tag
found = HandleECIESx25519TagMessage (buf, length); found = HandleECIESx25519TagMessage (buf, length);
if (!found) if (!found)
{ {
auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16 auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16
// AES tag might be used even if encryption type is not ElGamal/AES // AES tag might be used even if encryption type is not ElGamal/AES
if (it != m_Tags.end ()) // try AES tag if (it != m_Tags.end ()) // try AES tag
@ -519,7 +524,7 @@ namespace garlic
found = true; found = true;
} }
else else
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes"); LogPrint (eLogWarning, "Garlic: Message length ", length, " is less than 32 bytes");
} }
if (!found) // assume new session if (!found) // assume new session
{ {
@ -542,37 +547,37 @@ namespace garlic
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
if (!session->HandleNextMessage (buf, length, nullptr, 0)) if (!session->HandleNextMessage (buf, length, nullptr, 0))
{ {
// try to gererate more tags for last tagset // try to generate more tags for last tagset
if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS)) if (m_LastTagset && (m_LastTagset->GetNextIndex () - m_LastTagset->GetTrimBehind () < 3*ECIESX25519_MAX_NUM_GENERATED_TAGS))
{ {
uint64_t missingTag; memcpy (&missingTag, buf, 8); uint64_t missingTag; memcpy (&missingTag, buf, 8);
auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS); auto maxTags = std::max (m_NumRatchetInboundTags, ECIESX25519_MAX_NUM_GENERATED_TAGS);
LogPrint (eLogWarning, "Garlic: trying to generate more ECIES-X25519-AEAD-Ratchet tags"); LogPrint (eLogWarning, "Garlic: Trying to generate more ECIES-X25519-AEAD-Ratchet tags");
for (int i = 0; i < maxTags; i++) for (int i = 0; i < maxTags; i++)
{ {
auto nextTag = AddECIESx25519SessionNextTag (m_LastTagset); auto nextTag = AddECIESx25519SessionNextTag (m_LastTagset);
if (!nextTag) if (!nextTag)
{ {
LogPrint (eLogError, "Garlic: can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset"); LogPrint (eLogError, "Garlic: Can't create new ECIES-X25519-AEAD-Ratchet tag for last tagset");
break; break;
} }
if (nextTag == missingTag) if (nextTag == missingTag)
{ {
LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated"); LogPrint (eLogDebug, "Garlic: Missing ECIES-X25519-AEAD-Ratchet tag was generated");
if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[nextTag].index)) if (m_LastTagset->HandleNextMessage (buf, length, m_ECIESx25519Tags[nextTag].index))
found = true; found = true;
break; break;
} }
} }
if (!found) m_LastTagset = nullptr; if (!found) m_LastTagset = nullptr;
} }
if (!found) if (!found)
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
} }
} }
else else
LogPrint (eLogError, "Garlic: Failed to decrypt message"); LogPrint (eLogError, "Garlic: Failed to decrypt message");
} }
} }
} }
@ -585,14 +590,14 @@ namespace garlic
{ {
if (it->second.tagset->HandleNextMessage (buf, len, it->second.index)) if (it->second.tagset->HandleNextMessage (buf, len, it->second.index))
m_LastTagset = it->second.tagset; m_LastTagset = it->second.tagset;
else else
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message"); LogPrint (eLogError, "Garlic: Can't handle ECIES-X25519-AEAD-Ratchet message");
m_ECIESx25519Tags.erase (it); m_ECIESx25519Tags.erase (it);
return true; return true;
} }
return false; return false;
} }
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption, void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from) std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
@ -629,7 +634,7 @@ namespace garlic
SHA256 (buf, payloadSize, digest); SHA256 (buf, payloadSize, digest);
if (memcmp (payloadHash, digest, 32)) // payload hash doesn't match if (memcmp (payloadHash, digest, 32)) // payload hash doesn't match
{ {
LogPrint (eLogError, "Garlic: wrong payload hash"); LogPrint (eLogError, "Garlic: Wrong payload hash");
return; return;
} }
HandleGarlicPayload (buf, payloadSize, from); HandleGarlicPayload (buf, payloadSize, from);
@ -639,7 +644,7 @@ namespace garlic
{ {
if (len < 1) if (len < 1)
{ {
LogPrint (eLogError, "Garlic: payload is too short"); LogPrint (eLogError, "Garlic: Payload is too short");
return; return;
} }
int numCloves = buf[0]; int numCloves = buf[0];
@ -654,7 +659,7 @@ namespace garlic
if (flag & 0x80) // encrypted? if (flag & 0x80) // encrypted?
{ {
// TODO: implement // TODO: implement
LogPrint (eLogWarning, "Garlic: clove encrypted"); LogPrint (eLogWarning, "Garlic: Clove encrypted");
buf += 32; buf += 32;
} }
ptrdiff_t offset = buf - buf1; ptrdiff_t offset = buf - buf1;
@ -662,35 +667,35 @@ namespace garlic
switch (deliveryType) switch (deliveryType)
{ {
case eGarlicDeliveryTypeLocal: case eGarlicDeliveryTypeLocal:
LogPrint (eLogDebug, "Garlic: type local"); LogPrint (eLogDebug, "Garlic: Type local");
if (offset > (int)len) if (offset > (int)len)
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: Message is too short");
break; break;
} }
HandleI2NPMessage (buf, len - offset); HandleI2NPMessage (buf, len - offset);
break; break;
case eGarlicDeliveryTypeDestination: case eGarlicDeliveryTypeDestination:
LogPrint (eLogDebug, "Garlic: type destination"); LogPrint (eLogDebug, "Garlic: Type destination");
buf += 32; // destination. check it later or for multiple destinations buf += 32; // destination. check it later or for multiple destinations
offset = buf - buf1; offset = buf - buf1;
if (offset > (int)len) if (offset > (int)len)
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: Message is too short");
break; break;
} }
HandleI2NPMessage (buf, len - offset); HandleI2NPMessage (buf, len - offset);
break; break;
case eGarlicDeliveryTypeTunnel: case eGarlicDeliveryTypeTunnel:
{ {
LogPrint (eLogDebug, "Garlic: type tunnel"); LogPrint (eLogDebug, "Garlic: Type tunnel");
// gwHash and gwTunnel sequence is reverted // gwHash and gwTunnel sequence is reverted
uint8_t * gwHash = buf; uint8_t * gwHash = buf;
buf += 32; buf += 32;
offset = buf - buf1; offset = buf - buf1;
if (offset + 4 > (int)len) if (offset + 4 > (int)len)
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: Message is too short");
break; break;
} }
uint32_t gwTunnel = bufbe32toh (buf); uint32_t gwTunnel = bufbe32toh (buf);
@ -721,32 +726,32 @@ namespace garlic
{ {
if (offset > (int)len) if (offset > (int)len)
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: Message is too short");
break; break;
} }
i2p::transport::transports.SendMessage (ident, i2p::transport::transports.SendMessage (ident,
CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len - offset))); CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len - offset)));
} }
else else
LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported"); LogPrint (eLogWarning, "Garlic: Type router for inbound tunnels not supported");
break; break;
} }
default: default:
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType); LogPrint (eLogWarning, "Garlic: Unknown delivery type ", (int)deliveryType);
} }
if (offset > (int)len) if (offset > (int)len)
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: Message is too short");
break; break;
} }
buf += GetI2NPMessageLength (buf, len - offset); // I2NP buf += GetI2NPMessageLength (buf, len - offset); // I2NP
buf += 4; // CloveID buf += 4; // CloveID
buf += 8; // Date buf += 8; // Date
buf += 3; // Certificate buf += 3; // Certificate
offset = buf - buf1; offset = buf - buf1;
if (offset > (int)len) if (offset > (int)len)
{ {
LogPrint (eLogError, "Garlic: clove is too long"); LogPrint (eLogError, "Garlic: Clove is too long");
break; break;
} }
len -= offset; len -= offset;
@ -759,10 +764,10 @@ namespace garlic
if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
return WrapECIESX25519MessageForRouter (msg, router->GetIdentity ()->GetEncryptionPublicKey ()); return WrapECIESX25519MessageForRouter (msg, router->GetIdentity ()->GetEncryptionPublicKey ());
else else
{ {
auto session = GetRoutingSession (router, false); auto session = GetRoutingSession (router, false);
return session->WrapSingleMessage (msg); return session->WrapSingleMessage (msg);
} }
} }
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession ( std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
@ -776,14 +781,14 @@ namespace garlic
destination->Encrypt (nullptr, staticKey); // we are supposed to get static key destination->Encrypt (nullptr, staticKey); // we are supposed to get static key
auto it = m_ECIESx25519Sessions.find (staticKey); auto it = m_ECIESx25519Sessions.find (staticKey);
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
{ {
session = it->second; session = it->second;
if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ())) if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ()))
{ {
LogPrint (eLogDebug, "Garlic: session restarted"); LogPrint (eLogDebug, "Garlic: Session restarted");
session = nullptr; session = nullptr;
} }
} }
if (!session) if (!session)
{ {
session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true); session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
@ -840,7 +845,7 @@ namespace garlic
it->second->GetSharedRoutingPath (); // delete shared path if necessary it->second->GetSharedRoutingPath (); // delete shared path if necessary
if (!it->second->CleanupExpiredTags ()) if (!it->second->CleanupExpiredTags ())
{ {
LogPrint (eLogInfo, "Routing session to ", it->first.ToBase32 (), " deleted"); LogPrint (eLogInfo, "Garlic: Routing session to ", it->first.ToBase32 (), " deleted");
it->second->SetOwner (nullptr); it->second->SetOwner (nullptr);
it = m_Sessions.erase (it); it = m_Sessions.erase (it);
} }
@ -879,18 +884,18 @@ namespace garlic
it->second.tagset->DeleteSymmKey (it->second.index); it->second.tagset->DeleteSymmKey (it->second.index);
it = m_ECIESx25519Tags.erase (it); it = m_ECIESx25519Tags.erase (it);
numExpiredTags++; numExpiredTags++;
} }
else else
{ {
auto session = it->second.tagset->GetSession (); auto session = it->second.tagset->GetSession ();
if (!session || session->IsTerminated()) if (!session || session->IsTerminated())
{ {
it = m_ECIESx25519Tags.erase (it); it = m_ECIESx25519Tags.erase (it);
numExpiredTags++; numExpiredTags++;
} }
else else
++it; ++it;
} }
} }
if (numExpiredTags > 0) if (numExpiredTags > 0)
LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ()); LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " ECIESx25519 tags expired for ", GetIdentHash().ToBase64 ());
@ -925,7 +930,7 @@ namespace garlic
if (session) if (session)
{ {
session->MessageConfirmed (msgID); session->MessageConfirmed (msgID);
LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged"); LogPrint (eLogDebug, "Garlic: Message ", msgID, " acknowledged");
} }
} }
@ -1019,7 +1024,7 @@ namespace garlic
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: files) for (auto it: files)
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT) if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
i2p::fs::Remove (it); i2p::fs::Remove (it);
} }
void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len)
@ -1030,7 +1035,7 @@ namespace garlic
switch (deliveryType) switch (deliveryType)
{ {
case eGarlicDeliveryTypeDestination: case eGarlicDeliveryTypeDestination:
LogPrint (eLogDebug, "Garlic: type destination"); LogPrint (eLogDebug, "Garlic: Type destination");
buf += 32; // TODO: check destination buf += 32; // TODO: check destination
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]]; [[fallthrough]];
@ -1038,7 +1043,7 @@ namespace garlic
// no break here // no break here
case eGarlicDeliveryTypeLocal: case eGarlicDeliveryTypeLocal:
{ {
LogPrint (eLogDebug, "Garlic: type local"); LogPrint (eLogDebug, "Garlic: Type local");
I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid I2NPMessageType typeID = (I2NPMessageType)(buf[0]); buf++; // typeid
int32_t msgID = bufbe32toh (buf); buf += 4; // msgID int32_t msgID = bufbe32toh (buf); buf += 4; // msgID
buf += 4; // expiration buf += 4; // expiration
@ -1046,19 +1051,19 @@ namespace garlic
if (offset <= (int)len) if (offset <= (int)len)
HandleCloveI2NPMessage (typeID, buf, len - offset, msgID); HandleCloveI2NPMessage (typeID, buf, len - offset, msgID);
else else
LogPrint (eLogError, "Garlic: clove is too long"); LogPrint (eLogError, "Garlic: Clove is too long");
break; break;
} }
case eGarlicDeliveryTypeTunnel: case eGarlicDeliveryTypeTunnel:
{ {
LogPrint (eLogDebug, "Garlic: type tunnel"); LogPrint (eLogDebug, "Garlic: Type tunnel");
// gwHash and gwTunnel sequence is reverted // gwHash and gwTunnel sequence is reverted
const uint8_t * gwHash = buf; const uint8_t * gwHash = buf;
buf += 32; buf += 32;
ptrdiff_t offset = buf - buf1; ptrdiff_t offset = buf - buf1;
if (offset + 13 > (int)len) if (offset + 13 > (int)len)
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: Message is too short");
break; break;
} }
uint32_t gwTunnel = bufbe32toh (buf); buf += 4; uint32_t gwTunnel = bufbe32toh (buf); buf += 4;
@ -1079,7 +1084,7 @@ namespace garlic
break; break;
} }
default: default:
LogPrint (eLogWarning, "Garlic: unexpected delivery type ", (int)deliveryType); LogPrint (eLogWarning, "Garlic: Unexpected delivery type ", (int)deliveryType);
} }
} }
@ -1099,13 +1104,13 @@ namespace garlic
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
{ {
if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ())) if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ()))
{ {
it->second->Terminate (); // detach it->second->Terminate (); // detach
m_ECIESx25519Sessions.erase (it); m_ECIESx25519Sessions.erase (it);
} }
else else
{ {
LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists"); LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists");
return; return;
} }
} }
@ -1127,6 +1132,6 @@ namespace garlic
if (!m_PayloadBuffer) if (!m_PayloadBuffer)
m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE]; m_PayloadBuffer = new uint8_t[I2NP_MAX_MESSAGE_SIZE];
return m_PayloadBuffer; return m_PayloadBuffer;
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -115,7 +115,7 @@ namespace garlic
virtual bool MessageConfirmed (uint32_t msgID); virtual bool MessageConfirmed (uint32_t msgID);
virtual bool IsRatchets () const { return false; }; virtual bool IsRatchets () const { return false; };
virtual bool IsReadyToSend () const { return true; }; virtual bool IsReadyToSend () const { return true; };
virtual bool IsTerminated () const { return !GetOwner (); }; virtual bool IsTerminated () const { return !GetOwner (); };
virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only
void SetLeaseSetUpdated () void SetLeaseSetUpdated ()
@ -245,13 +245,14 @@ namespace garlic
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag void AddECIESx25519Key (const uint8_t * key, uint64_t tag); // one tag
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
virtual void SubmitECIESx25519Key (const uint8_t * key, uint64_t tag); // from different thread
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID); void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
uint64_t AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset); uint64_t AddECIESx25519SessionNextTag (ReceiveRatchetTagSetPtr tagset);
void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session);
void RemoveECIESx25519Session (const uint8_t * staticKey); void RemoveECIESx25519Session (const uint8_t * staticKey);
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
uint8_t * GetPayloadBuffer (); uint8_t * GetPayloadBuffer ();
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
virtual void SetLeaseSetUpdated (); virtual void SetLeaseSetUpdated ();

View File

@ -96,7 +96,7 @@ namespace crypto
EC_POINT * C = EC_POINT_new (m_Group); EC_POINT * C = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub
BIGNUM * x = BN_CTX_get (ctx); BIGNUM * x = BN_CTX_get (ctx);
GetXY (C, x, nullptr); // Cx GetXY (C, x, nullptr); // Cx
BN_mod (x, x, q, ctx); // Cx % q BN_mod (x, x, q, ctx); // Cx % q
bool ret = !BN_cmp (x, r); // Cx = r ? bool ret = !BN_cmp (x, r); // Cx = r ?
EC_POINT_free (C); EC_POINT_free (C);
@ -111,8 +111,8 @@ namespace crypto
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BN_CTX_start (ctx); BN_CTX_start (ctx);
EC_POINT * C = EC_POINT_new (m_Group); // C = k*P = (rx, ry) EC_POINT * C = EC_POINT_new (m_Group); // C = k*P = (rx, ry)
EC_POINT * Q = nullptr; EC_POINT * Q = nullptr;
if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx)) if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx))
{ {
EC_POINT * S = EC_POINT_new (m_Group); // S = s*P EC_POINT * S = EC_POINT_new (m_Group); // S = s*P
EC_POINT_mul (m_Group, S, s, nullptr, nullptr, ctx); EC_POINT_mul (m_Group, S, s, nullptr, nullptr, ctx);

View File

@ -14,9 +14,9 @@
#include "Base.h" #include "Base.h"
#include "HTTP.h" #include "HTTP.h"
namespace i2p namespace i2p
{ {
namespace http namespace http
{ {
const std::vector<std::string> HTTP_METHODS = { const std::vector<std::string> HTTP_METHODS = {
"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "CONNECT", // HTTP basic methods
@ -279,7 +279,7 @@ namespace http
method = tokens[0]; method = tokens[0];
uri = tokens[1]; uri = tokens[1];
version = tokens[2]; version = tokens[2];
expect = HEADER_LINE; expect = HEADER_LINE;
} }
else else
{ {
@ -363,7 +363,7 @@ namespace http
return false; /* no header */ return false; /* no header */
if (it->second.find("gzip") != std::string::npos) if (it->second.find("gzip") != std::string::npos)
return true; /* gotcha! */ return true; /* gotcha! */
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos) if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
return true; return true;
return false; return false;
} }
@ -409,7 +409,7 @@ namespace http
/* all ok */ /* all ok */
version = tokens[0]; version = tokens[0];
status = tokens[2]; status = tokens[2];
expect = HEADER_LINE; expect = HEADER_LINE;
} else { } else {
std::string line = str.substr(pos, eol - pos); std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
@ -460,7 +460,7 @@ namespace http
case 304: ptr = "Not Modified"; break; case 304: ptr = "Not Modified"; break;
case 307: ptr = "Temporary Redirect"; break; case 307: ptr = "Temporary Redirect"; break;
/* client error */ /* client error */
case 400: ptr = "Bad Request"; break; case 400: ptr = "Bad Request"; break;
case 401: ptr = "Unauthorized"; break; case 401: ptr = "Unauthorized"; break;
case 403: ptr = "Forbidden"; break; case 403: ptr = "Forbidden"; break;
case 404: ptr = "Not Found"; break; case 404: ptr = "Not Found"; break;
@ -471,19 +471,19 @@ namespace http
case 502: ptr = "Bad Gateway"; break; case 502: ptr = "Bad Gateway"; break;
case 503: ptr = "Not Implemented"; break; case 503: ptr = "Not Implemented"; break;
case 504: ptr = "Gateway Timeout"; break; case 504: ptr = "Gateway Timeout"; break;
default: ptr = "Unknown Status"; break; default: ptr = "Unknown Status"; break;
} }
return ptr; return ptr;
} }
std::string UrlDecode(const std::string& data, bool allow_null) std::string UrlDecode(const std::string& data, bool allow_null)
{ {
std::string decoded(data); std::string decoded(data);
size_t pos = 0; size_t pos = 0;
while ((pos = decoded.find('%', pos)) != std::string::npos) while ((pos = decoded.find('%', pos)) != std::string::npos)
{ {
char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16); char c = strtol(decoded.substr(pos + 1, 2).c_str(), NULL, 16);
if (c == '\0' && !allow_null) if (c == '\0' && !allow_null)
{ {
pos += 3; pos += 3;
continue; continue;
@ -494,10 +494,10 @@ namespace http
return decoded; return decoded;
} }
bool MergeChunkedResponse (std::istream& in, std::ostream& out) bool MergeChunkedResponse (std::istream& in, std::ostream& out)
{ {
std::string hexLen; std::string hexLen;
while (!in.eof ()) while (!in.eof ())
{ {
std::getline (in, hexLen); std::getline (in, hexLen);
errno = 0; errno = 0;
@ -522,6 +522,6 @@ namespace http
if (user.empty () && pass.empty ()) return ""; if (user.empty () && pass.empty ()) return "";
return "Basic " + i2p::data::ToBase64Standard (user + ":" + pass); return "Basic " + i2p::data::ToBase64Standard (user + ":" + pass);
} }
} // http } // http
} // i2p } // i2p

View File

@ -161,14 +161,14 @@ namespace http
/** /**
* @brief Merge HTTP response content with Transfer-Encoding: chunked * @brief Merge HTTP response content with Transfer-Encoding: chunked
* @param in Input stream * @param in Input stream
* @param out Output stream * @param out Output stream
* @return true on success, false otherwise * @return true on success, false otherwise
*/ */
bool MergeChunkedResponse (std::istream& in, std::ostream& out); bool MergeChunkedResponse (std::istream& in, std::ostream& out);
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass); std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass);
} // http } // http
} // i2p } // i2p

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -38,20 +38,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint) std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (bool endpoint)
{ {
I2NPMessage * msg = nullptr; return i2p::tunnel::tunnels.NewI2NPTunnelMessage (endpoint);
if (endpoint)
{
// should fit two tunnel message + tunnel gateway header, enough for one garlic encrypted streaming packet
msg = new I2NPMessageBuffer<2*i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE + 28>(); // reserved for alignment and NTCP 16 + 6 + 6
msg->Align (6);
msg->offset += TUNNEL_GATEWAY_HEADER_SIZE; // reserve room for TunnelGateway header
}
else
{
msg = new I2NPMessageBuffer<i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34>(); // reserved for alignment and NTCP 16 + 6 + 12
msg->Align (12);
}
return std::shared_ptr<I2NPMessage>(msg);
} }
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len) std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
@ -88,7 +75,7 @@ namespace i2p
{ {
auto msg = NewI2NPMessage (len); auto msg = NewI2NPMessage (len);
if (msg->Concat (buf, len) < len) if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen); LogPrint (eLogError, "I2NP: Message length ", len, " exceeds max length ", msg->maxLen);
msg->FillI2NPMessageHeader (msgType, replyMsgID); msg->FillI2NPMessageHeader (msgType, replyMsgID);
return msg; return msg;
} }
@ -103,7 +90,7 @@ namespace i2p
msg->from = from; msg->from = from;
} }
else else
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length"); LogPrint (eLogError, "I2NP: Message length ", len, " exceeds max length");
return msg; return msg;
} }
@ -183,8 +170,8 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey,
const uint8_t * replyTag, bool replyECIES) const uint8_t * replyTag, bool replyECIES)
{ {
int cnt = excludedFloodfills.size (); int cnt = excludedFloodfills.size ();
auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage (); auto m = cnt > 7 ? NewI2NPMessage () : NewI2NPShortMessage ();
@ -256,7 +243,7 @@ namespace i2p
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router, std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router,
uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel) uint32_t replyToken, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel)
{ {
if (!router) // we send own RouterInfo if (!router) // we send own RouterInfo
@ -411,7 +398,7 @@ namespace i2p
retCode = 30; // always reject with bandwidth reason (30) retCode = 30; // always reject with bandwidth reason (30)
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
// encrypt reply // encrypt reply
i2p::crypto::CBCEncryption encryption; i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++) for (int j = 0; j < num; j++)
@ -422,7 +409,7 @@ namespace i2p
uint8_t nonce[12]; uint8_t nonce[12];
memset (nonce, 0, 12); memset (nonce, 0, 12);
auto& noiseState = i2p::context.GetCurrentNoiseState (); auto& noiseState = i2p::context.GetCurrentNoiseState ();
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, if (!i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt noiseState.m_H, 32, noiseState.m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{ {
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed"); LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
@ -560,7 +547,7 @@ namespace i2p
{ {
LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours"); LogPrint (eLogDebug, "I2NP: Short request record ", i, " is ours");
uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[SHORT_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText)) if (!i2p::context.DecryptTunnelShortRequestRecord (record + SHORT_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText))
{ {
LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i); LogPrint (eLogWarning, "I2NP: Can't decrypt short request record ", i);
return; return;
@ -571,10 +558,10 @@ namespace i2p
return; return;
} }
auto& noiseState = i2p::context.GetCurrentNoiseState (); auto& noiseState = i2p::context.GetCurrentNoiseState ();
uint8_t replyKey[32], layerKey[32], ivKey[32]; uint8_t replyKey[32], layerKey[32], ivKey[32];
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK); i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelReplyKey", noiseState.m_CK);
memcpy (replyKey, noiseState.m_CK + 32, 32); memcpy (replyKey, noiseState.m_CK + 32, 32);
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK); i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "SMTunnelLayerKey", noiseState.m_CK);
memcpy (layerKey, noiseState.m_CK + 32, 32); memcpy (layerKey, noiseState.m_CK + 32, 32);
bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG; bool isEndpoint = clearText[SHORT_REQUEST_RECORD_FLAG_OFFSET] & TUNNEL_BUILD_RECORD_ENDPOINT_FLAG;
if (isEndpoint) if (isEndpoint)
@ -615,8 +602,8 @@ namespace i2p
if (j == i) if (j == i)
{ {
memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options memset (reply + SHORT_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode; reply[SHORT_RESPONSE_RECORD_RET_OFFSET] = retCode;
if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16, if (!i2p::crypto::AEADChaCha20Poly1305 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE - 16,
noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt noiseState.m_H, 32, replyKey, nonce, reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
{ {
LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed"); LogPrint (eLogWarning, "I2NP: Short reply AEAD encryption failed");
@ -624,7 +611,7 @@ namespace i2p
} }
} }
else else
i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply); i2p::crypto::ChaCha20 (reply, SHORT_TUNNEL_BUILD_RECORD_SIZE, replyKey, nonce, reply);
reply += SHORT_TUNNEL_BUILD_RECORD_SIZE; reply += SHORT_TUNNEL_BUILD_RECORD_SIZE;
} }
// send reply // send reply
@ -633,16 +620,16 @@ namespace i2p
auto replyMsg = NewI2NPShortMessage (); auto replyMsg = NewI2NPShortMessage ();
replyMsg->Concat (buf, len); replyMsg->Concat (buf, len);
replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET)); replyMsg->FillI2NPMessageHeader (eI2NPShortTunnelBuildReply, bufbe32toh (clearText + SHORT_REQUEST_RECORD_SEND_MSG_ID_OFFSET));
if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (), if (memcmp ((const uint8_t *)i2p::context.GetIdentHash (),
clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local? clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, 32)) // reply IBGW is not local?
{ {
i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK); i2p::crypto::HKDF (noiseState.m_CK, nullptr, 0, "RGarlicKeyAndTag", noiseState.m_CK);
uint64_t tag; uint64_t tag;
memcpy (&tag, noiseState.m_CK, 8); memcpy (&tag, noiseState.m_CK, 8);
// we send it to reply tunnel // we send it to reply tunnel
transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + SHORT_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg (bufbe32toh (clearText + SHORT_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag))); i2p::garlic::WrapECIESX25519Message (replyMsg, noiseState.m_CK + 32, tag)));
} }
else else
{ {
@ -698,7 +685,7 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->len += TUNNEL_GATEWAY_HEADER_SIZE; msg->len += TUNNEL_GATEWAY_HEADER_SIZE;
if (msg->Concat (buf, len) < len) if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen); LogPrint (eLogError, "I2NP: Tunnel gateway buffer overflow ", msg->maxLen);
msg->FillI2NPMessageHeader (eI2NPTunnelGateway); msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg; return msg;
} }
@ -729,7 +716,7 @@ namespace i2p
msg->offset += gatewayMsgOffset; msg->offset += gatewayMsgOffset;
msg->len += gatewayMsgOffset; msg->len += gatewayMsgOffset;
if (msg->Concat (buf, len) < len) if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen); LogPrint (eLogError, "I2NP: Tunnel gateway buffer overflow ", msg->maxLen);
msg->FillI2NPMessageHeader (msgType, replyMsgID); // create content message msg->FillI2NPMessageHeader (msgType, replyMsgID); // create content message
len = msg->GetLength (); len = msg->GetLength ();
msg->offset -= gatewayMsgOffset; msg->offset -= gatewayMsgOffset;
@ -744,13 +731,13 @@ namespace i2p
{ {
if (len < I2NP_HEADER_SIZE_OFFSET + 2) if (len < I2NP_HEADER_SIZE_OFFSET + 2)
{ {
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header"); LogPrint (eLogError, "I2NP: Message length ", len, " is smaller than header");
return len; return len;
} }
auto l = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE; auto l = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE;
if (l > len) if (l > len)
{ {
LogPrint (eLogError, "I2NP: message length ", l, " exceeds buffer length ", len); LogPrint (eLogError, "I2NP: Message length ", l, " exceeds buffer length ", len);
l = len; l = len;
} }
return l; return l;
@ -760,18 +747,18 @@ namespace i2p
{ {
if (len < I2NP_HEADER_SIZE) if (len < I2NP_HEADER_SIZE)
{ {
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header"); LogPrint (eLogError, "I2NP: Message length ", len, " is smaller than header");
return; return;
} }
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET]; uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET); uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID); LogPrint (eLogDebug, "I2NP: Msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
uint8_t * buf = msg + I2NP_HEADER_SIZE; uint8_t * buf = msg + I2NP_HEADER_SIZE;
auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET); auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
len -= I2NP_HEADER_SIZE; len -= I2NP_HEADER_SIZE;
if (size > len) if (size > len)
{ {
LogPrint (eLogError, "I2NP: payload size ", size, " exceeds buffer length ", len); LogPrint (eLogError, "I2NP: Payload size ", size, " exceeds buffer length ", len);
size = len; size = len;
} }
switch (typeID) switch (typeID)
@ -815,13 +802,8 @@ namespace i2p
break; break;
case eI2NPGarlic: case eI2NPGarlic:
{ {
if (msg->from) if (msg->from && msg->from->GetTunnelPool ())
{ msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
if (msg->from->GetTunnelPool ())
msg->from->GetTunnelPool ()->ProcessGarlicMessage (msg);
else
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
}
else else
i2p::context.ProcessGarlicMessage (msg); i2p::context.ProcessGarlicMessage (msg);
break; break;
@ -860,7 +842,7 @@ namespace i2p
Flush (); Flush ();
} }
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg) void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage>&& msg)
{ {
if (msg) if (msg)
{ {

View File

@ -56,7 +56,7 @@ namespace i2p
// TunnelBuild // TunnelBuild
const size_t TUNNEL_BUILD_RECORD_SIZE = 528; const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 218; const size_t SHORT_TUNNEL_BUILD_RECORD_SIZE = 218;
// BuildRequestRecordEncrypted // BuildRequestRecordEncrypted
const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0; const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0;
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16; const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
@ -98,7 +98,7 @@ namespace i2p
// ShortResponseRecord // ShortResponseRecord
const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0; const size_t SHORT_RESPONSE_RECORD_OPTIONS_OFFSET = 0;
const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201; const size_t SHORT_RESPONSE_RECORD_RET_OFFSET = 201;
enum I2NPMessageType enum I2NPMessageType
{ {
eI2NPDummyMsg = 0, eI2NPDummyMsg = 0,
@ -150,7 +150,7 @@ namespace tunnel
std::shared_ptr<i2p::tunnel::InboundTunnel> from; std::shared_ptr<i2p::tunnel::InboundTunnel> from;
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2), I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
// header accessors // header accessors
uint8_t * GetHeader () { return GetBuffer (); }; uint8_t * GetHeader () { return GetBuffer (); };
@ -273,9 +273,9 @@ namespace tunnel
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr); uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel,
const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false); const uint8_t * replyKey, const uint8_t * replyTag, bool replyECIES = false);
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers); std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr); std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
@ -301,7 +301,7 @@ namespace tunnel
public: public:
~I2NPMessagesHandler (); ~I2NPMessagesHandler ();
void PutNextMessage (std::shared_ptr<I2NPMessage> msg); void PutNextMessage (std::shared_ptr<I2NPMessage>&& msg);
void Flush (); void Flush ();
private: private:

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, The PurpleI2P Project * Copyright (c) 2013-2022, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -50,42 +50,3 @@ uint64_t be64toh(uint64_t big64)
return u64.raw_value; return u64.raw_value;
} }
#endif #endif
/* it can be used in Windows 8
#include <Winsock2.h>
uint16_t htobe16(uint16_t int16)
{
return htons(int16);
}
uint32_t htobe32(uint32_t int32)
{
return htonl(int32);
}
uint64_t htobe64(uint64_t int64)
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
//return htonll(int64);
return 0;
}
uint16_t be16toh(uint16_t big16)
{
return ntohs(big16);
}
uint32_t be32toh(uint32_t big32)
{
return ntohl(big32);
}
uint64_t be64toh(uint64_t big64)
{
// http://msdn.microsoft.com/en-us/library/windows/desktop/jj710199%28v=vs.85%29.aspx
//return ntohll(big64);
return 0;
}
*/

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2020, The PurpleI2P Project * Copyright (c) 2013-2022, The PurpleI2P Project
* *
* This file is part of Purple i2pd project and licensed under BSD3 * This file is part of Purple i2pd project and licensed under BSD3
* *
@ -13,10 +13,11 @@
#if defined(__FreeBSD__) || defined(__NetBSD__) #if defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/endian.h> #include <sys/endian.h>
#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__) #elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__GLIBC__)
#include <endian.h> #include <endian.h>
#elif defined(__APPLE__) && defined(__MACH__)
#elif defined(__APPLE__) && defined(__MACH__)
#include <libkern/OSByteOrder.h> #include <libkern/OSByteOrder.h>
#define htobe16(x) OSSwapHostToBigInt16(x) #define htobe16(x) OSSwapHostToBigInt16(x)
@ -34,6 +35,22 @@
#define be64toh(x) OSSwapBigToHostInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x)
#define le64toh(x) OSSwapLittleToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x)
#elif defined(_WIN32)
#define htobe16(x) __builtin_bswap16(x)
#define htole16(x) (x)
#define be16toh(x) __builtin_bswap16(x)
#define le16toh(x) (x)
#define htobe32(x) __builtin_bswap32(x)
#define htole32(x) (x)
#define be32toh(x) __builtin_bswap32(x)
#define le32toh(x) (x)
#define htobe64(x) __builtin_bswap64(x)
#define htole64(x) (x)
#define be64toh(x) __builtin_bswap64(x)
#define le64toh(x) (x)
#else #else
#define NEEDS_LOCAL_ENDIAN #define NEEDS_LOCAL_ENDIAN
#include <cstdint> #include <cstdint>

View File

@ -19,7 +19,8 @@ namespace data
Identity& Identity::operator=(const Keys& keys) Identity& Identity::operator=(const Keys& keys)
{ {
// copy public and signing keys together // copy public and signing keys together
memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey)); memcpy (publicKey, keys.publicKey, sizeof (publicKey));
memcpy (signingKey, keys.signingKey, sizeof (signingKey));
memset (certificate, 0, sizeof (certificate)); memset (certificate, 0, sizeof (certificate));
return *this; return *this;
} }
@ -52,9 +53,9 @@ namespace data
{ {
memcpy (m_StandardIdentity.publicKey, publicKey, 32); memcpy (m_StandardIdentity.publicKey, publicKey, 32);
RAND_bytes (m_StandardIdentity.publicKey + 32, 224); RAND_bytes (m_StandardIdentity.publicKey + 32, 224);
} }
else else
memcpy (m_StandardIdentity.publicKey, publicKey, 256); memcpy (m_StandardIdentity.publicKey, publicKey, 256);
if (type != SIGNING_KEY_TYPE_DSA_SHA1) if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{ {
size_t excessLen = 0; size_t excessLen = 0;
@ -63,7 +64,7 @@ namespace data
{ {
case SIGNING_KEY_TYPE_ECDSA_SHA256_P256: case SIGNING_KEY_TYPE_ECDSA_SHA256_P256:
{ {
size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64 size_t padding = 128 - i2p::crypto::ECDSAP256_KEY_LENGTH; // 64 = 128 - 64
RAND_bytes (m_StandardIdentity.signingKey, padding); RAND_bytes (m_StandardIdentity.signingKey, padding);
memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH); memcpy (m_StandardIdentity.signingKey + padding, signingKey, i2p::crypto::ECDSAP256_KEY_LENGTH);
break; break;
@ -127,7 +128,7 @@ namespace data
{ {
LogPrint (eLogError, "Identity: Unexpected excessive signing key len ", excessLen); LogPrint (eLogError, "Identity: Unexpected excessive signing key len ", excessLen);
excessLen = MAX_EXTENDED_BUFFER_SIZE - 4; excessLen = MAX_EXTENDED_BUFFER_SIZE - 4;
} }
memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen); memcpy (m_ExtendedBuffer + 4, excessBuf, excessLen);
delete[] excessBuf; delete[] excessBuf;
} }
@ -214,7 +215,7 @@ namespace data
{ {
if (len < DEFAULT_IDENTITY_SIZE) if (len < DEFAULT_IDENTITY_SIZE)
{ {
LogPrint (eLogError, "Identity: buffer length ", len, " is too small"); LogPrint (eLogError, "Identity: Buffer length ", len, " is too small");
return 0; return 0;
} }
memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE); memcpy (&m_StandardIdentity, buf, DEFAULT_IDENTITY_SIZE);
@ -479,7 +480,7 @@ namespace data
size_t ret = m_Public->FromBuffer (buf, len); size_t ret = m_Public->FromBuffer (buf, len);
auto cryptoKeyLen = GetPrivateKeyLen (); auto cryptoKeyLen = GetPrivateKeyLen ();
if (!ret || ret + cryptoKeyLen > len) return 0; // overflow if (!ret || ret + cryptoKeyLen > len) return 0; // overflow
memcpy (m_PrivateKey, buf + ret, cryptoKeyLen); memcpy (m_PrivateKey, buf + ret, cryptoKeyLen);
ret += cryptoKeyLen; ret += cryptoKeyLen;
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow
@ -508,7 +509,7 @@ namespace data
if (m_Public->GetSignatureLen () + ret > len) return 0; if (m_Public->GetSignatureLen () + ret > len) return 0;
if (!m_Public->Verify (offlineInfo, keyLen + 6, buf + ret)) if (!m_Public->Verify (offlineInfo, keyLen + 6, buf + ret))
{ {
LogPrint (eLogError, "Identity: offline signature verification failed"); LogPrint (eLogError, "Identity: Offline signature verification failed");
return 0; return 0;
} }
ret += m_Public->GetSignatureLen (); ret += m_Public->GetSignatureLen ();
@ -653,9 +654,9 @@ namespace data
size_t PrivateKeys::GetPrivateKeyLen () const size_t PrivateKeys::GetPrivateKeyLen () const
{ {
// private key length always 256, but type 4 // private key length always 256, but type 4
return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256; return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256;
} }
uint8_t * PrivateKeys::GetPadding() uint8_t * PrivateKeys::GetPadding()
{ {
if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519) if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
@ -680,7 +681,7 @@ namespace data
break; break;
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD:
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key); return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
break; break;
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key); return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key);
@ -787,7 +788,7 @@ namespace data
keys.m_OfflineSignature.resize (pubKeyLen + m_Public->GetSignatureLen () + 6); keys.m_OfflineSignature.resize (pubKeyLen + m_Public->GetSignatureLen () + 6);
htobe32buf (keys.m_OfflineSignature.data (), expires); // expires htobe32buf (keys.m_OfflineSignature.data (), expires); // expires
htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type htobe16buf (keys.m_OfflineSignature.data () + 4, type); // type
GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key GenerateSigningKeyPair (type, keys.m_SigningPrivateKey, keys.m_OfflineSignature.data () + 6); // public key
Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature Sign (keys.m_OfflineSignature.data (), pubKeyLen + 6, keys.m_OfflineSignature.data () + 6 + pubKeyLen); // signature
// recreate signer // recreate signer
keys.m_Signer = nullptr; keys.m_Signer = nullptr;

View File

@ -84,9 +84,9 @@ namespace data
typedef uint16_t SigningKeyType; typedef uint16_t SigningKeyType;
typedef uint16_t CryptoKeyType; typedef uint16_t CryptoKeyType;
const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521 const size_t MAX_EXTENDED_BUFFER_SIZE = 8; // cryptoKeyType + signingKeyType + 4 extra bytes of P521
class IdentityEx class IdentityEx
{ {
public: public:
IdentityEx (); IdentityEx ();
@ -120,7 +120,7 @@ namespace data
CryptoKeyType GetCryptoKeyType () const; CryptoKeyType GetCryptoKeyType () const;
void DropVerifier () const; // to save memory void DropVerifier () const; // to save memory
bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); } bool operator == (const IdentityEx & other) const { return GetIdentHash() == other.GetIdentHash(); }
void RecalculateIdentHash(uint8_t * buff=nullptr); void RecalculateIdentHash(uint8_t * buff=nullptr);
static i2p::crypto::Verifier * CreateVerifier (SigningKeyType keyType); static i2p::crypto::Verifier * CreateVerifier (SigningKeyType keyType);
@ -138,7 +138,7 @@ namespace data
mutable i2p::crypto::Verifier * m_Verifier = nullptr; mutable i2p::crypto::Verifier * m_Verifier = nullptr;
mutable std::mutex m_VerifierMutex; mutable std::mutex m_VerifierMutex;
size_t m_ExtendedLen; size_t m_ExtendedLen;
uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE]; uint8_t m_ExtendedBuffer[MAX_EXTENDED_BUFFER_SIZE];
}; };
class PrivateKeys // for eepsites class PrivateKeys // for eepsites
@ -222,7 +222,7 @@ namespace data
RoutingDestination () {}; RoutingDestination () {};
virtual ~RoutingDestination () {}; virtual ~RoutingDestination () {};
virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0; virtual std::shared_ptr<const IdentityEx> GetIdentity () const = 0;
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted) const = 0; // encrypt data for virtual void Encrypt (const uint8_t * data, uint8_t * encrypted) const = 0; // encrypt data for
virtual bool IsDestination () const = 0; // for garlic virtual bool IsDestination () const = 0; // for garlic

View File

@ -61,7 +61,7 @@ namespace data
size_t size = m_Identity->GetFullLen (); size_t size = m_Identity->GetFullLen ();
if (size > m_BufferLen) if (size > m_BufferLen)
{ {
LogPrint (eLogError, "LeaseSet: identity length ", size, " exceeds buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet: Identity length ", size, " exceeds buffer size ", m_BufferLen);
m_IsValid = false; m_IsValid = false;
return; return;
} }
@ -77,23 +77,23 @@ namespace data
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
m_IsValid = false; m_IsValid = false;
return; return;
} }
uint8_t num = m_Buffer[size]; uint8_t num = m_Buffer[size];
size++; // num size++; // num
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num); LogPrint (eLogDebug, "LeaseSet: Read num=", (int)num);
if (!num || num > MAX_NUM_LEASES) if (!num || num > MAX_NUM_LEASES)
{ {
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num); LogPrint (eLogError, "LeaseSet: Rncorrect number of leases", (int)num);
m_IsValid = false; m_IsValid = false;
return; return;
} }
if (size + num*LEASE_SIZE > m_BufferLen) if (size + num*LEASE_SIZE > m_BufferLen)
{ {
LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet: ", size, " exceeds buffer size ", m_BufferLen);
m_IsValid = false; m_IsValid = false;
return; return;
} }
UpdateLeasesBegin (); UpdateLeasesBegin ();
// process leases // process leases
m_ExpirationTime = 0; m_ExpirationTime = 0;
@ -112,7 +112,7 @@ namespace data
} }
if (!m_ExpirationTime) if (!m_ExpirationTime)
{ {
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped"); LogPrint (eLogWarning, "LeaseSet: All leases are expired. Dropped");
m_IsValid = false; m_IsValid = false;
return; return;
} }
@ -121,16 +121,16 @@ namespace data
// verify // verify
if (verifySignature) if (verifySignature)
{ {
auto signedSize = leases - m_Buffer; auto signedSize = leases - m_Buffer;
if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen) if (signedSize + m_Identity->GetSignatureLen () > m_BufferLen)
{ {
LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet: Signature exceeds buffer size ", m_BufferLen);
m_IsValid = false; m_IsValid = false;
} }
else if (!m_Identity->Verify (m_Buffer, signedSize, leases)) else if (!m_Identity->Verify (m_Buffer, signedSize, leases))
{ {
LogPrint (eLogWarning, "LeaseSet: verification failed"); LogPrint (eLogWarning, "LeaseSet: Verification failed");
m_IsValid = false; m_IsValid = false;
} }
} }
@ -274,7 +274,7 @@ namespace data
{ {
if (len <= m_BufferLen) m_BufferLen = len; if (len <= m_BufferLen) m_BufferLen = len;
else else
LogPrint (eLogError, "LeaseSet2: actual buffer size ", len , " exceeds full buffer size ", m_BufferLen); LogPrint (eLogError, "LeaseSet2: Actual buffer size ", len , " exceeds full buffer size ", m_BufferLen);
} }
LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto): LeaseSet2::LeaseSet2 (uint8_t storeType, const uint8_t * buf, size_t len, bool storeLeases, CryptoKeyType preferredCrypto):
@ -331,7 +331,7 @@ namespace data
m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset); m_TransientVerifier = ProcessOfflineSignature (identity, buf, len, offset);
if (!m_TransientVerifier) if (!m_TransientVerifier)
{ {
LogPrint (eLogError, "LeaseSet2: offline signature failed"); LogPrint (eLogError, "LeaseSet2: Offline signature failed");
return; return;
} }
} }
@ -378,7 +378,7 @@ namespace data
bool verified = verifier->Verify (buf - 1, signatureOffset + 1, buf + signatureOffset); bool verified = verifier->Verify (buf - 1, signatureOffset + 1, buf + signatureOffset);
const_cast<uint8_t *>(buf)[-1] = c; const_cast<uint8_t *>(buf)[-1] = c;
if (!verified) if (!verified)
LogPrint (eLogWarning, "LeaseSet2: verification failed"); LogPrint (eLogWarning, "LeaseSet2: Verification failed");
return verified; return verified;
} }
@ -489,7 +489,7 @@ namespace data
m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset); m_TransientVerifier = ProcessOfflineSignature (blindedVerifier, buf, len, offset);
if (!m_TransientVerifier) if (!m_TransientVerifier)
{ {
LogPrint (eLogError, "LeaseSet2: offline signature failed"); LogPrint (eLogError, "LeaseSet2: Offline signature failed");
return; return;
} }
} }
@ -515,7 +515,7 @@ namespace data
key->GetBlindedKey (date, blinded.data ()); key->GetBlindedKey (date, blinded.data ());
if (memcmp (blindedPublicKey, blinded.data (), blindedKeyLen)) if (memcmp (blindedPublicKey, blinded.data (), blindedKeyLen))
{ {
LogPrint (eLogError, "LeaseSet2: blinded public key doesn't match"); LogPrint (eLogError, "LeaseSet2: Blinded public key doesn't match");
return; return;
} }
} }
@ -569,7 +569,7 @@ namespace data
ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1); ReadFromBuffer (innerPlainText.data () + 1, lenInnerPlaintext - 1);
} }
else else
LogPrint (eLogError, "LeaseSet2: unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet"); LogPrint (eLogError, "LeaseSet2: Unexpected LeaseSet type ", (int)innerPlainText[0], " inside encrypted LeaseSet");
} }
else else
{ {
@ -582,7 +582,7 @@ namespace data
// helper for ExtractClientAuthData // helper for ExtractClientAuthData
static inline bool GetAuthCookie (const uint8_t * authClients, int numClients, const uint8_t * okm, uint8_t * authCookie) static inline bool GetAuthCookie (const uint8_t * authClients, int numClients, const uint8_t * okm, uint8_t * authCookie)
{ {
// try to find clientCookie_i for clientID_i = okm[44:51] // try to find clientCookie_i for clientID_i = okm[44:51]
for (int i = 0; i < numClients; i++) for (int i = 0; i < numClients; i++)
{ {
if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i if (!memcmp (okm + 44, authClients + i*40, 8)) // clientID_i
@ -606,7 +606,7 @@ namespace data
{ {
const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey const uint8_t * ephemeralPublicKey = buf + offset; offset += 32; // ephemeralPublicKey
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len) if (offset > len)
{ {
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data"); LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in DH auth data");
@ -632,7 +632,7 @@ namespace data
{ {
const uint8_t * authSalt = buf + offset; offset += 32; // authSalt const uint8_t * authSalt = buf + offset; offset += 32; // authSalt
uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients uint16_t numClients = bufbe16toh (buf + offset); offset += 2; // clients
const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients const uint8_t * authClients = buf + offset; offset += numClients*40; // authClients
if (offset > len) if (offset > len)
{ {
LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data"); LogPrint (eLogError, "LeaseSet2: Too many clients ", numClients, " in PSK auth data");
@ -653,7 +653,7 @@ namespace data
LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided"); LogPrint (eLogError, "LeaseSet2: Can't calculate authCookie: psk_i is not provided");
} }
else else
LogPrint (eLogError, "LeaseSet2: unknown client auth type ", (int)flag); LogPrint (eLogError, "LeaseSet2: Unknown client auth type ", (int)flag);
} }
return offset - 1; return offset - 1;
} }
@ -737,7 +737,7 @@ namespace data
htobe64buf (m_Buffer + offset, ts); htobe64buf (m_Buffer + offset, ts);
offset += 8; // end date offset += 8; // end date
} }
// we don't sign it yet. must be signed later on // we don't sign it yet. must be signed later on
} }
LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len): LocalLeaseSet::LocalLeaseSet (std::shared_ptr<const IdentityEx> identity, const uint8_t * buf, size_t len):
@ -768,7 +768,7 @@ namespace data
size_t size = ident.GetFullLen (); size_t size = ident.GetFullLen ();
if (size > sz) if (size > sz)
{ {
LogPrint (eLogError, "LeaseSet: identity length ", size, " exceeds buffer size ", sz); LogPrint (eLogError, "LeaseSet: Identity length ", size, " exceeds buffer size ", sz);
return false; return false;
} }
// encryption key // encryption key
@ -779,7 +779,7 @@ namespace data
++size; ++size;
if (!numLeases || numLeases > MAX_NUM_LEASES) if (!numLeases || numLeases > MAX_NUM_LEASES)
{ {
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)numLeases); LogPrint (eLogError, "LeaseSet: Incorrect number of leases", (int)numLeases);
return false; return false;
} }
const uint8_t * leases = ptr + size; const uint8_t * leases = ptr + size;
@ -863,17 +863,17 @@ namespace data
} }
// update expiration // update expiration
if (expirationTime) if (expirationTime)
{ {
SetExpirationTime (expirationTime*1000LL); SetExpirationTime (expirationTime*1000LL);
auto expires = (int)expirationTime - timestamp; auto expires = (int)expirationTime - timestamp;
htobe16buf (expiresBuf, expires > 0 ? expires : 0); htobe16buf (expiresBuf, expires > 0 ? expires : 0);
} }
else else
{ {
// no tunnels or withdraw // no tunnels or withdraw
SetExpirationTime (timestamp*1000LL); SetExpirationTime (timestamp*1000LL);
memset (expiresBuf, 0, 2); // expires immeditely memset (expiresBuf, 0, 2); // expires immeditely
} }
// sign // sign
keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type keys.Sign (m_Buffer, offset, m_Buffer + offset); // LS + leading store type
} }
@ -916,7 +916,7 @@ namespace data
{ {
LogPrint (eLogError, "LeaseSet2: Can't create blinded signer for signature type ", blindedKey.GetSigType ()); LogPrint (eLogError, "LeaseSet2: Can't create blinded signer for signature type ", blindedKey.GetSigType ());
return; return;
} }
auto offset = 1; auto offset = 1;
htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type htobe16buf (m_Buffer + offset, blindedKey.GetBlindedSigType ()); offset += 2; // Blinded Public Key Sig Type
memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key memcpy (m_Buffer + offset, blindedPub, publicKeyLen); offset += publicKeyLen; // Blinded Public Key
@ -984,7 +984,7 @@ namespace data
m_StoreHash = blindedKey->GetStoreHash (); m_StoreHash = blindedKey->GetStoreHash ();
} }
else else
LogPrint (eLogError, "LeaseSet2: couldn't extract inner layer"); LogPrint (eLogError, "LeaseSet2: Couldn't extract inner layer");
} }
void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const void LocalEncryptedLeaseSet2::CreateClientAuthData (const uint8_t * subcredential, int authType, std::shared_ptr<std::vector<AuthPublicKey> > authKeys, const uint8_t * authCookie, uint8_t * authData) const
@ -995,7 +995,7 @@ namespace data
ek.GenerateKeys (); // esk and epk ek.GenerateKeys (); // esk and epk
memcpy (authData, ek.GetPublicKey (), 32); authData += 32; // epk memcpy (authData, ek.GetPublicKey (), 32); authData += 32; // epk
htobe16buf (authData, authKeys->size ()); authData += 2; // num clients htobe16buf (authData, authKeys->size ()); authData += 2; // num clients
uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp uint8_t authInput[100]; // sharedSecret || cpk_i || subcredential || publishedTimestamp
memcpy (authInput + 64, subcredential, 36); memcpy (authInput + 64, subcredential, 36);
for (auto& it: *authKeys) for (auto& it: *authKeys)
{ {

View File

@ -128,8 +128,8 @@ namespace data
}; };
/** /**
validate lease set buffer signature and extract expiration timestamp * validate lease set buffer signature and extract expiration timestamp
@returns true if the leaseset is well formed and signature is valid * @returns true if the leaseset is well formed and signature is valid
*/ */
bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires); bool LeaseSetBufferValidate(const uint8_t * ptr, size_t sz, uint64_t & expires);

View File

@ -46,7 +46,7 @@ namespace log {
#ifndef _WIN32 #ifndef _WIN32
/** /**
* @brief Maps our log levels to syslog one * @brief Maps our log levels to syslog one
* @return syslog priority LOG_*, as defined in syslog.h * @return syslog priority LOG_*, as defined in syslog.h
*/ */
static inline int GetSyslogPrio (enum LogLevel l) { static inline int GetSyslogPrio (enum LogLevel l) {
@ -113,11 +113,11 @@ namespace log {
std::string str_tolower(std::string s) { std::string str_tolower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), std::transform(s.begin(), s.end(), s.begin(),
// static_cast<int(*)(int)>(std::tolower) // wrong // static_cast<int(*)(int)>(std::tolower) // wrong
// [](int c){ return std::tolower(c); } // wrong // [](int c){ return std::tolower(c); } // wrong
// [](char c){ return std::tolower(c); } // wrong // [](char c){ return std::tolower(c); } // wrong
[](unsigned char c){ return std::tolower(c); } // correct [](unsigned char c){ return std::tolower(c); } // correct
); );
return s; return s;
} }
@ -129,10 +129,10 @@ namespace log {
else if (level == "info") { m_MinLevel = eLogInfo; } else if (level == "info") { m_MinLevel = eLogInfo; }
else if (level == "debug") { m_MinLevel = eLogDebug; } else if (level == "debug") { m_MinLevel = eLogDebug; }
else { else {
LogPrint(eLogError, "Log: unknown loglevel: ", level); LogPrint(eLogError, "Log: Unknown loglevel: ", level);
return; return;
} }
LogPrint(eLogInfo, "Log: min messages level set to ", level); LogPrint(eLogInfo, "Log: Logging level set to ", level);
} }
const char * Log::TimeAsString(std::time_t t) { const char * Log::TimeAsString(std::time_t t) {
@ -170,7 +170,7 @@ namespace log {
break; break;
case eLogStdout: case eLogStdout:
default: default:
std::cout << TimeAsString(msg->timestamp) std::cout << TimeAsString(msg->timestamp)
<< "@" << short_tid << "@" << short_tid
<< "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels] << "/" << LogMsgColors[msg->level] << g_LogLevelStr[msg->level] << LogMsgColors[eNumLogLevels]
<< " - " << msg->text << std::endl; << " - " << msg->text << std::endl;
@ -212,7 +212,7 @@ namespace log {
m_LogStream = os; m_LogStream = os;
return; return;
} }
LogPrint(eLogError, "Log: can't open file ", path); LogPrint(eLogError, "Log: Can't open file ", path);
} }
void Log::SendTo (std::shared_ptr<std::ostream> os) { void Log::SendTo (std::shared_ptr<std::ostream> os) {

View File

@ -52,7 +52,7 @@ namespace log {
{ {
private: private:
enum LogType m_Destination; enum LogType m_Destination;
enum LogLevel m_MinLevel; enum LogLevel m_MinLevel;
std::shared_ptr<std::ostream> m_LogStream; std::shared_ptr<std::ostream> m_LogStream;
std::string m_Logfile; std::string m_Logfile;
@ -75,7 +75,7 @@ namespace log {
/** /**
* @brief Makes formatted string from unix timestamp * @brief Makes formatted string from unix timestamp
* @param ts Second since epoch * @param ts Second since epoch
* *
* This function internally caches the result for last provided value * This function internally caches the result for last provided value
*/ */
@ -86,52 +86,52 @@ namespace log {
Log (); Log ();
~Log (); ~Log ();
LogType GetLogType () { return m_Destination; }; LogType GetLogType () { return m_Destination; };
LogLevel GetLogLevel () { return m_MinLevel; }; LogLevel GetLogLevel () { return m_MinLevel; };
void Start (); void Start ();
void Stop (); void Stop ();
/** /**
* @brief Sets minimal allowed level for log messages * @brief Sets minimal allowed level for log messages
* @param level String with wanted minimal msg level * @param level String with wanted minimal msg level
*/ */
void SetLogLevel (const std::string& level); void SetLogLevel (const std::string& level);
/** /**
* @brief Sets log destination to logfile * @brief Sets log destination to logfile
* @param path Path to logfile * @param path Path to logfile
*/ */
void SendTo (const std::string &path); void SendTo (const std::string &path);
/** /**
* @brief Sets log destination to given output stream * @brief Sets log destination to given output stream
* @param os Output stream * @param os Output stream
*/ */
void SendTo (std::shared_ptr<std::ostream> os); void SendTo (std::shared_ptr<std::ostream> os);
/** /**
* @brief Sets format for timestamps in log * @brief Sets format for timestamps in log
* @param format String with timestamp format * @param format String with timestamp format
*/ */
void SetTimeFormat (std::string format) { m_TimeFormat = format; }; void SetTimeFormat (std::string format) { m_TimeFormat = format; };
#ifndef _WIN32 #ifndef _WIN32
/** /**
* @brief Sets log destination to syslog * @brief Sets log destination to syslog
* @param name Wanted program name * @param name Wanted program name
* @param facility Wanted log category * @param facility Wanted log category
*/ */
void SendTo (const char *name, int facility); void SendTo (const char *name, int facility);
#endif #endif
/** /**
* @brief Format log message and write to output stream/syslog * @brief Format log message and write to output stream/syslog
* @param msg Pointer to processed message * @param msg Pointer to processed message
*/ */
void Append(std::shared_ptr<i2p::log::LogMsg> &); void Append(std::shared_ptr<i2p::log::LogMsg> &);
/** @brief Reopen log file */ /** @brief Reopen log file */
void Reopen(); void Reopen();
}; };
@ -144,8 +144,8 @@ namespace log {
*/ */
struct LogMsg { struct LogMsg {
std::time_t timestamp; std::time_t timestamp;
std::string text; /**< message text as single string */ std::string text; /**< message text as single string */
LogLevel level; /**< message level */ LogLevel level; /**< message level */
std::thread::id tid; /**< id of thread that generated message */ std::thread::id tid; /**< id of thread that generated message */
LogMsg (LogLevel lvl, std::time_t ts, std::string&& txt): timestamp(ts), text(std::move(txt)), level(lvl) {} LogMsg (LogLevel lvl, std::time_t ts, std::string&& txt): timestamp(ts), text(std::move(txt)), level(lvl) {}
@ -153,7 +153,7 @@ namespace log {
Log & Logger(); Log & Logger();
typedef std::function<void (const std::string&)> ThrowFunction; typedef std::function<void (const std::string&)> ThrowFunction;
ThrowFunction GetThrowFunction (); ThrowFunction GetThrowFunction ();
void SetThrowFunction (ThrowFunction f); void SetThrowFunction (ThrowFunction f);
} // log } // log

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -23,7 +23,7 @@
#include "HTTP.h" #include "HTTP.h"
#include "util.h" #include "util.h"
#ifdef __linux__ #if defined(__linux__) && !defined(_NETINET_IN_H)
#include <linux/in6.h> #include <linux/in6.h>
#endif #endif
@ -59,14 +59,14 @@ namespace transport
void NTCP2Establisher::KDF1Bob () void NTCP2Establisher::KDF1Bob ()
{ {
KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetStaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ()); KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
} }
void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub)
{ {
MixHash (sessionRequest + 32, 32); // encrypted payload MixHash (sessionRequest + 32, 32); // encrypted payload
int paddingLength = sessionRequestLen - 64; int paddingLength = sessionRequestLen - 64;
if (paddingLength > 0) if (paddingLength > 0)
MixHash (sessionRequest + 64, paddingLength); MixHash (sessionRequest + 64, paddingLength);
MixHash (epub, 32); MixHash (epub, 32);
@ -91,7 +91,7 @@ namespace transport
void NTCP2Establisher::KDF3Alice () void NTCP2Establisher::KDF3Alice ()
{ {
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial); i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
MixKey (inputKeyMaterial); MixKey (inputKeyMaterial);
} }
@ -130,7 +130,7 @@ namespace transport
// m3p2Len // m3p2Len
auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen (); auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen ();
m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
htobe16buf (options + 4, m3p2Len); htobe16buf (options + 4, m3p2Len);
// fill m3p2 payload (RouterInfo block) // fill m3p2 payload (RouterInfo block)
m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; // m3p1 is 48 bytes m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; // m3p1 is 48 bytes
uint8_t * m3p2 = m_SessionConfirmedBuffer + 48; uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
@ -195,8 +195,9 @@ namespace transport
MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext) MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext)
} }
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen) bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew)
{ {
clockSkew = false;
// decrypt X // decrypt X
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
decryption.SetKey (i2p::context.GetIdentHash ()); decryption.SetKey (i2p::context.GetIdentHash ());
@ -232,7 +233,8 @@ namespace transport
if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW) if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
{ {
LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew"); LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew");
return false; clockSkew = true;
// we send SessionCreate to let Alice know our time and then close session
} }
} }
else else
@ -318,17 +320,18 @@ namespace transport
} }
NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter, NTCP2Session::NTCP2Session (NTCP2Server& 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, NTCP2_ESTABLISH_TIMEOUT), TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT),
m_Server (server), m_Socket (m_Server.GetService ()), m_Server (server), m_Socket (m_Server.GetService ()),
m_IsEstablished (false), m_IsTerminated (false), m_IsEstablished (false), m_IsTerminated (false),
m_Establisher (new NTCP2Establisher), m_Establisher (new NTCP2Establisher),
m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr),
#if OPENSSL_SIPHASH #if OPENSSL_SIPHASH
m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr), m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr),
#else
m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr),
#endif #endif
m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr), m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr),
m_NextReceivedBufferSize (0), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0), m_NextReceivedBufferSize (0), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0),
m_IsSending (false), m_IsReceiving (false), m_NextPaddingSize (16) m_IsSending (false), m_IsReceiving (false), m_NextPaddingSize (16)
{ {
if (in_RemoteRouter) // Alice if (in_RemoteRouter) // Alice
@ -336,8 +339,8 @@ namespace transport
m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash (); m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash ();
if (addr) if (addr)
{ {
memcpy (m_Establisher->m_RemoteStaticKey, addr->ntcp2->staticKey, 32); memcpy (m_Establisher->m_RemoteStaticKey, addr->s, 32);
memcpy (m_Establisher->m_IV, addr->ntcp2->iv, 16); memcpy (m_Establisher->m_IV, addr->i, 16);
m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port); m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port);
} }
else else
@ -352,8 +355,6 @@ namespace transport
delete[] m_NextReceivedBuffer; delete[] m_NextReceivedBuffer;
delete[] m_NextSendBuffer; delete[] m_NextSendBuffer;
#if OPENSSL_SIPHASH #if OPENSSL_SIPHASH
if (m_SendSipKey) EVP_PKEY_free (m_SendSipKey);
if (m_ReceiveSipKey) EVP_PKEY_free (m_ReceiveSipKey);
if (m_SendMDCtx) EVP_MD_CTX_destroy (m_SendMDCtx); if (m_SendMDCtx) EVP_MD_CTX_destroy (m_SendMDCtx);
if (m_ReceiveMDCtx) EVP_MD_CTX_destroy (m_ReceiveMDCtx); if (m_ReceiveMDCtx) EVP_MD_CTX_destroy (m_ReceiveMDCtx);
#endif #endif
@ -373,7 +374,7 @@ namespace transport
transports.PeerDisconnected (shared_from_this ()); transports.PeerDisconnected (shared_from_this ());
m_Server.RemoveNTCP2Session (shared_from_this ()); m_Server.RemoveNTCP2Session (shared_from_this ());
m_SendQueue.clear (); m_SendQueue.clear ();
LogPrint (eLogDebug, "NTCP2: session terminated"); LogPrint (eLogDebug, "NTCP2: Session terminated");
} }
} }
@ -402,7 +403,7 @@ namespace transport
} }
void NTCP2Session::CreateNextReceivedBuffer (size_t size) void NTCP2Session::CreateNextReceivedBuffer (size_t size)
{ {
if (m_NextReceivedBuffer) if (m_NextReceivedBuffer)
{ {
if (size <= m_NextReceivedBufferSize) if (size <= m_NextReceivedBufferSize)
@ -412,19 +413,19 @@ namespace transport
} }
m_NextReceivedBuffer = new uint8_t[size]; m_NextReceivedBuffer = new uint8_t[size];
m_NextReceivedBufferSize = size; m_NextReceivedBufferSize = size;
} }
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts) void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
{ {
if (m_NextReceivedBuffer && !m_IsReceiving && if (m_NextReceivedBuffer && !m_IsReceiving &&
ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT) ts > m_LastActivityTimestamp + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
{ {
delete[] m_NextReceivedBuffer; delete[] m_NextReceivedBuffer;
m_NextReceivedBuffer = nullptr; m_NextReceivedBuffer = nullptr;
m_NextReceivedBufferSize = 0; m_NextReceivedBufferSize = 0;
} }
} }
void NTCP2Session::KeyDerivationFunctionDataPhase () void NTCP2Session::KeyDerivationFunctionDataPhase ()
{ {
uint8_t k[64]; uint8_t k[64];
@ -454,7 +455,7 @@ namespace transport
(void) bytes_transferred; (void) bytes_transferred;
if (ecode) if (ecode)
{ {
LogPrint (eLogWarning, "NTCP2: couldn't send SessionRequest message: ", ecode.message ()); LogPrint (eLogWarning, "NTCP2: Couldn't send SessionRequest message: ", ecode.message ());
Terminate (); Terminate ();
} }
else else
@ -477,9 +478,16 @@ namespace transport
{ {
LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred); LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred);
uint16_t paddingLen = 0; uint16_t paddingLen = 0;
if (m_Establisher->ProcessSessionRequestMessage (paddingLen)) bool clockSkew = false;
if (m_Establisher->ProcessSessionRequestMessage (paddingLen, clockSkew))
{ {
if (paddingLen > 0) if (clockSkew)
{
// we don't care about padding, send SessionCreated and close session
SendSessionCreated ();
m_Server.GetService ().post (std::bind (&NTCP2Session::Terminate, shared_from_this ()));
}
else if (paddingLen > 0)
{ {
if (paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE - 64) // session request is 287 bytes max if (paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE - 64) // session request is 287 bytes max
{ {
@ -488,7 +496,7 @@ namespace transport
} }
else else
{ {
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long"); LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
Terminate (); Terminate ();
} }
} }
@ -541,7 +549,7 @@ namespace transport
} }
else else
{ {
LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long"); LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long");
Terminate (); Terminate ();
} }
} }
@ -584,7 +592,7 @@ namespace transport
(void) bytes_transferred; (void) bytes_transferred;
if (ecode) if (ecode)
{ {
LogPrint (eLogWarning, "NTCP2: couldn't send SessionConfirmed message: ", ecode.message ()); LogPrint (eLogWarning, "NTCP2: Couldn't send SessionConfirmed message: ", ecode.message ());
Terminate (); Terminate ();
} }
else else
@ -611,7 +619,7 @@ namespace transport
(void) bytes_transferred; (void) bytes_transferred;
if (ecode) if (ecode)
{ {
LogPrint (eLogWarning, "NTCP2: couldn't send SessionCreated message: ", ecode.message ()); LogPrint (eLogWarning, "NTCP2: Couldn't send SessionCreated message: ", ecode.message ());
Terminate (); Terminate ();
} }
else else
@ -654,7 +662,7 @@ namespace transport
// process RI // process RI
if (buf[0] != eNTCP2BlkRouterInfo) if (buf[0] != eNTCP2BlkRouterInfo)
{ {
LogPrint (eLogWarning, "NTCP2: unexpected block ", (int)buf[0], " in SessionConfirmed"); LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)buf[0], " in SessionConfirmed");
Terminate (); Terminate ();
return; return;
} }
@ -682,7 +690,7 @@ namespace transport
auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey); auto addr = ri.GetNTCP2AddressWithStaticKey (m_Establisher->m_RemoteStaticKey);
if (!addr) if (!addr)
{ {
LogPrint (eLogError, "NTCP2: No NTCP2 address wth static key found in SessionConfirmed"); LogPrint (eLogError, "NTCP2: No NTCP2 address with static key found in SessionConfirmed");
Terminate (); Terminate ();
return; return;
} }
@ -711,17 +719,19 @@ namespace transport
void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey) void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey)
{ {
#if OPENSSL_SIPHASH #if OPENSSL_SIPHASH
m_SendSipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, sendSipKey, 16); EVP_PKEY * sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, sendSipKey, 16);
m_SendMDCtx = EVP_MD_CTX_create (); m_SendMDCtx = EVP_MD_CTX_create ();
EVP_PKEY_CTX *ctx = nullptr; EVP_PKEY_CTX *ctx = nullptr;
EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, m_SendSipKey); EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, sipKey);
EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr); EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
EVP_PKEY_free (sipKey);
m_ReceiveSipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16); sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16);
m_ReceiveMDCtx = EVP_MD_CTX_create (); m_ReceiveMDCtx = EVP_MD_CTX_create ();
ctx = nullptr; ctx = nullptr;
EVP_DigestSignInit (m_ReceiveMDCtx, &ctx, NULL, NULL, m_ReceiveSipKey); EVP_DigestSignInit (m_ReceiveMDCtx, &ctx, NULL, NULL, sipKey);
EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr); EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
EVP_PKEY_free (sipKey);
#else #else
m_SendSipKey = sendSipKey; m_SendSipKey = sendSipKey;
m_ReceiveSipKey = receiveSipKey; m_ReceiveSipKey = receiveSipKey;
@ -747,7 +757,7 @@ namespace transport
if (IsTerminated ()) return; if (IsTerminated ()) return;
#ifdef __linux__ #ifdef __linux__
const int one = 1; const int one = 1;
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
#endif #endif
boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (), boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
@ -758,7 +768,7 @@ namespace transport
if (ecode) if (ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
LogPrint (eLogWarning, "NTCP2: receive length read error: ", ecode.message ()); LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ());
Terminate (); Terminate ();
} }
else else
@ -773,7 +783,7 @@ namespace transport
#endif #endif
// m_NextReceivedLen comes from the network in BigEndian // m_NextReceivedLen comes from the network in BigEndian
m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key); m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key);
LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); LogPrint (eLogDebug, "NTCP2: Received length ", m_NextReceivedLen);
if (m_NextReceivedLen >= 16) if (m_NextReceivedLen >= 16)
{ {
CreateNextReceivedBuffer (m_NextReceivedLen); CreateNextReceivedBuffer (m_NextReceivedLen);
@ -790,7 +800,7 @@ namespace transport
} }
else else
{ {
LogPrint (eLogError, "NTCP2: received length ", m_NextReceivedLen, " is too short"); LogPrint (eLogError, "NTCP2: Received length ", m_NextReceivedLen, " is too short");
Terminate (); Terminate ();
} }
} }
@ -813,7 +823,7 @@ namespace transport
if (ecode) if (ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
LogPrint (eLogWarning, "NTCP2: receive read error: ", ecode.message ()); LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ());
Terminate (); Terminate ();
} }
else else
@ -825,7 +835,7 @@ namespace transport
CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++; CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++;
if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false)) if (i2p::crypto::AEADChaCha20Poly1305 (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen, false))
{ {
LogPrint (eLogDebug, "NTCP2: received message decrypted"); LogPrint (eLogDebug, "NTCP2: Received message decrypted");
ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16); ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16);
m_IsReceiving = false; m_IsReceiving = false;
ReceiveLength (); ReceiveLength ();
@ -856,10 +866,10 @@ namespace transport
switch (blk) switch (blk)
{ {
case eNTCP2BlkDateTime: case eNTCP2BlkDateTime:
LogPrint (eLogDebug, "NTCP2: datetime"); LogPrint (eLogDebug, "NTCP2: Datetime");
break; break;
case eNTCP2BlkOptions: case eNTCP2BlkOptions:
LogPrint (eLogDebug, "NTCP2: options"); LogPrint (eLogDebug, "NTCP2: Options");
break; break;
case eNTCP2BlkRouterInfo: case eNTCP2BlkRouterInfo:
{ {
@ -875,25 +885,29 @@ namespace transport
LogPrint (eLogError, "NTCP2: I2NP block is too long ", size); LogPrint (eLogError, "NTCP2: I2NP block is too long ", size);
break; break;
} }
auto nextMsg = NewI2NPMessage (size); auto nextMsg = (frame[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPMessage (size);
nextMsg->Align (12); // for possible tunnel msg
nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
memcpy (nextMsg->GetNTCP2Header (), frame + offset, size); if (nextMsg->len <= nextMsg->maxLen)
nextMsg->FromNTCP2 (); {
m_Handler.PutNextMessage (nextMsg); memcpy (nextMsg->GetNTCP2Header (), frame + offset, size);
nextMsg->FromNTCP2 ();
m_Handler.PutNextMessage (std::move (nextMsg));
}
else
LogPrint (eLogError, "NTCP2: I2NP block is too long for I2NP message");
break; break;
} }
case eNTCP2BlkTermination: case eNTCP2BlkTermination:
if (size >= 9) if (size >= 9)
{ {
LogPrint (eLogDebug, "NTCP2: termination. reason=", (int)(frame[offset + 8])); LogPrint (eLogDebug, "NTCP2: Termination. reason=", (int)(frame[offset + 8]));
Terminate (); Terminate ();
} }
else else
LogPrint (eLogWarning, "NTCP2: Unexpected termination block size ", size); LogPrint (eLogWarning, "NTCP2: Unexpected termination block size ", size);
break; break;
case eNTCP2BlkPadding: case eNTCP2BlkPadding:
LogPrint (eLogDebug, "NTCP2: padding"); LogPrint (eLogDebug, "NTCP2: Padding");
break; break;
default: default:
LogPrint (eLogWarning, "NTCP2: Unknown block type ", (int)blk); LogPrint (eLogWarning, "NTCP2: Unknown block type ", (int)blk);
@ -905,7 +919,7 @@ namespace transport
void NTCP2Session::SetNextSentFrameLength (size_t frameLen, uint8_t * lengthBuf) void NTCP2Session::SetNextSentFrameLength (size_t frameLen, uint8_t * lengthBuf)
{ {
#if OPENSSL_SIPHASH #if OPENSSL_SIPHASH
EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr); EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr);
EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8); EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8);
size_t l = 8; size_t l = 8;
@ -915,7 +929,7 @@ namespace transport
#endif #endif
// length must be in BigEndian // length must be in BigEndian
htobe16buf (lengthBuf, frameLen ^ le16toh (m_SendIV.key)); htobe16buf (lengthBuf, frameLen ^ le16toh (m_SendIV.key));
LogPrint (eLogDebug, "NTCP2: sent length ", frameLen); LogPrint (eLogDebug, "NTCP2: Sent length ", frameLen);
} }
void NTCP2Session::SendI2NPMsgs (std::vector<std::shared_ptr<I2NPMessage> >& msgs) void NTCP2Session::SendI2NPMsgs (std::vector<std::shared_ptr<I2NPMessage> >& msgs)
@ -968,7 +982,7 @@ namespace transport
{ {
// allocate send buffer // allocate send buffer
m_NextSendBuffer = new uint8_t[287]; // can be any size > 16, we just allocate 287 frequently m_NextSendBuffer = new uint8_t[287]; // can be any size > 16, we just allocate 287 frequently
// crate padding block // create padding block
auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16); auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16);
// and padding block to encrypt and send // and padding block to encrypt and send
if (paddingLen) if (paddingLen)
@ -1076,15 +1090,15 @@ namespace transport
size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100; size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100;
if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3; if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) paddingSize = NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
if (paddingSize > len) paddingSize = len; if (paddingSize > len) paddingSize = len;
if (paddingSize) if (paddingSize)
{ {
if (m_NextPaddingSize >= 16) if (m_NextPaddingSize >= 16)
{ {
RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes)); RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes));
m_NextPaddingSize = 0; m_NextPaddingSize = 0;
} }
paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize; paddingSize = m_PaddingSizes[m_NextPaddingSize++] % paddingSize;
} }
buf[0] = eNTCP2BlkPadding; // blk buf[0] = eNTCP2BlkPadding; // blk
htobe16buf (buf + 1, paddingSize); // size htobe16buf (buf + 1, paddingSize); // size
memset (buf + 3, 0, paddingSize); memset (buf + 3, 0, paddingSize);
@ -1110,7 +1124,13 @@ namespace transport
void NTCP2Session::SendTermination (NTCP2TerminationReason reason) void NTCP2Session::SendTermination (NTCP2TerminationReason reason)
{ {
if (!m_SendKey || !m_SendSipKey) return; if (!m_SendKey ||
#if OPENSSL_SIPHASH
!m_SendMDCtx
#else
!m_SendSipKey
#endif
) return;
m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block
// termination block // termination block
m_NextSendBuffer[2] = eNTCP2BlkTermination; m_NextSendBuffer[2] = eNTCP2BlkTermination;
@ -1143,21 +1163,21 @@ namespace transport
SendQueue (); SendQueue ();
else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE) else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
{ {
LogPrint (eLogWarning, "NTCP2: outgoing messages queue size to ", LogPrint (eLogWarning, "NTCP2: Outgoing messages queue size to ",
GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE); GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
Terminate (); Terminate ();
} }
} }
void NTCP2Session::SendLocalRouterInfo () void NTCP2Session::SendLocalRouterInfo (bool update)
{ {
if (!IsOutgoing ()) // we send it in SessionConfirmed if (update || !IsOutgoing ()) // we send it in SessionConfirmed for ougoing session
m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ())); m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
} }
NTCP2Server::NTCP2Server (): NTCP2Server::NTCP2Server ():
RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()), RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
m_ProxyType(eNoProxy), m_Resolver(GetService ()) m_ProxyType(eNoProxy), m_Resolver(GetService ())
{ {
} }
@ -1223,7 +1243,7 @@ namespace transport
m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6()); m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true)); m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true)); m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
#ifdef __linux__ #if defined(__linux__) && !defined(_NETINET_IN_H)
if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address
{ {
// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others // Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
@ -1249,7 +1269,7 @@ namespace transport
} }
catch ( std::exception & ex ) catch ( std::exception & ex )
{ {
LogPrint(eLogError, "NTCP2: failed to bind to v6 port ", address->port, ": ", ex.what()); LogPrint(eLogError, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ()); ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
continue; continue;
} }
@ -1290,7 +1310,7 @@ namespace transport
auto it = m_NTCP2Sessions.find (ident); auto it = m_NTCP2Sessions.find (ident);
if (it != m_NTCP2Sessions.end ()) if (it != m_NTCP2Sessions.end ())
{ {
LogPrint (eLogWarning, "NTCP2: session to ", ident.ToBase64 (), " already exists"); LogPrint (eLogWarning, "NTCP2: Session to ", ident.ToBase64 (), " already exists");
if (incoming) if (incoming)
// replace by new session // replace by new session
it->second->Terminate (); it->second->Terminate ();
@ -1359,7 +1379,7 @@ namespace transport
boost::system::error_code ec; boost::system::error_code ec;
conn->GetSocket ().bind (*localAddress, ec); conn->GetSocket ().bind (*localAddress, ec);
if (ec) if (ec)
LogPrint (eLogError, "NTCP2: can't bind to ", localAddress->address ().to_string (), ": ", ec.message ()); LogPrint (eLogError, "NTCP2: Can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
} }
conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer)); conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
} }
@ -1528,7 +1548,7 @@ namespace transport
{ {
if (ecode) if (ecode)
{ {
LogPrint(eLogWarning, "NTCP2: failed to connect to proxy ", ecode.message()); LogPrint(eLogWarning, "NTCP2: Failed to connect to proxy ", ecode.message());
timer->cancel(); timer->cancel();
conn->Terminate(); conn->Terminate();
return; return;
@ -1545,7 +1565,7 @@ namespace transport
(void) transferred; (void) transferred;
if(ec) if(ec)
{ {
LogPrint(eLogWarning, "NTCP2: socks5 write error ", ec.message()); LogPrint(eLogWarning, "NTCP2: SOCKS5 write error ", ec.message());
} }
}); });
auto readbuff = std::make_shared<std::vector<uint8_t> >(2); auto readbuff = std::make_shared<std::vector<uint8_t> >(2);
@ -1554,7 +1574,7 @@ namespace transport
{ {
if(ec) if(ec)
{ {
LogPrint(eLogError, "NTCP2: socks5 read error ", ec.message()); LogPrint(eLogError, "NTCP2: SOCKS5 read error ", ec.message());
timer->cancel(); timer->cancel();
conn->Terminate(); conn->Terminate();
return; return;
@ -1568,14 +1588,14 @@ namespace transport
} }
else if ((*readbuff)[1] == 0xff) else if ((*readbuff)[1] == 0xff)
{ {
LogPrint(eLogError, "NTCP2: socks5 proxy rejected authentication"); LogPrint(eLogError, "NTCP2: SOCKS5 proxy rejected authentication");
timer->cancel(); timer->cancel();
conn->Terminate(); conn->Terminate();
return; return;
} }
LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]); LogPrint(eLogError, "NTCP2:", (int)(*readbuff)[1]);
} }
LogPrint(eLogError, "NTCP2: socks5 server gave invalid response"); LogPrint(eLogError, "NTCP2: SOCKS5 server gave invalid response");
timer->cancel(); timer->cancel();
conn->Terminate(); conn->Terminate();
}); });
@ -1603,7 +1623,7 @@ namespace transport
{ {
(void) transferred; (void) transferred;
if(ec) if(ec)
LogPrint(eLogError, "NTCP2: http proxy write error ", ec.message()); LogPrint(eLogError, "NTCP2: HTTP proxy write error ", ec.message());
}); });
boost::asio::streambuf * readbuff = new boost::asio::streambuf; boost::asio::streambuf * readbuff = new boost::asio::streambuf;
@ -1612,7 +1632,7 @@ namespace transport
{ {
if(ec) if(ec)
{ {
LogPrint(eLogError, "NTCP2: http proxy read error ", ec.message()); LogPrint(eLogError, "NTCP2: HTTP proxy read error ", ec.message());
timer->cancel(); timer->cancel();
conn->Terminate(); conn->Terminate();
} }
@ -1630,10 +1650,10 @@ namespace transport
return; return;
} }
else else
LogPrint(eLogError, "NTCP2: http proxy rejected request ", res.code); LogPrint(eLogError, "NTCP2: HTTP proxy rejected request ", res.code);
} }
else else
LogPrint(eLogError, "NTCP2: http proxy gave malformed response"); LogPrint(eLogError, "NTCP2: HTTP proxy gave malformed response");
timer->cancel(); timer->cancel();
conn->Terminate(); conn->Terminate();
delete readbuff; delete readbuff;
@ -1642,7 +1662,7 @@ namespace transport
break; break;
} }
default: default:
LogPrint(eLogError, "NTCP2: unknown proxy type, invalid state"); LogPrint(eLogError, "NTCP2: Unknown proxy type, invalid state");
} }
} }
@ -1683,7 +1703,7 @@ namespace transport
{ {
if(ec) if(ec)
{ {
LogPrint(eLogError, "NTCP2: failed to write handshake to socks proxy ", ec.message()); LogPrint(eLogError, "NTCP2: Failed to write handshake to socks proxy ", ec.message());
return; return;
} }
}); });
@ -1693,7 +1713,7 @@ namespace transport
{ {
if(e) if(e)
{ {
LogPrint(eLogError, "NTCP2: socks proxy read error ", e.message()); LogPrint(eLogError, "NTCP2: SOCKS proxy read error ", e.message());
} }
else if(transferred == sz) else if(transferred == sz)
{ {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -42,7 +42,7 @@ namespace transport
const int NTCP2_CLOCK_SKEW = 60; // in seconds const int NTCP2_CLOCK_SKEW = 60; // in seconds
const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up const int NTCP2_MAX_OUTGOING_QUEUE_SIZE = 500; // how many messages we can queue up
enum NTCP2BlockType enum NTCP2BlockType
{ {
eNTCP2BlkDateTime = 0, eNTCP2BlkDateTime = 0,
@ -107,7 +107,7 @@ namespace transport
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
bool ProcessSessionRequestMessage (uint16_t& paddingLen); bool ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew);
bool ProcessSessionCreatedMessage (uint16_t& paddingLen); bool ProcessSessionCreatedMessage (uint16_t& paddingLen);
bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce); bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce);
bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf); bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf);
@ -118,7 +118,7 @@ namespace transport
i2p::data::IdentHash m_RemoteIdentHash; i2p::data::IdentHash m_RemoteIdentHash;
uint16_t m3p2Len; uint16_t m3p2Len;
uint8_t m_SessionRequestBuffer[NTCP2_SESSION_REQUEST_MAX_SIZE], uint8_t m_SessionRequestBuffer[NTCP2_SESSION_REQUEST_MAX_SIZE],
m_SessionCreatedBuffer[NTCP2_SESSION_CREATED_MAX_SIZE], * m_SessionConfirmedBuffer; m_SessionCreatedBuffer[NTCP2_SESSION_CREATED_MAX_SIZE], * m_SessionConfirmedBuffer;
size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen; size_t m_SessionRequestBufferLen, m_SessionCreatedBufferLen;
@ -137,7 +137,7 @@ namespace transport
void Done (); void Done ();
void Close () { m_Socket.close (); }; // for accept void Close () { m_Socket.close (); }; // for accept
void DeleteNextReceiveBuffer (uint64_t ts); void DeleteNextReceiveBuffer (uint64_t ts);
boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; };
const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; const boost::asio::ip::tcp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; }; void SetRemoteEndpoint (const boost::asio::ip::tcp::endpoint& ep) { m_RemoteEndpoint = ep; };
@ -148,7 +148,7 @@ namespace transport
void ClientLogin (); // Alice void ClientLogin (); // Alice
void ServerLogin (); // Bob void ServerLogin (); // Bob
void SendLocalRouterInfo (); // after handshake void SendLocalRouterInfo (bool update); // after handshake or by update
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
private: private:
@ -205,7 +205,6 @@ namespace transport
uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32]; uint8_t m_Kab[32], m_Kba[32], m_Sipkeysab[32], m_Sipkeysba[32];
const uint8_t * m_SendKey, * m_ReceiveKey; const uint8_t * m_SendKey, * m_ReceiveKey;
#if OPENSSL_SIPHASH #if OPENSSL_SIPHASH
EVP_PKEY * m_SendSipKey, * m_ReceiveSipKey;
EVP_MD_CTX * m_SendMDCtx, * m_ReceiveMDCtx; EVP_MD_CTX * m_SendMDCtx, * m_ReceiveMDCtx;
#else #else
const uint8_t * m_SendSipKey, * m_ReceiveSipKey; const uint8_t * m_SendSipKey, * m_ReceiveSipKey;
@ -227,7 +226,7 @@ namespace transport
uint64_t m_NextRouterInfoResendTime; // seconds since epoch uint64_t m_NextRouterInfoResendTime; // seconds since epoch
uint16_t m_PaddingSizes[16]; uint16_t m_PaddingSizes[16];
int m_NextPaddingSize; int m_NextPaddingSize;
}; };
class NTCP2Server: private i2p::util::RunnableServiceWithWork class NTCP2Server: private i2p::util::RunnableServiceWithWork
@ -259,7 +258,7 @@ namespace transport
void UseProxy(ProxyType proxy, const std::string& address, uint16_t port, const std::string& user, const std::string& pass); void UseProxy(ProxyType proxy, const std::string& address, uint16_t port, const std::string& user, const std::string& pass);
void SetLocalAddress (const boost::asio::ip::address& localAddress); void SetLocalAddress (const boost::asio::ip::address& localAddress);
private: private:
void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error); void HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error);
@ -268,7 +267,7 @@ namespace transport
void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer); void AfterSocksHandshake(std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::deadline_timer> timer);
// timer // timer
void ScheduleTermination (); void ScheduleTermination ();
void HandleTerminationTimer (const boost::system::error_code& ecode); void HandleTerminationTimer (const boost::system::error_code& ecode);
@ -286,7 +285,7 @@ namespace transport
boost::asio::ip::tcp::resolver m_Resolver; boost::asio::ip::tcp::resolver m_Resolver;
std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint; std::unique_ptr<boost::asio::ip::tcp::endpoint> m_ProxyEndpoint;
std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress; std::shared_ptr<boost::asio::ip::tcp::endpoint> m_Address4, m_Address6, m_YggdrasilAddress;
public: public:
// for HTTP/I2PControl // for HTTP/I2PControl

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2021, 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
* *
@ -56,9 +56,9 @@ namespace data
uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold); uint16_t threshold; i2p::config::GetOption("reseed.threshold", threshold);
if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils if (m_RouterInfos.size () < threshold || m_Floodfills.size () < NETDB_MIN_FLOODFILLS) // reseed if # of router less than threshold or too few floodfiils
{ {
Reseed (); Reseed ();
} }
else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false)) else if (!GetRandomRouter (i2p::context.GetSharedRouterInfo (), false))
Reseed (); // we don't have a router we can connect to. Trying to reseed Reseed (); // we don't have a router we can connect to. Trying to reseed
@ -66,14 +66,14 @@ namespace data
if (it != m_RouterInfos.end ()) if (it != m_RouterInfos.end ())
{ {
// remove own router // remove own router
m_RouterInfos.erase (it);
m_Floodfills.remove (it->second); m_Floodfills.remove (it->second);
m_RouterInfos.erase (it);
} }
// insert own router // insert own router
m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ()); m_RouterInfos.emplace (i2p::context.GetIdentHash (), i2p::context.GetSharedRouterInfo ());
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ()); m_Floodfills.push_back (i2p::context.GetSharedRouterInfo ());
i2p::config::GetOption("persist.profiles", m_PersistProfiles); i2p::config::GetOption("persist.profiles", m_PersistProfiles);
m_IsRunning = true; m_IsRunning = true;
@ -107,7 +107,10 @@ namespace data
{ {
i2p::util::SetThreadName("NetDB"); i2p::util::SetThreadName("NetDB");
uint32_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0; uint64_t lastSave = 0, lastPublish = 0, lastExploratory = 0, lastManageRequest = 0, lastDestinationCleanup = 0;
uint64_t lastProfilesCleanup = i2p::util::GetSecondsSinceEpoch ();
int16_t profilesCleanupVariance = 0;
while (m_IsRunning) while (m_IsRunning)
{ {
try try
@ -118,7 +121,7 @@ namespace data
int numMsgs = 0; int numMsgs = 0;
while (msg) while (msg)
{ {
LogPrint(eLogDebug, "NetDb: got request with type ", (int) msg->GetTypeID ()); LogPrint(eLogDebug, "NetDb: Got request with type ", (int) msg->GetTypeID ());
switch (msg->GetTypeID ()) switch (msg->GetTypeID ())
{ {
case eI2NPDatabaseStore: case eI2NPDatabaseStore:
@ -138,7 +141,7 @@ namespace data
HandleNTCP2RouterInfoMsg (msg); HandleNTCP2RouterInfoMsg (msg);
break; break;
default: // WTF? default: // WTF?
LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ()); LogPrint (eLogError, "NetDb: Unexpected message type ", (int) msg->GetTypeID ());
//i2p::HandleI2NPMessage (msg); //i2p::HandleI2NPMessage (msg);
} }
if (numMsgs > 100) break; if (numMsgs > 100) break;
@ -148,13 +151,14 @@ namespace data
} }
if (!m_IsRunning) break; if (!m_IsRunning) break;
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) // 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) // 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)
@ -164,14 +168,22 @@ namespace data
} }
lastSave = ts; lastSave = ts;
} }
if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT) if (ts - lastDestinationCleanup >= i2p::garlic::INCOMING_TAGS_EXPIRATION_TIMEOUT)
{ {
i2p::context.CleanupDestination (); i2p::context.CleanupDestination ();
lastDestinationCleanup = ts; lastDestinationCleanup = ts;
} }
// publish if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance))
if (!m_HiddenMode && i2p::transport::transports.IsOnline ()) {
DeleteObsoleteProfiles ();
lastProfilesCleanup = ts;
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
}
// publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
{ {
bool publish = false; bool publish = false;
if (m_PublishReplyToken) if (m_PublishReplyToken)
@ -179,15 +191,15 @@ namespace data
// next publishing attempt // next publishing attempt
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)
{ {
// new publish // new publish
m_PublishExcluded.clear (); m_PublishExcluded.clear ();
if (i2p::context.IsFloodfill ()) if (i2p::context.IsFloodfill ())
m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves m_PublishExcluded.insert (i2p::context.GetIdentHash ()); // do publish to ourselves
publish = true; publish = true;
} }
if (publish) // update timestamp and publish if (publish) // update timestamp and publish
{ {
i2p::context.UpdateTimestamp (ts); i2p::context.UpdateTimestamp (ts);
@ -195,6 +207,7 @@ namespace data
lastPublish = ts; lastPublish = ts;
} }
} }
if (ts - lastExploratory >= 30) // exploratory every 30 seconds if (ts - lastExploratory >= 30) // exploratory every 30 seconds
{ {
auto numRouters = m_RouterInfos.size (); auto numRouters = m_RouterInfos.size ();
@ -216,7 +229,7 @@ namespace data
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "NetDb: runtime exception: ", ex.what ()); LogPrint (eLogError, "NetDb: Runtime exception: ", ex.what ());
} }
} }
} }
@ -290,7 +303,7 @@ namespace data
if (inserted) if (inserted)
{ {
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64()); LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
{ {
std::unique_lock<std::mutex> l(m_FloodfillsMutex); std::unique_lock<std::mutex> l(m_FloodfillsMutex);
m_Floodfills.push_back (r); m_Floodfills.push_back (r);
@ -343,7 +356,7 @@ namespace data
updated = true; updated = true;
} }
else else
LogPrint (eLogError, "NetDb: new LeaseSet validation failed: ", ident.ToBase32()); LogPrint (eLogError, "NetDb: New LeaseSet validation failed: ", ident.ToBase32());
} }
return updated; return updated;
} }
@ -373,7 +386,7 @@ namespace data
} }
} }
else else
LogPrint (eLogError, "NetDb: new LeaseSet2 validation failed: ", ident.ToBase32()); LogPrint (eLogError, "NetDb: New LeaseSet2 validation failed: ", ident.ToBase32());
return false; return false;
} }
@ -430,7 +443,7 @@ namespace data
int riLen = ri->GetBufferLen(); int riLen = ri->GetBufferLen();
if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) { if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) {
// bad router info // bad router info
LogPrint(eLogError, "NetDb: bad router info"); LogPrint(eLogError, "NetDb: Bad router info");
return; return;
} }
m_FloodfillBootstrap = ri; m_FloodfillBootstrap = ri;
@ -445,7 +458,7 @@ namespace data
void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills) void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills)
{ {
LogPrint(eLogInfo, "NetDB: reseeding from floodfill ", ri.GetIdentHashBase64()); LogPrint(eLogInfo, "NetDB: Reseeding from floodfill ", ri.GetIdentHashBase64());
std::vector<std::shared_ptr<i2p::I2NPMessage> > requests; std::vector<std::shared_ptr<i2p::I2NPMessage> > requests;
i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash(); i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash();
@ -472,22 +485,22 @@ namespace data
i2p::transport::transports.SendMessages(ih, requests); i2p::transport::transports.SendMessages(ih, requests);
} }
bool NetDb::LoadRouterInfo (const std::string & path) bool NetDb::LoadRouterInfo (const std::string& path, uint64_t ts)
{ {
auto r = std::make_shared<RouterInfo>(path); auto r = std::make_shared<RouterInfo>(path);
if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses ()) if (r->GetRouterIdentity () && !r->IsUnreachable () && r->HasValidAddresses () &&
{ ts < r->GetTimestamp () + 24*60*60*NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT*1000LL)
{
r->DeleteBuffer (); r->DeleteBuffer ();
r->ClearProperties (); // properties are not used for regular routers
if (m_RouterInfos.emplace (r->GetIdentHash (), r).second) if (m_RouterInfos.emplace (r->GetIdentHash (), r).second)
{ {
if (r->IsFloodfill () && r->IsEligibleFloodfill ()) if (r->IsFloodfill () && r->IsEligibleFloodfill ())
m_Floodfills.push_back (r); m_Floodfills.push_back (r);
} }
} }
else else
{ {
LogPrint(eLogWarning, "NetDb: RI from ", path, " is invalid. Delete"); LogPrint(eLogWarning, "NetDb: RI from ", path, " is invalid or too old. Delete");
i2p::fs::Remove(path); i2p::fs::Remove(path);
} }
return true; return true;
@ -568,11 +581,11 @@ namespace data
m_RouterInfos.clear (); m_RouterInfos.clear ();
m_Floodfills.clear (); m_Floodfills.clear ();
m_LastLoad = i2p::util::GetSecondsSinceEpoch(); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch();
std::vector<std::string> files; std::vector<std::string> files;
m_Storage.Traverse(files); m_Storage.Traverse(files);
for (const auto& path : files) for (const auto& path : files)
LoadRouterInfo(path); LoadRouterInfo (path, ts);
LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)"); LogPrint (eLogInfo, "NetDb: ", m_RouterInfos.size(), " routers loaded (", m_Floodfills.size (), " floodfils)");
} }
@ -591,15 +604,14 @@ namespace data
expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL : expirationTimeout = i2p::context.IsFloodfill () ? NETDB_FLOODFILL_EXPIRATION_TIMEOUT*1000LL :
NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total; NETDB_MIN_EXPIRATION_TIMEOUT*1000LL + (NETDB_MAX_EXPIRATION_TIMEOUT - NETDB_MIN_EXPIRATION_TIMEOUT)*1000LL*NETDB_MIN_ROUTERS/total;
auto own = i2p::context.GetSharedRouterInfo (); auto own = i2p::context.GetSharedRouterInfo ();
for (auto& it: m_RouterInfos) for (auto& it: m_RouterInfos)
{ {
if (it.second == own) continue; // skip own if (it.second == own) continue; // skip own
std::string ident = it.second->GetIdentHashBase64(); std::string ident = it.second->GetIdentHashBase64();
std::string path = m_Storage.Path(ident);
if (it.second->IsUpdated ()) if (it.second->IsUpdated ())
{ {
it.second->SaveToFile (path); it.second->SaveToFile (m_Storage.Path(ident));
it.second->SetUpdated (false); it.second->SetUpdated (false);
it.second->SetUnreachable (false); it.second->SetUnreachable (false);
it.second->DeleteBuffer (); it.second->DeleteBuffer ();
@ -608,8 +620,8 @@ namespace data
} }
// 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 || if (it.second->IsUnreachable () && (total - deletedCount < NETDB_MIN_ROUTERS ||
(it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS))) (it.second->IsFloodfill () && totalFloodfills - deletedFloodfillsCount < NETDB_MIN_FLOODFILLS)))
it.second->SetUnreachable (false); it.second->SetUnreachable (false);
// find & mark expired routers // find & mark expired routers
if (!it.second->IsReachable () && it.second->IsSSU (false)) if (!it.second->IsReachable () && it.second->IsSSU (false))
{ {
@ -626,15 +638,17 @@ namespace data
// delete RI file // delete RI file
m_Storage.Remove(ident); m_Storage.Remove(ident);
deletedCount++; deletedCount++;
if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false; if (total - deletedCount < NETDB_MIN_ROUTERS) checkForExpiration = false;
} }
} // m_RouterInfos iteration } // m_RouterInfos iteration
m_RouterInfoBuffersPool.CleanUpMt ();
if (updatedCount > 0) if (updatedCount > 0)
LogPrint (eLogInfo, "NetDb: saved ", updatedCount, " new/updated routers"); LogPrint (eLogInfo, "NetDb: Saved ", updatedCount, " new/updated routers");
if (deletedCount > 0) if (deletedCount > 0)
{ {
LogPrint (eLogInfo, "NetDb: deleting ", deletedCount, " unreachable routers"); LogPrint (eLogInfo, "NetDb: Deleting ", deletedCount, " unreachable routers");
// clean up RouterInfos table // clean up RouterInfos table
{ {
std::unique_lock<std::mutex> l(m_RouterInfosMutex); std::unique_lock<std::mutex> l(m_RouterInfosMutex);
@ -666,7 +680,7 @@ namespace data
auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory auto dest = m_Requests.CreateRequest (destination, false, requestComplete); // non-exploratory
if (!dest) if (!dest)
{ {
LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already"); LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
return; return;
} }
@ -674,24 +688,24 @@ namespace data
if (floodfill) if (floodfill)
{ {
if (direct && !floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) && if (direct && !floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) &&
!i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) !i2p::transport::transports.IsConnected (floodfill->GetIdentHash ()))
direct = false; // floodfill can't be reached directly direct = false; // floodfill can't be reached directly
if (direct) if (direct)
transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ())); transports.SendMessage (floodfill->GetIdentHash (), dest->CreateRequestMessage (floodfill->GetIdentHash ()));
else else
{ {
auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = pool ? pool->GetNextOutboundTunnel () : nullptr; auto outbound = pool ? pool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = pool ? pool->GetNextInboundTunnel () : nullptr; auto inbound = pool ? pool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (outbound && inbound) if (outbound && inbound)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound)); outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound));
else else
{ {
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found"); LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no tunnels found");
m_Requests.RequestComplete (destination, nullptr); m_Requests.RequestComplete (destination, nullptr);
} }
} }
} }
else else
{ {
LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found"); LogPrint (eLogError, "NetDb: ", destination.ToBase64(), " destination requested, but no floodfills found");
@ -705,10 +719,10 @@ namespace data
auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory
if (!dest) if (!dest)
{ {
LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already"); LogPrint (eLogWarning, "NetDb: Destination ", destination.ToBase64(), " is requested already");
return; return;
} }
LogPrint(eLogInfo, "NetDb: destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64()); LogPrint(eLogInfo, "NetDb: Destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64());
// direct // direct
transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr)); transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr));
} }
@ -732,7 +746,7 @@ namespace data
IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET); IdentHash ident (buf + DATABASE_STORE_KEY_OFFSET);
if (ident.IsZero ()) if (ident.IsZero ())
{ {
LogPrint (eLogDebug, "NetDb: database store with zero ident, dropped"); LogPrint (eLogDebug, "NetDb: Database store with zero ident, dropped");
return; return;
} }
uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET); uint32_t replyToken = bufbe32toh (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET);
@ -751,14 +765,14 @@ namespace data
if (outbound) if (outbound)
outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus); outbound->SendTunnelDataMsg (buf + offset, tunnelID, deliveryStatus);
else else
LogPrint (eLogWarning, "NetDb: no outbound tunnels for DatabaseStore reply found"); LogPrint (eLogWarning, "NetDb: No outbound tunnels for DatabaseStore reply found");
} }
offset += 32; offset += 32;
} }
// we must send reply back before this check // we must send reply back before this check
if (ident == i2p::context.GetIdentHash ()) if (ident == i2p::context.GetIdentHash ())
{ {
LogPrint (eLogDebug, "NetDb: database store with own RouterInfo received, dropped"); LogPrint (eLogDebug, "NetDb: Database store with own RouterInfo received, dropped");
return; return;
} }
size_t payloadOffset = offset; size_t payloadOffset = offset;
@ -771,24 +785,24 @@ namespace data
{ {
if (storeType == NETDB_STORE_TYPE_LEASESET) // 1 if (storeType == NETDB_STORE_TYPE_LEASESET) // 1
{ {
LogPrint (eLogDebug, "NetDb: store request: LeaseSet for ", ident.ToBase32()); LogPrint (eLogDebug, "NetDb: Store request: LeaseSet for ", ident.ToBase32());
updated = AddLeaseSet (ident, buf + offset, len - offset); updated = AddLeaseSet (ident, buf + offset, len - offset);
} }
else // all others are considered as LeaseSet2 else // all others are considered as LeaseSet2
{ {
LogPrint (eLogDebug, "NetDb: store request: LeaseSet2 of type ", 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);
} }
} }
} }
else // RouterInfo else // RouterInfo
{ {
LogPrint (eLogDebug, "NetDb: store request: RouterInfo"); LogPrint (eLogDebug, "NetDb: Store request: RouterInfo");
size_t size = bufbe16toh (buf + offset); size_t size = bufbe16toh (buf + offset);
offset += 2; offset += 2;
if (size > MAX_RI_BUFFER_SIZE || size > len - offset) if (size > MAX_RI_BUFFER_SIZE || size > len - offset)
{ {
LogPrint (eLogError, "NetDb: invalid RouterInfo length ", (int)size); LogPrint (eLogError, "NetDb: Invalid RouterInfo length ", (int)size);
return; return;
} }
uint8_t uncompressed[MAX_RI_BUFFER_SIZE]; uint8_t uncompressed[MAX_RI_BUFFER_SIZE];
@ -797,7 +811,7 @@ namespace data
updated = AddRouterInfo (ident, uncompressed, uncompressedSize); updated = AddRouterInfo (ident, uncompressed, uncompressedSize);
else else
{ {
LogPrint (eLogInfo, "NetDb: decompression failed ", uncompressedSize); LogPrint (eLogInfo, "NetDb: Decompression failed ", uncompressedSize);
return; return;
} }
} }
@ -872,7 +886,7 @@ namespace data
m_Requests.RequestComplete (ident, nullptr); m_Requests.RequestComplete (ident, nullptr);
} }
else if(!m_FloodfillBootstrap) else if(!m_FloodfillBootstrap)
LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found"); LogPrint (eLogWarning, "NetDb: Requested destination for ", key, " not found");
// try responses // try responses
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
@ -887,7 +901,7 @@ namespace data
if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL) if (!r || i2p::util::GetMillisecondsSinceEpoch () > r->GetTimestamp () + 3600*1000LL)
{ {
// router with ident not found or too old (1 hour) // router with ident not found or too old (1 hour)
LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ..."); LogPrint (eLogDebug, "NetDb: Found new/outdated router. Requesting RouterInfo...");
if(m_FloodfillBootstrap) if(m_FloodfillBootstrap)
RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true); RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true);
else else
@ -928,14 +942,14 @@ namespace data
excluded += 2; excluded += 2;
if (numExcluded > 512) if (numExcluded > 512)
{ {
LogPrint (eLogWarning, "NetDb: number of excluded peers", numExcluded, " exceeds 512"); LogPrint (eLogWarning, "NetDb: Number of excluded peers", numExcluded, " exceeds 512");
return; return;
} }
std::shared_ptr<I2NPMessage> replyMsg; std::shared_ptr<I2NPMessage> replyMsg;
if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP) if (lookupType == DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP)
{ {
LogPrint (eLogInfo, "NetDb: exploratory close to ", key, " ", numExcluded, " excluded"); LogPrint (eLogInfo, "NetDb: Exploratory close to ", key, " ", numExcluded, " excluded");
std::set<IdentHash> excludedRouters; std::set<IdentHash> excludedRouters;
for (int i = 0; i < numExcluded; i++) for (int i = 0; i < numExcluded; i++)
{ {
@ -957,14 +971,13 @@ namespace data
else else
{ {
if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP || if (lookupType == DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP ||
lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP) lookupType == DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP)
{ {
auto router = FindRouter (ident); auto router = FindRouter (ident);
if (router) if (router)
{ {
LogPrint (eLogDebug, "NetDb: requested RouterInfo ", key, " found"); LogPrint (eLogDebug, "NetDb: Requested RouterInfo ", key, " found");
if (!router->GetBuffer ()) PopulateRouterInfoBuffer (router);
router->LoadBuffer (m_Storage.Path (router->GetIdentHashBase64 ()));
if (router->GetBuffer ()) if (router->GetBuffer ())
replyMsg = CreateDatabaseStoreMsg (router); replyMsg = CreateDatabaseStoreMsg (router);
} }
@ -977,11 +990,11 @@ namespace data
if (!leaseSet) if (!leaseSet)
{ {
// no lease set found // no lease set found
LogPrint(eLogDebug, "NetDb: requested LeaseSet not found for ", ident.ToBase32()); LogPrint(eLogDebug, "NetDb: Requested LeaseSet not found for ", ident.ToBase32());
} }
else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets else if (!leaseSet->IsExpired ()) // we don't send back our LeaseSets
{ {
LogPrint (eLogDebug, "NetDb: requested LeaseSet ", key, " found"); LogPrint (eLogDebug, "NetDb: Requested LeaseSet ", key, " found");
replyMsg = CreateDatabaseStoreMsg (ident, leaseSet); replyMsg = CreateDatabaseStoreMsg (ident, leaseSet);
} }
} }
@ -1026,10 +1039,10 @@ namespace data
replyMsg = garlic.WrapSingleMessage (replyMsg); replyMsg = garlic.WrapSingleMessage (replyMsg);
} }
if (!replyMsg) if (!replyMsg)
LogPrint (eLogError, "NetDb: failed to wrap message"); LogPrint (eLogError, "NetDb: Failed to wrap message");
} }
else else
LogPrint(eLogWarning, "NetDb: encrypted reply requested but no tags provided"); LogPrint(eLogWarning, "NetDb: Encrypted reply requested but no tags provided");
} }
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr; auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr;
@ -1051,8 +1064,8 @@ namespace data
m_PublishExcluded.clear (); m_PublishExcluded.clear ();
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
} }
} }
void NetDb::Explore (int numDestinations) void NetDb::Explore (int numDestinations)
{ {
// new requests // new requests
@ -1063,14 +1076,14 @@ namespace data
uint8_t randomHash[32]; uint8_t randomHash[32];
std::vector<i2p::tunnel::TunnelMessageBlock> msgs; std::vector<i2p::tunnel::TunnelMessageBlock> msgs;
LogPrint (eLogInfo, "NetDb: exploring new ", numDestinations, " routers ..."); LogPrint (eLogInfo, "NetDb: Exploring new ", numDestinations, " routers ...");
for (int i = 0; i < numDestinations; i++) for (int i = 0; i < numDestinations; i++)
{ {
RAND_bytes (randomHash, 32); RAND_bytes (randomHash, 32);
auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory auto dest = m_Requests.CreateRequest (randomHash, true); // exploratory
if (!dest) if (!dest)
{ {
LogPrint (eLogWarning, "NetDb: exploratory destination is requested already"); LogPrint (eLogWarning, "NetDb: Exploratory destination is requested already");
return; return;
} }
auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ());
@ -1112,7 +1125,7 @@ namespace data
LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again"); LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
m_PublishExcluded.clear (); m_PublishExcluded.clear ();
} }
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded); auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
if (floodfill) if (floodfill)
{ {
@ -1122,19 +1135,19 @@ namespace data
m_PublishExcluded.insert (floodfill->GetIdentHash ()); m_PublishExcluded.insert (floodfill->GetIdentHash ());
m_PublishReplyToken = replyToken; m_PublishReplyToken = replyToken;
if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect? if (floodfill->IsReachableFrom (i2p::context.GetRouterInfo ()) || // are we able to connect?
i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ? i2p::transport::transports.IsConnected (floodfill->GetIdentHash ())) // already connected ?
// send directly // send directly
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
else else
{ {
// otherwise through exploratory // otherwise through exploratory
auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool (); auto exploratoryPool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel () : nullptr; auto outbound = exploratoryPool ? exploratoryPool->GetNextOutboundTunnel (nullptr, floodfill->GetCompatibleTransports (false)) : nullptr;
auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel () : nullptr; auto inbound = exploratoryPool ? exploratoryPool->GetNextInboundTunnel (nullptr, floodfill->GetCompatibleTransports (true)) : nullptr;
if (inbound && outbound) if (inbound && outbound)
outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0,
CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound)); CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken, inbound));
} }
} }
} }
@ -1174,7 +1187,7 @@ namespace data
{ {
return !router->IsHidden () && router != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
(reverse ? compatibleWith->IsReachableFrom (*router) : (reverse ? compatibleWith->IsReachableFrom (*router) :
router->IsReachableFrom (*compatibleWith)) && router->IsReachableFrom (*compatibleWith)) &&
router->IsECIES (); router->IsECIES ();
}); });
} }
@ -1184,11 +1197,21 @@ namespace data
return GetRandomRouter ( return GetRandomRouter (
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool [v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
{ {
return !router->IsHidden () && router->IsECIES () && return !router->IsHidden () && router->IsECIES () &&
router->IsPeerTesting (v4) && !excluded.count (router->GetIdentHash ()); router->IsPeerTesting (v4) && !excluded.count (router->GetIdentHash ());
}); });
} }
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const
{
return GetRandomRouter (
[v4, &excluded](std::shared_ptr<const RouterInfo> router)->bool
{
return !router->IsHidden () && router->IsECIES () &&
router->IsSSU2PeerTesting (v4) && !excluded.count (router->GetIdentHash ());
});
}
std::shared_ptr<const RouterInfo> NetDb::GetRandomSSUV6Router () const std::shared_ptr<const RouterInfo> NetDb::GetRandomSSUV6Router () const
{ {
return GetRandomRouter ( return GetRandomRouter (
@ -1216,7 +1239,7 @@ namespace data
return !router->IsHidden () && router != compatibleWith && return !router->IsHidden () && router != compatibleWith &&
(reverse ? compatibleWith->IsReachableFrom (*router) : (reverse ? compatibleWith->IsReachableFrom (*router) :
router->IsReachableFrom (*compatibleWith)) && router->IsReachableFrom (*compatibleWith)) &&
(router->GetCaps () & RouterInfo::eHighBandwidth) && (router->GetCaps () & RouterInfo::eHighBandwidth) &&
router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION && router->GetVersion () >= NETDB_MIN_HIGHBANDWIDTH_VERSION &&
router->IsECIES (); router->IsECIES ();
}); });
@ -1238,12 +1261,12 @@ namespace data
return it->second; return it->second;
// try some routers around // try some routers around
auto it1 = m_RouterInfos.begin (); auto it1 = m_RouterInfos.begin ();
if (inds[0]) if (inds[0])
{ {
// before // before
inds[1] %= inds[0]; inds[1] %= inds[0];
std::advance (it1, (inds[1] + inds[0])/2); std::advance (it1, (inds[1] + inds[0])/2);
} }
else else
it1 = it; it1 = it;
auto it2 = it; auto it2 = it;
@ -1254,14 +1277,14 @@ namespace data
std::advance (it2, inds[2]); std::advance (it2, inds[2]);
} }
// it1 - from, it2 - to // it1 - from, it2 - to
it = it1; it = it1;
while (it != it2 && it != m_RouterInfos.end ()) while (it != it2 && it != m_RouterInfos.end ())
{ {
if (!it->second->IsUnreachable () && filter (it->second)) if (!it->second->IsUnreachable () && filter (it->second))
return it->second; return it->second;
it++; it++;
} }
// still not found, try from the begining // still not found, try from the beginning
it = m_RouterInfos.begin (); it = m_RouterInfos.begin ();
while (it != it1 && it != m_RouterInfos.end ()) while (it != it1 && it != m_RouterInfos.end ())
{ {
@ -1269,7 +1292,7 @@ namespace data
return it->second; return it->second;
it++; it++;
} }
// still not found, try to the begining // still not found, try to the beginning
it = it2; it = it2;
while (it != m_RouterInfos.end ()) while (it != m_RouterInfos.end ())
{ {
@ -1363,7 +1386,8 @@ namespace data
return res; return res;
} }
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily(const std::string & fam) const { std::shared_ptr<const RouterInfo> NetDb::GetRandomRouterInFamily (FamilyID fam) const
{
return GetRandomRouter( return GetRandomRouter(
[fam](std::shared_ptr<const RouterInfo> router)->bool [fam](std::shared_ptr<const RouterInfo> router)->bool
{ {
@ -1408,5 +1432,11 @@ namespace data
++it; ++it;
} }
} }
void NetDb::PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r)
{
if (!r || r->GetBuffer ()) return;
r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
}
} }
} }

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