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

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

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
set MSYSTEM=MINGW32
set bitness=32
set "WD=C:\msys64-xp\usr\bin\"
set "xSH=%WD%bash -lc"
%xSH% "make clean" >> nul %xSH% "make clean" >> nul
echo Building i2pd %tag% for winxp echo Building i2pd %tag% for winxp...
%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 %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 :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 ();
} }
@ -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;
} }
} }

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;
} }
@ -286,7 +289,7 @@ namespace data
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
* *
@ -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
@ -1305,6 +1305,16 @@ 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);
@ -1320,7 +1330,7 @@ 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)
@ -1336,7 +1346,7 @@ namespace crypto
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
@ -1349,6 +1359,21 @@ namespace crypto
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)
{ {
static const uint8_t protocolNameHash[32] = static const uint8_t protocolNameHash[32] =

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
@ -104,7 +108,7 @@ 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
@ -315,11 +319,13 @@ 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 MixHash (const std::vector<std::pair<uint8_t *, size_t> >& bufs);
void MixKey (const uint8_t * sharedSecret); 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
@ -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

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

@ -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,9 +93,7 @@ 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 ())
@ -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));
@ -396,7 +417,7 @@ namespace client
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))
@ -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)
@ -910,7 +951,7 @@ 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 ();
@ -925,7 +966,7 @@ namespace client
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,7 +979,7 @@ namespace client
m_StreamingAckDelay = std::stoi(it->second); m_StreamingAckDelay = std::stoi(it->second);
it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS); it = params->find (I2CP_PARAM_STREAMING_ANSWER_PINGS);
if (it != params->end ()) if (it != params->end ())
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)
{ {
@ -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 ();
@ -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";
@ -134,6 +138,7 @@ 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 ();

View File

@ -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)
@ -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
@ -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
@ -700,7 +700,7 @@ 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;
@ -776,7 +776,7 @@ namespace garlic
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);
@ -912,7 +912,7 @@ 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;
@ -1056,7 +1056,7 @@ namespace garlic
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;
} }
} }

View File

@ -1,4 +1,3 @@
/* /*
* Copyright (c) 2013-2021, The PurpleI2P Project * Copyright (c) 2013-2021, The PurpleI2P Project
* *
@ -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
@ -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

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++;
} }
@ -484,13 +484,18 @@ namespace garlic
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
@ -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,18 +547,18 @@ 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)
@ -567,7 +572,7 @@ namespace garlic
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
@ -586,7 +591,7 @@ 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;
} }
@ -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;
@ -780,7 +785,7 @@ namespace garlic
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;
} }
} }
@ -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);
} }
@ -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);
} }
} }
@ -1105,7 +1110,7 @@ namespace garlic
} }
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;
} }
} }

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
* *
@ -245,6 +245,7 @@ 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);

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

@ -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,7 +471,7 @@ 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;
} }

View File

@ -161,7 +161,7 @@ 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
*/ */

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;
} }
@ -184,7 +171,7 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::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 ();
@ -642,7 +629,7 @@ namespace i2p
// 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

@ -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 (); };
@ -274,8 +274,8 @@ namespace tunnel
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;
} }
@ -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;
@ -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);
@ -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 ();
@ -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

@ -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);
@ -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;
} }
@ -80,10 +80,10 @@ namespace data
} }
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;
} }
@ -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;
} }
@ -130,7 +130,7 @@ namespace data
} }
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;
@ -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,14 +320,15 @@ 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),
@ -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");
} }
} }
@ -417,7 +418,7 @@ namespace transport
void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts) void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
{ {
if (m_NextReceivedBuffer && !m_IsReceiving && if (m_NextReceivedBuffer && !m_IsReceiving &&
ts > 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;
@ -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)
@ -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
* *
@ -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);
@ -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;

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
* *
@ -66,8 +66,8 @@ 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 ());
@ -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;
@ -155,6 +158,7 @@ namespace data
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,12 +168,20 @@ 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;
} }
if (ts - lastProfilesCleanup >= (uint64_t)(i2p::data::PEER_PROFILE_AUTOCLEAN_TIMEOUT + profilesCleanupVariance))
{
DeleteObsoleteProfiles ();
lastProfilesCleanup = ts;
profilesCleanupVariance = (rand () % (2 * i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE) - i2p::data::PEER_PROFILE_AUTOCLEAN_VARIANCE);
}
// publish // publish
if (!m_HiddenMode && i2p::transport::transports.IsOnline ()) if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
{ {
@ -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 ());
} }
} }
} }
@ -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,13 +485,13 @@ 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 ())
@ -487,7 +500,7 @@ namespace data
} }
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)");
} }
@ -596,10 +609,9 @@ namespace data
{ {
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,7 +620,7 @@ 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))
@ -630,11 +642,13 @@ namespace data
} }
} // 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,15 +688,15 @@ 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
@ -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;
@ -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 ());
@ -1122,15 +1135,15 @@ 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));
@ -1189,6 +1202,16 @@ namespace data
}); });
} }
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 (
@ -1261,7 +1284,7 @@ namespace data
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 ()));
}
} }
} }

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
* *
@ -30,6 +30,7 @@
#include "NetDbRequests.h" #include "NetDbRequests.h"
#include "Family.h" #include "Family.h"
#include "version.h" #include "version.h"
#include "util.h"
namespace i2p namespace i2p
{ {
@ -41,6 +42,7 @@ namespace data
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60; const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65 * 60;
const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours
const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours
const int NETDB_MAX_OFFLINE_EXPIRATION_TIMEOUT = 180; // in days
const int NETDB_PUBLISH_INTERVAL = 60 * 40; const int NETDB_PUBLISH_INTERVAL = 60 * 40;
const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
@ -88,13 +90,14 @@ namespace data
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const; std::shared_ptr<const RouterInfo> GetHighBandwidthRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith, bool reverse) const;
std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetRandomPeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSU2PeerTestRouter (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomSSUV6Router () const; // TODO: change to v6 peer test later std::shared_ptr<const RouterInfo> GetRandomSSUV6Router () const; // TODO: change to v6 peer test later
std::shared_ptr<const RouterInfo> GetRandomIntroducer (bool v4, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetRandomIntroducer (bool v4, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::shared_ptr<const RouterInfo> GetClosestFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num, std::vector<IdentHash> GetClosestFloodfills (const IdentHash& destination, size_t num,
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const; std::shared_ptr<const RouterInfo> GetRandomRouterInFamily (FamilyID fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
@ -120,13 +123,15 @@ namespace data
size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n);
void ClearRouterInfos () { m_RouterInfos.clear (); }; void ClearRouterInfos () { m_RouterInfos.clear (); };
std::shared_ptr<RouterInfo::Buffer> NewRouterInfoBuffer () { return m_RouterInfoBuffersPool.AcquireSharedMt (); };
void PopulateRouterInfoBuffer (std::shared_ptr<RouterInfo> r);
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; }; uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
private: private:
void Load (); void Load ();
bool LoadRouterInfo (const std::string & path); bool LoadRouterInfo (const std::string& path, uint64_t ts);
void SaveUpdated (); void SaveUpdated ();
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
@ -153,7 +158,6 @@ namespace data
std::list<std::shared_ptr<RouterInfo> > m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
bool m_IsRunning; bool m_IsRunning;
uint64_t m_LastLoad;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
@ -175,6 +179,8 @@ namespace data
std::set<IdentHash> m_PublishExcluded; std::set<IdentHash> m_PublishExcluded;
uint32_t m_PublishReplyToken = 0; uint32_t m_PublishReplyToken = 0;
i2p::util::MemoryPoolMt<RouterInfo::Buffer> m_RouterInfoBuffersPool;
}; };
extern NetDb netdb; extern NetDb netdb;

View File

@ -60,7 +60,7 @@ namespace data
void Start (); void Start ();
void Stop (); void Stop ();
std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr); std::shared_ptr<RequestedDestination> CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r); void RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r);
std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const; std::shared_ptr<RequestedDestination> FindRequest (const IdentHash& ident) const;
void ManageRequests (); void ManageRequests ();

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