mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-04-23 17:36:37 +02:00
commit
2ff6f9d346
86 changed files with 1781 additions and 1241 deletions
20
.github/workflows/build-osx.yml
vendored
Normal file
20
.github/workflows/build-osx.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
name: Build on OSX
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: With USE_UPNP=${{ matrix.with_upnp }}
|
||||||
|
runs-on: macOS-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
with_upnp: ['yes', 'no']
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: install packages
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
|
brew install boost miniupnpc openssl@1.1
|
||||||
|
- name: build application
|
||||||
|
run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3
|
4
.github/workflows/build-windows.yml
vendored
4
.github/workflows/build-windows.yml
vendored
|
@ -26,4 +26,6 @@ jobs:
|
||||||
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: make USE_UPNP=yes DEBUG=no -j3
|
run: |
|
||||||
|
mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon
|
||||||
|
make USE_UPNP=yes DEBUG=no -j3
|
||||||
|
|
22
.github/workflows/build.yml
vendored
22
.github/workflows/build.yml
vendored
|
@ -1,10 +1,10 @@
|
||||||
name: Build on Ubuntu with make
|
name: Build on Ubuntu
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Building with USE_UPNP=${{ matrix.with_upnp }} flag
|
name: With USE_UPNP=${{ matrix.with_upnp }}
|
||||||
runs-on: ubuntu-16.04
|
runs-on: ubuntu-16.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
|
@ -18,4 +18,20 @@ jobs:
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev
|
sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev
|
||||||
- name: build application
|
- name: build application
|
||||||
run: make USE_AVX=no USE_AESNI=no USE_UPNP=${{ matrix.with_upnp }} -j3
|
run: make USE_UPNP=${{ matrix.with_upnp }} -j3
|
||||||
|
|
||||||
|
build_qt:
|
||||||
|
name: With QT GUI
|
||||||
|
runs-on: ubuntu-16.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: install packages
|
||||||
|
run: |
|
||||||
|
sudo add-apt-repository ppa:mhier/libboost-latest
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev
|
||||||
|
- name: build application
|
||||||
|
run: |
|
||||||
|
cd qt/i2pd_qt
|
||||||
|
qmake
|
||||||
|
make -j3
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -3,11 +3,12 @@
|
||||||
router.info
|
router.info
|
||||||
router.keys
|
router.keys
|
||||||
i2p
|
i2p
|
||||||
libi2pd.so
|
|
||||||
netDb
|
netDb
|
||||||
/i2pd
|
/i2pd
|
||||||
/libi2pd.a
|
/libi2pd.a
|
||||||
/libi2pdclient.a
|
/libi2pdclient.a
|
||||||
|
/libi2pd.so
|
||||||
|
/libi2pdclient.so
|
||||||
*.exe
|
*.exe
|
||||||
|
|
||||||
|
|
||||||
|
|
51
ChangeLog
51
ChangeLog
|
@ -1,6 +1,57 @@
|
||||||
# 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.35.0] - 2020-11-30
|
||||||
|
### Added
|
||||||
|
- ECIES-x25519 routers
|
||||||
|
- Random intro keys for SSU
|
||||||
|
- Graceful shutdown timer for windows
|
||||||
|
- Send queue for I2CP messages
|
||||||
|
- Update DSA router keys to EdDSA
|
||||||
|
- TCP_QUICKACK for NTCP2 sockets on Linux
|
||||||
|
### Changed
|
||||||
|
- Exclude floodfills with DSA signatures and < 0.9.28
|
||||||
|
- Random intervals between tunnel tests and manage for tunnel pools
|
||||||
|
- Don't replace an addressbook record by one with DSA signature
|
||||||
|
- Publish RouterInfo after update
|
||||||
|
- Create paired inbound tunnels if no inbound tunnels yet
|
||||||
|
- Reseed servers list
|
||||||
|
### Fixed
|
||||||
|
- Transient signature length, if different from identity
|
||||||
|
- Terminate I2CP session if destroyed
|
||||||
|
- RouterInfo publishing confirmation
|
||||||
|
- Check if ECIES-X25519-AEAD-Ratchet session expired before generating more tags
|
||||||
|
- Correct block size for delivery type local for ECIES-X25519-AEAD-Ratchet
|
||||||
|
|
||||||
|
## [2.34.0] - 2020-10-27
|
||||||
|
### Added
|
||||||
|
- Ping responses for streaming
|
||||||
|
- STREAM FORWARD for SAM
|
||||||
|
- Tunnels through ECIES-x25519 routers
|
||||||
|
- Single thread for I2CP
|
||||||
|
- Shared transient destination between proxies
|
||||||
|
- Database lookups from ECIES destinations with ratchets response
|
||||||
|
- Handle WebDAV HTTP methods
|
||||||
|
- Don't try to connect or build tunnels if offline
|
||||||
|
- Validate IP when trying connect to remote peer
|
||||||
|
- Handle ICMP responses and WinAPI errors for SSU
|
||||||
|
### Changed
|
||||||
|
- Removed NTCP
|
||||||
|
- Dropped gcc 4.7 support
|
||||||
|
- Encyption type 0,4 by default for client tunnels
|
||||||
|
- Stripped out some HTTP header for HTTP server response
|
||||||
|
- HTTP 1.1 addressbook requests
|
||||||
|
- Set LeaseSet type to 3 for ratchets if not specified
|
||||||
|
- Handle SSU v4 and v6 messages in one thread
|
||||||
|
- Eliminate DH keys thread
|
||||||
|
### Fixed
|
||||||
|
- Random crashes on I2CP session disconnect
|
||||||
|
- Stream through racthets hangs if first SYN was not acked
|
||||||
|
- Check "Last-Modified" instead "If-Modified-Since" for addressbook reponse
|
||||||
|
- Trim behind ECIESx25519 tags
|
||||||
|
- Few bugs with Android main activity
|
||||||
|
- QT visual and layout issues
|
||||||
|
|
||||||
## [2.33.0] - 2020-08-24
|
## [2.33.0] - 2020-08-24
|
||||||
### Added
|
### Added
|
||||||
- Shared transient addresses
|
- Shared transient addresses
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2013-2015, The PurpleI2P Project
|
Copyright (c) 2013-2020, The PurpleI2P Project
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
|
|
36
Makefile
36
Makefile
|
@ -4,17 +4,15 @@ ARLIB := libi2pd.a
|
||||||
SHLIB_CLIENT := libi2pdclient.so
|
SHLIB_CLIENT := libi2pdclient.so
|
||||||
ARLIB_CLIENT := libi2pdclient.a
|
ARLIB_CLIENT := libi2pdclient.a
|
||||||
I2PD := i2pd
|
I2PD := i2pd
|
||||||
GREP := grep
|
|
||||||
DEPS := obj/make.dep
|
|
||||||
|
|
||||||
LIB_SRC_DIR := libi2pd
|
LIB_SRC_DIR := libi2pd
|
||||||
LIB_CLIENT_SRC_DIR := libi2pd_client
|
LIB_CLIENT_SRC_DIR := libi2pd_client
|
||||||
DAEMON_SRC_DIR := daemon
|
DAEMON_SRC_DIR := daemon
|
||||||
|
|
||||||
|
# import source files lists
|
||||||
include filelist.mk
|
include filelist.mk
|
||||||
|
|
||||||
USE_AESNI := yes
|
USE_AESNI := yes
|
||||||
USE_AVX := yes
|
|
||||||
USE_STATIC := no
|
USE_STATIC := no
|
||||||
USE_MESHNET := no
|
USE_MESHNET := no
|
||||||
USE_UPNP := no
|
USE_UPNP := no
|
||||||
|
@ -51,7 +49,12 @@ ifeq ($(USE_MESHNET),yes)
|
||||||
NEEDED_CXXFLAGS += -DMESHNET
|
NEEDED_CXXFLAGS += -DMESHNET
|
||||||
endif
|
endif
|
||||||
|
|
||||||
NEEDED_CXXFLAGS += -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR)
|
NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR)
|
||||||
|
|
||||||
|
LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
||||||
|
LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
||||||
|
DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
|
||||||
|
DEPS += $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d)
|
||||||
|
|
||||||
all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
|
all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD)
|
||||||
|
|
||||||
|
@ -72,32 +75,29 @@ api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT)
|
||||||
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
## -std=c++11. If you want to remove this variable please do so in a way that allows setting
|
||||||
## custom FLAGS to work at build-time.
|
## custom FLAGS to work at build-time.
|
||||||
|
|
||||||
deps: mk_obj_dir
|
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS)
|
|
||||||
@sed -i -e '/\.o:/ s/^/obj\//' $(DEPS)
|
|
||||||
|
|
||||||
obj/%.o: %.cpp
|
obj/%.o: %.cpp
|
||||||
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $<
|
$(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
# '-' is 'ignore if missing' on first run
|
# '-' is 'ignore if missing' on first run
|
||||||
-include $(DEPS)
|
-include $(DEPS)
|
||||||
|
|
||||||
DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC))
|
|
||||||
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT)
|
$(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT)
|
||||||
$(CXX) -o $@ $^ $(LDFLAGS) $(LDLIBS)
|
$(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS)
|
||||||
|
|
||||||
$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
$(SHLIB): $(LIB_OBJS)
|
||||||
ifneq ($(USE_STATIC),yes)
|
ifneq ($(USE_STATIC),yes)
|
||||||
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
$(SHLIB_CLIENT): $(LIB_CLIENT_OBJS)
|
||||||
$(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^
|
ifneq ($(USE_STATIC),yes)
|
||||||
|
$(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB)
|
||||||
|
endif
|
||||||
|
|
||||||
$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC))
|
$(ARLIB): $(LIB_OBJS)
|
||||||
$(AR) -r $@ $^
|
$(AR) -r $@ $^
|
||||||
|
|
||||||
$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC))
|
$(ARLIB_CLIENT): $(LIB_CLIENT_OBJS)
|
||||||
$(AR) -r $@ $^
|
$(AR) -r $@ $^
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
@ -123,7 +123,6 @@ doxygen:
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
.PHONY: deps
|
|
||||||
.PHONY: doxygen
|
.PHONY: doxygen
|
||||||
.PHONY: dist
|
.PHONY: dist
|
||||||
.PHONY: last-dist
|
.PHONY: last-dist
|
||||||
|
@ -131,3 +130,4 @@ doxygen:
|
||||||
.PHONY: api_client
|
.PHONY: api_client
|
||||||
.PHONY: mk_obj_dir
|
.PHONY: mk_obj_dir
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
|
.PHONY: strip
|
||||||
|
|
|
@ -35,10 +35,7 @@ endif
|
||||||
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
# Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2
|
||||||
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
# Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic
|
||||||
ifeq ($(USE_AESNI),yes)
|
ifeq ($(USE_AESNI),yes)
|
||||||
CXXFLAGS += -maes
|
CXXFLAGS += -D__AES__ -maes
|
||||||
endif
|
|
||||||
ifeq ($(USE_AVX),1)
|
|
||||||
CXXFLAGS += -mavx
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
@ -51,4 +48,4 @@ install: all
|
||||||
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
|
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
|
||||||
@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
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# set defaults instead redefine
|
# set defaults instead redefine
|
||||||
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation -Wno-psabi
|
CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-psabi
|
||||||
LDFLAGS ?= ${LD_DEBUG}
|
LDFLAGS ?= ${LD_DEBUG}
|
||||||
|
|
||||||
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
|
## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time
|
||||||
|
@ -33,7 +33,7 @@ ifeq ($(USE_STATIC),yes)
|
||||||
# NOTE: on glibc you will get this warning:
|
# NOTE: on glibc you will get this warning:
|
||||||
# Using 'getaddrinfo' in statically linked applications requires at runtime
|
# Using 'getaddrinfo' in statically linked applications requires at runtime
|
||||||
# the shared libraries from the glibc version used for linking
|
# the shared libraries from the glibc version used for linking
|
||||||
LIBDIR := /usr/lib
|
LIBDIR := /usr/lib/$(SYS)
|
||||||
LDLIBS += $(LIBDIR)/libboost_system.a
|
LDLIBS += $(LIBDIR)/libboost_system.a
|
||||||
LDLIBS += $(LIBDIR)/libboost_date_time.a
|
LDLIBS += $(LIBDIR)/libboost_date_time.a
|
||||||
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
LDLIBS += $(LIBDIR)/libboost_filesystem.a
|
||||||
|
@ -41,37 +41,24 @@ ifeq ($(USE_STATIC),yes)
|
||||||
LDLIBS += $(LIBDIR)/libssl.a
|
LDLIBS += $(LIBDIR)/libssl.a
|
||||||
LDLIBS += $(LIBDIR)/libcrypto.a
|
LDLIBS += $(LIBDIR)/libcrypto.a
|
||||||
LDLIBS += $(LIBDIR)/libz.a
|
LDLIBS += $(LIBDIR)/libz.a
|
||||||
LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt -ldl
|
ifeq ($(USE_UPNP),yes)
|
||||||
USE_AESNI := no
|
LDLIBS += $(LIBDIR)/libminiupnpc.a
|
||||||
|
endif
|
||||||
|
LDLIBS += -lpthread -ldl
|
||||||
else
|
else
|
||||||
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread
|
||||||
endif
|
|
||||||
|
|
||||||
# UPNP Support (miniupnpc 1.5 and higher)
|
|
||||||
ifeq ($(USE_UPNP),yes)
|
ifeq ($(USE_UPNP),yes)
|
||||||
CXXFLAGS += -DUSE_UPNP
|
|
||||||
ifeq ($(USE_STATIC),yes)
|
|
||||||
LDLIBS += $(LIBDIR)/libminiupnpc.a
|
|
||||||
else
|
|
||||||
LDLIBS += -lminiupnpc
|
LDLIBS += -lminiupnpc
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_AESNI),yes)
|
# UPNP Support (miniupnpc 1.5 and higher)
|
||||||
#check if AES-NI is supported by CPU
|
ifeq ($(USE_UPNP),yes)
|
||||||
ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0)
|
NEEDED_CXXFLAGS += -DUSE_UPNP
|
||||||
machine := $(shell uname -m)
|
|
||||||
ifeq ($(machine), aarch64)
|
|
||||||
CXXFLAGS += -DARM64AES
|
|
||||||
else
|
|
||||||
CPU_FLAGS += -maes
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_AVX),yes)
|
ifeq ($(USE_AESNI),yes)
|
||||||
#check if AVX supported by CPU
|
ifeq (, $(findstring arm, $(SYS))$(findstring aarch64, $(SYS))) # no arm and aarch64 in dumpmachine
|
||||||
ifneq ($(shell $(GREP) -c avx /proc/cpuinfo),0)
|
NEEDED_CXXFLAGS += -D__AES__ -maes
|
||||||
CPU_FLAGS += -mavx
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
USE_WIN32_APP=yes
|
# Build application with GUI (tray, main window)
|
||||||
CXX = g++
|
USE_WIN32_APP := yes
|
||||||
|
|
||||||
WINDRES = windres
|
WINDRES = windres
|
||||||
CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
|
|
||||||
INCFLAGS = -Idaemon -I.
|
CXXFLAGS := $(CXX_DEBUG) -D_MT -DWIN32_LEAN_AND_MEAN -fPIC -msse
|
||||||
LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++
|
INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32
|
||||||
|
LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc
|
||||||
|
|
||||||
# detect proper flag for c++11 support by compilers
|
# detect proper flag for c++11 support by compilers
|
||||||
CXXVER := $(shell $(CXX) -dumpversion)
|
CXXVER := $(shell $(CXX) -dumpversion)
|
||||||
|
@ -38,29 +40,21 @@ LDLIBS += \
|
||||||
-liphlpapi \
|
-liphlpapi \
|
||||||
-lole32 \
|
-lole32 \
|
||||||
-luuid \
|
-luuid \
|
||||||
-lstdc++ \
|
|
||||||
-lpthread
|
-lpthread
|
||||||
|
|
||||||
ifeq ($(USE_WIN32_APP), yes)
|
ifeq ($(USE_WIN32_APP), yes)
|
||||||
CXXFLAGS += -DWIN32_APP
|
NEEDED_CXXFLAGS += -DWIN32_APP
|
||||||
LDFLAGS += -mwindows
|
LDFLAGS += -mwindows
|
||||||
DAEMON_RC += Win32/Resource.rc
|
DAEMON_RC += Win32/Resource.rc
|
||||||
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_WINXP_FLAGS), yes)
|
ifeq ($(USE_WINXP_FLAGS), yes)
|
||||||
CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
NEEDED_CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# don't change following line to ifeq ($(USE_AESNI),yes) !!!
|
ifeq ($(USE_AESNI),yes)
|
||||||
ifeq ($(USE_AESNI),1)
|
NEEDED_CXXFLAGS += -D__AES__ -maes
|
||||||
CPU_FLAGS += -maes
|
|
||||||
else
|
|
||||||
CPU_FLAGS += -msse
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(USE_AVX),1)
|
|
||||||
CPU_FLAGS += -mavx
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_ASLR),yes)
|
ifeq ($(USE_ASLR),yes)
|
||||||
|
|
|
@ -22,12 +22,8 @@ ifeq ($(USE_UPNP),yes)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_AESNI),1)
|
ifeq ($(USE_AESNI),yes)
|
||||||
CXXFLAGS += -maes
|
CXXFLAGS += -D__AES__ -maes
|
||||||
else
|
else
|
||||||
CXXFLAGS += -msse
|
CXXFLAGS += -msse
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(USE_AVX),1)
|
|
||||||
CXXFLAGS += -mavx
|
|
||||||
endif
|
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Win32/Win32Service.h"
|
#include "Win32Service.h"
|
||||||
#ifdef WIN32_APP
|
#ifdef WIN32_APP
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include "Win32/Win32App.h"
|
#include "Win32App.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
|
|
@ -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-2017, The PurpleI2P Project"
|
VALUE "LegalCopyright", "Copyright (C) 2013-2020, 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
|
||||||
|
|
|
@ -43,10 +43,7 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace win32
|
namespace win32
|
||||||
{
|
{
|
||||||
static DWORD GracefulShutdownEndtime = 0;
|
DWORD g_GracefulShutdownEndtime = 0;
|
||||||
|
|
||||||
typedef DWORD (* IPN)();
|
|
||||||
IPN GetTickCountLocal = (IPN)GetProcAddress (GetModuleHandle ("KERNEL32.dll"), "GetTickCount");
|
|
||||||
|
|
||||||
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem)
|
||||||
{
|
{
|
||||||
|
@ -167,9 +164,9 @@ namespace win32
|
||||||
s << "; ";
|
s << "; ";
|
||||||
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n";
|
||||||
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ());
|
||||||
if (GracefulShutdownEndtime != 0)
|
if (g_GracefulShutdownEndtime != 0)
|
||||||
{
|
{
|
||||||
DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCountLocal()) / 1000;
|
DWORD GracefulTimeLeft = (g_GracefulShutdownEndtime - GetTickCount()) / 1000;
|
||||||
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
|
s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -247,7 +244,7 @@ namespace win32
|
||||||
i2p::context.SetAcceptsTunnels (false);
|
i2p::context.SetAcceptsTunnels (false);
|
||||||
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes
|
||||||
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
|
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second
|
||||||
GracefulShutdownEndtime = GetTickCountLocal() + 10*60*1000;
|
g_GracefulShutdownEndtime = GetTickCount() + 10*60*1000;
|
||||||
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
i2p::util::DaemonWin32::Instance ().isGraceful = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -256,7 +253,7 @@ namespace win32
|
||||||
i2p::context.SetAcceptsTunnels (true);
|
i2p::context.SetAcceptsTunnels (true);
|
||||||
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER);
|
||||||
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
|
KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER);
|
||||||
GracefulShutdownEndtime = 0;
|
g_GracefulShutdownEndtime = 0;
|
||||||
i2p::util::DaemonWin32::Instance ().isGraceful = false;
|
i2p::util::DaemonWin32::Instance ().isGraceful = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -343,7 +340,7 @@ namespace win32
|
||||||
{
|
{
|
||||||
case IDT_GRACEFUL_SHUTDOWN_TIMER:
|
case IDT_GRACEFUL_SHUTDOWN_TIMER:
|
||||||
{
|
{
|
||||||
GracefulShutdownEndtime = 0;
|
g_GracefulShutdownEndtime = 0;
|
||||||
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
|
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace win32
|
namespace win32
|
||||||
{
|
{
|
||||||
|
extern DWORD g_GracefulShutdownEndtime;
|
||||||
|
|
||||||
bool StartWin32App ();
|
bool StartWin32App ();
|
||||||
void StopWin32App ();
|
void StopWin32App ();
|
||||||
int RunWin32App ();
|
int RunWin32App ();
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@drawable/icon"
|
android:icon="@drawable/icon"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:usesCleartextTraffic="true"
|
android:theme="@android:style/Theme.Holo.Light.DarkActionBar"
|
||||||
>
|
android:usesCleartextTraffic="true">
|
||||||
|
<activity android:name=".WebConsoleActivity"></activity>
|
||||||
|
|
||||||
<receiver android:name=".NetworkStateChangeReceiver">
|
<receiver android:name=".NetworkStateChangeReceiver">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@ -31,10 +31,10 @@
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".I2PDActivity"
|
android:name=".I2PDActivity"
|
||||||
android:label="@string/app_name" />
|
android:label="@string/app_name" />
|
||||||
|
@ -52,4 +52,5 @@
|
||||||
android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" />
|
android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" />
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
|
||||||
|
</manifest>
|
|
@ -30,8 +30,8 @@ android {
|
||||||
applicationId "org.purplei2p.i2pd"
|
applicationId "org.purplei2p.i2pd"
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
versionCode 2330
|
versionCode 2350
|
||||||
versionName "2.33.0"
|
versionName "2.35.0"
|
||||||
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
|
||||||
ndk {
|
ndk {
|
||||||
abiFilters 'armeabi-v7a'
|
abiFilters 'armeabi-v7a'
|
||||||
|
@ -90,7 +90,7 @@ android {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ext.abiCodes = ['armeabi-v7a':1, 'x86':2, 'arm64-v8a':3, 'x86_64':4]
|
ext.abiCodes = ['armeabi-v7a': 1, 'x86': 2, 'arm64-v8a': 3, 'x86_64': 4]
|
||||||
import com.android.build.OutputFile
|
import com.android.build.OutputFile
|
||||||
|
|
||||||
android.applicationVariants.all { variant ->
|
android.applicationVariants.all { variant ->
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout android:id="@+id/layout_prompt"
|
<LinearLayout android:id="@+id/layout_prompt"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
tools:context=".I2PDActivity">
|
tools:context=".WebConsoleActivity">
|
||||||
|
|
||||||
<WebView
|
<WebView
|
||||||
android:id="@+id/webview1"
|
android:id="@+id/webview1"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent" />
|
android:layout_height="fill_parent" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
|
@ -1,181 +0,0 @@
|
||||||
package org.purplei2p.i2pd;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import android.os.Environment;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import org.purplei2p.i2pd.R;
|
|
||||||
|
|
||||||
public class DaemonSingleton {
|
|
||||||
private static final String TAG = "i2pd";
|
|
||||||
private static final DaemonSingleton instance = new DaemonSingleton();
|
|
||||||
|
|
||||||
public interface StateUpdateListener {
|
|
||||||
void daemonStateUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
|
|
||||||
|
|
||||||
public static DaemonSingleton getInstance() {
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void addStateChangeListener(StateUpdateListener listener) {
|
|
||||||
stateUpdateListeners.add(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void removeStateChangeListener(StateUpdateListener listener) {
|
|
||||||
stateUpdateListeners.remove(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void setState(State newState) {
|
|
||||||
if (newState == null)
|
|
||||||
throw new NullPointerException();
|
|
||||||
|
|
||||||
State oldState = state;
|
|
||||||
|
|
||||||
if (oldState == null)
|
|
||||||
throw new NullPointerException();
|
|
||||||
|
|
||||||
if (oldState.equals(newState))
|
|
||||||
return;
|
|
||||||
|
|
||||||
state = newState;
|
|
||||||
fireStateUpdate1();
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void stopAcceptingTunnels() {
|
|
||||||
if (isStartedOkay()) {
|
|
||||||
setState(State.gracefulShutdownInProgress);
|
|
||||||
I2PD_JNI.stopAcceptingTunnels();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void startAcceptingTunnels() {
|
|
||||||
if (isStartedOkay()) {
|
|
||||||
setState(State.startedOkay);
|
|
||||||
I2PD_JNI.startAcceptingTunnels();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void reloadTunnelsConfigs() {
|
|
||||||
if (isStartedOkay()) {
|
|
||||||
I2PD_JNI.reloadTunnelsConfigs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized int GetTransitTunnelsCount() {
|
|
||||||
return I2PD_JNI.GetTransitTunnelsCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
private volatile boolean startedOkay;
|
|
||||||
|
|
||||||
public enum State {
|
|
||||||
uninitialized(R.string.uninitialized),
|
|
||||||
starting(R.string.starting),
|
|
||||||
jniLibraryLoaded(R.string.jniLibraryLoaded),
|
|
||||||
startedOkay(R.string.startedOkay),
|
|
||||||
startFailed(R.string.startFailed),
|
|
||||||
gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
|
|
||||||
stopped(R.string.stopped);
|
|
||||||
|
|
||||||
State(int statusStringResourceId) {
|
|
||||||
this.statusStringResourceId = statusStringResourceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final int statusStringResourceId;
|
|
||||||
|
|
||||||
public int getStatusStringResourceId() {
|
|
||||||
return statusStringResourceId;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private volatile State state = State.uninitialized;
|
|
||||||
|
|
||||||
public State getState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
setState(State.starting);
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
I2PD_JNI.loadLibraries();
|
|
||||||
setState(State.jniLibraryLoaded);
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
lastThrowable = tr;
|
|
||||||
setState(State.startFailed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
synchronized (DaemonSingleton.this) {
|
|
||||||
I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd");
|
|
||||||
daemonStartResult = I2PD_JNI.startDaemon();
|
|
||||||
if ("ok".equals(daemonStartResult)) {
|
|
||||||
setState(State.startedOkay);
|
|
||||||
setStartedOkay(true);
|
|
||||||
} else
|
|
||||||
setState(State.startFailed);
|
|
||||||
}
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
lastThrowable = tr;
|
|
||||||
setState(State.startFailed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}, "i2pdDaemonStart").start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Throwable lastThrowable;
|
|
||||||
private String daemonStartResult = "N/A";
|
|
||||||
|
|
||||||
private void fireStateUpdate1() {
|
|
||||||
Log.i(TAG, "daemon state change: " + state);
|
|
||||||
for (StateUpdateListener listener : stateUpdateListeners) {
|
|
||||||
try {
|
|
||||||
listener.daemonStateUpdate();
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
Log.e(TAG, "exception in listener ignored", tr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Throwable getLastThrowable() {
|
|
||||||
return lastThrowable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDaemonStartResult() {
|
|
||||||
return daemonStartResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Object startedOkayLock = new Object();
|
|
||||||
|
|
||||||
public boolean isStartedOkay() {
|
|
||||||
synchronized (startedOkayLock) {
|
|
||||||
return startedOkay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setStartedOkay(boolean startedOkay) {
|
|
||||||
synchronized (startedOkayLock) {
|
|
||||||
this.startedOkay = startedOkay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void stopDaemon() {
|
|
||||||
if (isStartedOkay()) {
|
|
||||||
try {
|
|
||||||
I2PD_JNI.stopDaemon();
|
|
||||||
} catch(Throwable tr) {
|
|
||||||
Log.e(TAG, "", tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
setStartedOkay(false);
|
|
||||||
setState(State.stopped);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
374
android/src/org/purplei2p/i2pd/DaemonWrapper.java
Normal file
374
android/src/org/purplei2p/i2pd/DaemonWrapper.java
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.Network;
|
||||||
|
import android.net.NetworkCapabilities;
|
||||||
|
import android.net.NetworkRequest;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
|
public class DaemonWrapper {
|
||||||
|
private static final String TAG = "i2pd";
|
||||||
|
private final AssetManager assetManager;
|
||||||
|
private final ConnectivityManager connectivityManager;
|
||||||
|
private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
|
||||||
|
private boolean assetsCopied;
|
||||||
|
|
||||||
|
public interface StateUpdateListener {
|
||||||
|
void daemonStateUpdate(State oldValue, State newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
|
||||||
|
|
||||||
|
public synchronized void addStateChangeListener(StateUpdateListener listener) {
|
||||||
|
stateUpdateListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void removeStateChangeListener(StateUpdateListener listener) {
|
||||||
|
stateUpdateListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void setState(State newState) {
|
||||||
|
if (newState == null)
|
||||||
|
throw new NullPointerException();
|
||||||
|
|
||||||
|
State oldState = state;
|
||||||
|
|
||||||
|
if (oldState == null)
|
||||||
|
throw new NullPointerException();
|
||||||
|
|
||||||
|
if (oldState.equals(newState))
|
||||||
|
return;
|
||||||
|
|
||||||
|
state = newState;
|
||||||
|
fireStateUpdate1(oldState, newState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void stopAcceptingTunnels() {
|
||||||
|
if (isStartedOkay()) {
|
||||||
|
setState(State.gracefulShutdownInProgress);
|
||||||
|
I2PD_JNI.stopAcceptingTunnels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void startAcceptingTunnels() {
|
||||||
|
if (isStartedOkay()) {
|
||||||
|
setState(State.startedOkay);
|
||||||
|
I2PD_JNI.startAcceptingTunnels();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void reloadTunnelsConfigs() {
|
||||||
|
if (isStartedOkay()) {
|
||||||
|
I2PD_JNI.reloadTunnelsConfigs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTransitTunnelsCount() {
|
||||||
|
return I2PD_JNI.GetTransitTunnelsCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
uninitialized(R.string.uninitialized),
|
||||||
|
starting(R.string.starting),
|
||||||
|
jniLibraryLoaded(R.string.jniLibraryLoaded),
|
||||||
|
startedOkay(R.string.startedOkay),
|
||||||
|
startFailed(R.string.startFailed),
|
||||||
|
gracefulShutdownInProgress(R.string.gracefulShutdownInProgress),
|
||||||
|
stopped(R.string.stopped);
|
||||||
|
|
||||||
|
State(int statusStringResourceId) {
|
||||||
|
this.statusStringResourceId = statusStringResourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int statusStringResourceId;
|
||||||
|
|
||||||
|
public int getStatusStringResourceId() {
|
||||||
|
return statusStringResourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStartedOkay() {
|
||||||
|
return equals(State.startedOkay) || equals(State.gracefulShutdownInProgress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private volatile State state = State.uninitialized;
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DaemonWrapper(AssetManager assetManager, ConnectivityManager connectivityManager){
|
||||||
|
this.assetManager = assetManager;
|
||||||
|
this.connectivityManager = connectivityManager;
|
||||||
|
setState(State.starting);
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
processAssets();
|
||||||
|
I2PD_JNI.loadLibraries();
|
||||||
|
setState(State.jniLibraryLoaded);
|
||||||
|
registerNetworkCallback();
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
lastThrowable = tr;
|
||||||
|
setState(State.startFailed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
synchronized (DaemonWrapper.this) {
|
||||||
|
I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd");
|
||||||
|
daemonStartResult = I2PD_JNI.startDaemon();
|
||||||
|
if ("ok".equals(daemonStartResult)) {
|
||||||
|
setState(State.startedOkay);
|
||||||
|
} else
|
||||||
|
setState(State.startFailed);
|
||||||
|
}
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
lastThrowable = tr;
|
||||||
|
setState(State.startFailed);
|
||||||
|
}
|
||||||
|
}, "i2pdDaemonStart").start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Throwable lastThrowable;
|
||||||
|
private String daemonStartResult = "N/A";
|
||||||
|
|
||||||
|
private void fireStateUpdate1(State oldValue, State newValue) {
|
||||||
|
Log.i(TAG, "daemon state change: " + state);
|
||||||
|
for (StateUpdateListener listener : stateUpdateListeners) {
|
||||||
|
try {
|
||||||
|
listener.daemonStateUpdate(oldValue, newValue);
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
Log.e(TAG, "exception in listener ignored", tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Throwable getLastThrowable() {
|
||||||
|
return lastThrowable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDaemonStartResult() {
|
||||||
|
return daemonStartResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStartedOkay() {
|
||||||
|
return getState().isStartedOkay();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void stopDaemon() {
|
||||||
|
if (isStartedOkay()) {
|
||||||
|
try {
|
||||||
|
I2PD_JNI.stopDaemon();
|
||||||
|
} catch(Throwable tr) {
|
||||||
|
Log.e(TAG, "", tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(State.stopped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processAssets() {
|
||||||
|
if (!assetsCopied) {
|
||||||
|
try {
|
||||||
|
assetsCopied = true;
|
||||||
|
|
||||||
|
File holderFile = new File(i2pdpath, "assets.ready");
|
||||||
|
String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
|
||||||
|
if (holderFile.exists()) {
|
||||||
|
try { // if holder file exists, read assets version string
|
||||||
|
FileReader fileReader = new FileReader(holderFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedReader br = new BufferedReader(fileReader);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String line;
|
||||||
|
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
text.append(line);
|
||||||
|
}
|
||||||
|
}finally {
|
||||||
|
try {
|
||||||
|
br.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
fileReader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if version differs from current app version or null, try to delete certificates folder
|
||||||
|
if (!text.toString().contains(versionName))
|
||||||
|
try {
|
||||||
|
boolean deleteResult = holderFile.delete();
|
||||||
|
if (!deleteResult)
|
||||||
|
Log.e(TAG, "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile.getAbsolutePath() + "'");
|
||||||
|
File certPath = new File(i2pdpath, "certificates");
|
||||||
|
deleteRecursive(certPath);
|
||||||
|
}
|
||||||
|
catch (Throwable tr) {
|
||||||
|
Log.e(TAG, "", tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy assets. If processed file exists, it won't be overwritten
|
||||||
|
copyAsset("addressbook");
|
||||||
|
copyAsset("certificates");
|
||||||
|
copyAsset("tunnels.d");
|
||||||
|
copyAsset("i2pd.conf");
|
||||||
|
copyAsset("subscriptions.txt");
|
||||||
|
copyAsset("tunnels.conf");
|
||||||
|
|
||||||
|
// update holder file about successful copying
|
||||||
|
FileWriter writer = new FileWriter(holderFile);
|
||||||
|
try {
|
||||||
|
writer.append(versionName);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG,"on writer close", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable tr)
|
||||||
|
{
|
||||||
|
Log.e(TAG,"on assets copying", tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the asset at the specified path to this app's data directory. If the
|
||||||
|
* asset is a directory, its contents are also copied.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* Path to asset, relative to app's assets directory.
|
||||||
|
*/
|
||||||
|
private void copyAsset(String path) {
|
||||||
|
// If we have a directory, we make it and recurse. If a file, we copy its
|
||||||
|
// contents.
|
||||||
|
try {
|
||||||
|
String[] contents = assetManager.list(path);
|
||||||
|
|
||||||
|
// The documentation suggests that list throws an IOException, but doesn't
|
||||||
|
// say under what conditions. It'd be nice if it did so when the path was
|
||||||
|
// to a file. That doesn't appear to be the case. If the returned array is
|
||||||
|
// null or has 0 length, we assume the path is to a file. This means empty
|
||||||
|
// directories will get turned into files.
|
||||||
|
if (contents == null || contents.length == 0) {
|
||||||
|
copyFileAsset(path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the directory.
|
||||||
|
File dir = new File(i2pdpath, path);
|
||||||
|
boolean result = dir.mkdirs();
|
||||||
|
Log.d(TAG, "dir.mkdirs() returned " + result);
|
||||||
|
|
||||||
|
// Recurse on the contents.
|
||||||
|
for (String entry : contents) {
|
||||||
|
copyAsset(path + '/' + entry);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "ex ignored for path='" + path + "'", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the asset file specified by path to app's data directory. Assumes
|
||||||
|
* parent directories have already been created.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* Path to asset, relative to app's assets directory.
|
||||||
|
*/
|
||||||
|
private void copyFileAsset(String path) {
|
||||||
|
File file = new File(i2pdpath, path);
|
||||||
|
if (!file.exists()) {
|
||||||
|
try {
|
||||||
|
try (InputStream in = assetManager.open(path)) {
|
||||||
|
try (OutputStream out = new FileOutputStream(file)) {
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read = in.read(buffer);
|
||||||
|
while (read != -1) {
|
||||||
|
out.write(buffer, 0, read);
|
||||||
|
read = in.read(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteRecursive(File fileOrDirectory) {
|
||||||
|
if (fileOrDirectory.isDirectory()) {
|
||||||
|
File[] files = fileOrDirectory.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File child : files) {
|
||||||
|
deleteRecursive(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean deleteResult = fileOrDirectory.delete();
|
||||||
|
if (!deleteResult)
|
||||||
|
Log.e(TAG, "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory.getAbsolutePath() + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerNetworkCallback(){
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) registerNetworkCallback0();
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.M)
|
||||||
|
private void registerNetworkCallback0() {
|
||||||
|
NetworkRequest request = new NetworkRequest.Builder()
|
||||||
|
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
||||||
|
.build();
|
||||||
|
NetworkStateCallbackImpl networkCallback = new NetworkStateCallbackImpl();
|
||||||
|
connectivityManager.registerNetworkCallback(request, networkCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private static final class NetworkStateCallbackImpl extends ConnectivityManager.NetworkCallback {
|
||||||
|
@Override
|
||||||
|
public void onAvailable(Network network) {
|
||||||
|
super.onAvailable(network);
|
||||||
|
I2PD_JNI.onNetworkStateChanged(true);
|
||||||
|
Log.i(TAG, "NetworkCallback.onAvailable");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLost(Network network) {
|
||||||
|
super.onLost(network);
|
||||||
|
I2PD_JNI.onNetworkStateChanged(false);
|
||||||
|
Log.i(TAG, " NetworkCallback.onLost");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,28 +19,38 @@ public class ForegroundService extends Service {
|
||||||
|
|
||||||
private volatile boolean shown;
|
private volatile boolean shown;
|
||||||
|
|
||||||
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
|
private static ForegroundService instance;
|
||||||
new DaemonSingleton.StateUpdateListener() {
|
|
||||||
|
private static volatile DaemonWrapper daemon;
|
||||||
|
|
||||||
|
private static final Object initDeinitLock = new Object();
|
||||||
|
|
||||||
|
private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener =
|
||||||
|
new DaemonWrapper.StateUpdateListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void daemonStateUpdate() {
|
public void daemonStateUpdate(DaemonWrapper.State oldValue, DaemonWrapper.State newValue) {
|
||||||
try {
|
updateNotificationText();
|
||||||
synchronized (ForegroundService.this) {
|
|
||||||
if (shown) cancelNotification();
|
|
||||||
showNotification();
|
|
||||||
}
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
Log.e(TAG,"error ignored",tr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void updateNotificationText() {
|
||||||
|
try {
|
||||||
|
synchronized (initDeinitLock) {
|
||||||
|
if (shown) cancelNotification();
|
||||||
|
showNotification();
|
||||||
|
}
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
Log.e(TAG,"error ignored",tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private NotificationManager notificationManager;
|
private NotificationManager notificationManager;
|
||||||
|
|
||||||
// Unique Identification Number for the Notification.
|
// Unique Identification Number for the Notification.
|
||||||
// We use it on Notification start, and to cancel it.
|
// We use it on Notification start, and to cancel it.
|
||||||
private int NOTIFICATION = 1;
|
private static final int NOTIFICATION = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for clients to access. Because we know this service always
|
* Class for clients to access. Because we know this service always
|
||||||
|
@ -53,16 +63,27 @@ public class ForegroundService extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void init(DaemonWrapper daemon) {
|
||||||
|
ForegroundService.daemon = daemon;
|
||||||
|
initCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initCheck() {
|
||||||
|
synchronized (initDeinitLock) {
|
||||||
|
if (instance != null && daemon != null) instance.setListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
instance = this;
|
||||||
|
initCheck();
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
private void setListener() {
|
||||||
DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
|
daemon.addStateChangeListener(daemonStateUpdatedListener);
|
||||||
if (!shown) daemonStateUpdatedListener.daemonStateUpdate();
|
updateNotificationText();
|
||||||
}
|
|
||||||
// Tell the user we started.
|
|
||||||
// Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,19 +94,33 @@ public class ForegroundService extends Service {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener);
|
|
||||||
cancelNotification();
|
cancelNotification();
|
||||||
|
deinitCheck();
|
||||||
|
instance=null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void cancelNotification() {
|
public static void deinit() {
|
||||||
// Cancel the persistent notification.
|
deinitCheck();
|
||||||
notificationManager.cancel(NOTIFICATION);
|
}
|
||||||
|
|
||||||
stopForeground(true);
|
private static void deinitCheck() {
|
||||||
|
synchronized (initDeinitLock) {
|
||||||
|
if (daemon != null && instance != null)
|
||||||
|
daemon.removeStateChangeListener(instance.daemonStateUpdatedListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Tell the user we stopped.
|
private void cancelNotification() {
|
||||||
//Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
|
synchronized (initDeinitLock) {
|
||||||
shown=false;
|
// Cancel the persistent notification.
|
||||||
|
notificationManager.cancel(NOTIFICATION);
|
||||||
|
|
||||||
|
stopForeground(true);
|
||||||
|
|
||||||
|
// Tell the user we stopped.
|
||||||
|
//Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show();
|
||||||
|
shown = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -100,36 +135,42 @@ public class ForegroundService extends Service {
|
||||||
/**
|
/**
|
||||||
* Show a notification while this service is running.
|
* Show a notification while this service is running.
|
||||||
*/
|
*/
|
||||||
private synchronized void showNotification() {
|
private void showNotification() {
|
||||||
// In this sample, we'll use the same text for the ticker and the expanded notification
|
synchronized (initDeinitLock) {
|
||||||
CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId());
|
if (daemon != null) {
|
||||||
|
// In this sample, we'll use the same text for the ticker and the expanded notification
|
||||||
|
CharSequence text = getText(daemon.getState().getStatusStringResourceId());
|
||||||
|
|
||||||
// The PendingIntent to launch our activity if the user selects this notification
|
// The PendingIntent to launch our activity if the user selects this notification
|
||||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||||
new Intent(this, I2PDActivity.class), 0);
|
new Intent(this, I2PDActivity.class), 0);
|
||||||
|
|
||||||
// If earlier version channel ID is not used
|
// If earlier version channel ID is not used
|
||||||
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
||||||
String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
|
String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : "";
|
||||||
|
|
||||||
// Set the info for the views that show in the notification panel.
|
// Set the info for the views that show in the notification panel.
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon
|
.setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon
|
||||||
if(Build.VERSION.SDK_INT >= 16) builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
|
if (Build.VERSION.SDK_INT >= 16)
|
||||||
if(Build.VERSION.SDK_INT >= 21) builder = builder.setCategory(Notification.CATEGORY_SERVICE);
|
builder = builder.setPriority(Notification.PRIORITY_DEFAULT);
|
||||||
Notification notification = builder
|
if (Build.VERSION.SDK_INT >= 21)
|
||||||
.setTicker(text) // the status text
|
builder = builder.setCategory(Notification.CATEGORY_SERVICE);
|
||||||
.setWhen(System.currentTimeMillis()) // the time stamp
|
Notification notification = builder
|
||||||
.setContentTitle(getText(R.string.app_name)) // the label of the entry
|
.setTicker(text) // the status text
|
||||||
.setContentText(text) // the contents of the entry
|
.setWhen(System.currentTimeMillis()) // the time stamp
|
||||||
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
.setContentTitle(getText(R.string.app_name)) // the label of the entry
|
||||||
.build();
|
.setContentText(text) // the contents of the entry
|
||||||
|
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
||||||
|
.build();
|
||||||
|
|
||||||
// Send the notification.
|
// Send the notification.
|
||||||
//mNM.notify(NOTIFICATION, notification);
|
//mNM.notify(NOTIFICATION, notification);
|
||||||
startForeground(NOTIFICATION, notification);
|
startForeground(NOTIFICATION, notification);
|
||||||
shown = true;
|
shown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
@ -144,6 +185,4 @@ public class ForegroundService extends Service {
|
||||||
else Log.e(TAG, "error: NOTIFICATION_SERVICE is null");
|
else Log.e(TAG, "error: NOTIFICATION_SERVICE is null");
|
||||||
return channelId;
|
return channelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
package org.purplei2p.i2pd;
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
|
@ -15,7 +7,6 @@ import java.util.TimerTask;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
|
@ -24,16 +15,11 @@ import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.ServiceConnection;
|
import android.content.ServiceConnection;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.AssetManager;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Network;
|
|
||||||
import android.net.NetworkCapabilities;
|
|
||||||
import android.net.NetworkRequest;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
@ -46,7 +32,6 @@ import android.widget.Toast;
|
||||||
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.RequiresApi;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
|
@ -60,44 +45,43 @@ import android.webkit.WebViewClient;
|
||||||
import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS;
|
import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS;
|
||||||
|
|
||||||
public class I2PDActivity extends Activity {
|
public class I2PDActivity extends Activity {
|
||||||
private WebView webView;
|
|
||||||
|
|
||||||
private static final String TAG = "i2pdActvt";
|
private static final String TAG = "i2pdActvt";
|
||||||
private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
|
private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
|
||||||
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
|
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
|
||||||
public static final String PACKAGE_URI_SCHEME = "package:";
|
public static final String PACKAGE_URI_SCHEME = "package:";
|
||||||
|
|
||||||
private TextView textView;
|
private TextView textView;
|
||||||
private boolean assetsCopied;
|
//private ConfigParser parser = new ConfigParser(i2pdpath); // TODO
|
||||||
private NetworkStateCallback networkCallback;
|
|
||||||
private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
|
|
||||||
//private ConfigParser parser = new ConfigParser(i2pdpath); // TODO:
|
|
||||||
|
|
||||||
private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
private static volatile DaemonWrapper daemon;
|
||||||
|
|
||||||
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton.StateUpdateListener() {
|
private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener = new DaemonWrapper.StateUpdateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void daemonStateUpdate() {
|
public void daemonStateUpdate(DaemonWrapper.State oldValue, DaemonWrapper.State newValue) {
|
||||||
processAssets();
|
updateStatusText();
|
||||||
runOnUiThread(() -> {
|
|
||||||
try {
|
|
||||||
if (textView == null)
|
|
||||||
return;
|
|
||||||
Throwable tr = daemon.getLastThrowable();
|
|
||||||
if (tr!=null) {
|
|
||||||
textView.setText(throwableToString(tr));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DaemonSingleton.State state = daemon.getState();
|
|
||||||
String startResultStr = DaemonSingleton.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : "";
|
|
||||||
String graceStr = DaemonSingleton.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : "";
|
|
||||||
textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr));
|
|
||||||
} catch (Throwable tr) {
|
|
||||||
Log.e(TAG,"error ignored",tr);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void updateStatusText() {
|
||||||
|
runOnUiThread(() -> {
|
||||||
|
try {
|
||||||
|
if (textView == null)
|
||||||
|
return;
|
||||||
|
Throwable tr = daemon.getLastThrowable();
|
||||||
|
if (tr!=null) {
|
||||||
|
textView.setText(throwableToString(tr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DaemonWrapper.State state = daemon.getState();
|
||||||
|
String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : "";
|
||||||
|
String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : "";
|
||||||
|
textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr));
|
||||||
|
} catch (Throwable tr) {
|
||||||
|
Log.e(TAG,"error ignored",tr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private static volatile long graceStartedMillis;
|
private static volatile long graceStartedMillis;
|
||||||
private static final Object graceStartedMillis_LOCK = new Object();
|
private static final Object graceStartedMillis_LOCK = new Object();
|
||||||
private Menu optionsMenu;
|
private Menu optionsMenu;
|
||||||
|
@ -117,10 +101,16 @@ public class I2PDActivity extends Activity {
|
||||||
Log.i(TAG, "onCreate");
|
Log.i(TAG, "onCreate");
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
if (daemon==null) {
|
||||||
|
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
daemon = new DaemonWrapper(getAssets(), connectivityManager);
|
||||||
|
}
|
||||||
|
ForegroundService.init(daemon);
|
||||||
|
|
||||||
textView = new TextView(this);
|
textView = new TextView(this);
|
||||||
setContentView(textView);
|
setContentView(textView);
|
||||||
daemon.addStateChangeListener(daemonStateUpdatedListener);
|
daemon.addStateChangeListener(daemonStateUpdatedListener);
|
||||||
daemonStateUpdatedListener.daemonStateUpdate();
|
daemonStateUpdatedListener.daemonStateUpdate(DaemonWrapper.State.uninitialized, daemon.getState());
|
||||||
|
|
||||||
// request permissions
|
// request permissions
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
@ -145,15 +135,13 @@ public class I2PDActivity extends Activity {
|
||||||
|
|
||||||
openBatteryOptimizationDialogIfNeeded();
|
openBatteryOptimizationDialogIfNeeded();
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
||||||
registerNetworkCallback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
textView = null;
|
textView = null;
|
||||||
|
ForegroundService.deinit();
|
||||||
daemon.removeStateChangeListener(daemonStateUpdatedListener);
|
daemon.removeStateChangeListener(daemonStateUpdatedListener);
|
||||||
//cancelGracefulStop0();
|
//cancelGracefulStop0();
|
||||||
try {
|
try {
|
||||||
|
@ -288,15 +276,8 @@ public class I2PDActivity extends Activity {
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case R.id.action_start_webview:
|
case R.id.action_start_webview:
|
||||||
setContentView(R.layout.webview);
|
startActivity(new Intent(getApplicationContext(), WebConsoleActivity.class));
|
||||||
this.webView = (WebView) findViewById(R.id.webview1);
|
return true;
|
||||||
this.webView.setWebViewClient(new WebViewClient());
|
|
||||||
|
|
||||||
WebSettings webSettings = this.webView.getSettings();
|
|
||||||
webSettings.setBuiltInZoomControls(true);
|
|
||||||
webSettings.setJavaScriptEnabled(false);
|
|
||||||
this.webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
@ -335,7 +316,7 @@ public class I2PDActivity extends Activity {
|
||||||
private static volatile Timer gracefulQuitTimer;
|
private static volatile Timer gracefulQuitTimer;
|
||||||
|
|
||||||
private void i2pdGracefulStop() {
|
private void i2pdGracefulStop() {
|
||||||
if (daemon.getState() == DaemonSingleton.State.stopped) {
|
if (daemon.getState() == DaemonWrapper.State.stopped) {
|
||||||
Toast.makeText(this, R.string.already_stopped, Toast.LENGTH_SHORT).show();
|
Toast.makeText(this, R.string.already_stopped, Toast.LENGTH_SHORT).show();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -384,9 +365,10 @@ public class I2PDActivity extends Activity {
|
||||||
if (gracefulQuitTimerOld != null)
|
if (gracefulQuitTimerOld != null)
|
||||||
gracefulQuitTimerOld.cancel();
|
gracefulQuitTimerOld.cancel();
|
||||||
|
|
||||||
if(daemon.GetTransitTunnelsCount() <= 0) { // no tunnels left
|
if(daemon.getTransitTunnelsCount() <= 0) { // no tunnels left
|
||||||
Log.d(TAG, "no transit tunnels left, stopping");
|
Log.d(TAG, "no transit tunnels left, stopping");
|
||||||
i2pdStop();
|
i2pdStop();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Timer gracefulQuitTimer = new Timer(true);
|
final Timer gracefulQuitTimer = new Timer(true);
|
||||||
|
@ -402,7 +384,7 @@ public class I2PDActivity extends Activity {
|
||||||
final TimerTask tickerTask = new TimerTask() {
|
final TimerTask tickerTask = new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
daemonStateUpdatedListener.daemonStateUpdate();
|
updateStatusText();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
gracefulQuitTimer.scheduleAtFixedRate(tickerTask, 0/*start delay*/, 1000/*millis period*/);
|
gracefulQuitTimer.scheduleAtFixedRate(tickerTask, 0/*start delay*/, 1000/*millis period*/);
|
||||||
|
@ -427,167 +409,6 @@ public class I2PDActivity extends Activity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the asset at the specified path to this app's data directory. If the
|
|
||||||
* asset is a directory, its contents are also copied.
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
* Path to asset, relative to app's assets directory.
|
|
||||||
*/
|
|
||||||
private void copyAsset(String path) {
|
|
||||||
AssetManager manager = getAssets();
|
|
||||||
|
|
||||||
// If we have a directory, we make it and recurse. If a file, we copy its
|
|
||||||
// contents.
|
|
||||||
try {
|
|
||||||
String[] contents = manager.list(path);
|
|
||||||
|
|
||||||
// The documentation suggests that list throws an IOException, but doesn't
|
|
||||||
// say under what conditions. It'd be nice if it did so when the path was
|
|
||||||
// to a file. That doesn't appear to be the case. If the returned array is
|
|
||||||
// null or has 0 length, we assume the path is to a file. This means empty
|
|
||||||
// directories will get turned into files.
|
|
||||||
if (contents == null || contents.length == 0) {
|
|
||||||
copyFileAsset(path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make the directory.
|
|
||||||
File dir = new File(i2pdpath, path);
|
|
||||||
boolean result = dir.mkdirs();
|
|
||||||
Log.d(TAG, "dir.mkdirs() returned " + result);
|
|
||||||
|
|
||||||
// Recurse on the contents.
|
|
||||||
for (String entry : contents) {
|
|
||||||
copyAsset(path + '/' + entry);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "ex ignored for path='" + path + "'", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy the asset file specified by path to app's data directory. Assumes
|
|
||||||
* parent directories have already been created.
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
* Path to asset, relative to app's assets directory.
|
|
||||||
*/
|
|
||||||
private void copyFileAsset(String path) {
|
|
||||||
File file = new File(i2pdpath, path);
|
|
||||||
if (!file.exists()) {
|
|
||||||
try {
|
|
||||||
try (InputStream in = getAssets().open(path)) {
|
|
||||||
try (OutputStream out = new FileOutputStream(file)) {
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int read = in.read(buffer);
|
|
||||||
while (read != -1) {
|
|
||||||
out.write(buffer, 0, read);
|
|
||||||
read = in.read(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteRecursive(File fileOrDirectory) {
|
|
||||||
if (fileOrDirectory.isDirectory()) {
|
|
||||||
File[] files = fileOrDirectory.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File child : files) {
|
|
||||||
deleteRecursive(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean deleteResult = fileOrDirectory.delete();
|
|
||||||
if (!deleteResult)
|
|
||||||
Log.e(TAG, "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory.getAbsolutePath() + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void processAssets() {
|
|
||||||
if (!assetsCopied) {
|
|
||||||
try {
|
|
||||||
assetsCopied = true; // prevent from running on every state update
|
|
||||||
|
|
||||||
File holderFile = new File(i2pdpath, "assets.ready");
|
|
||||||
String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX
|
|
||||||
StringBuilder text = new StringBuilder();
|
|
||||||
|
|
||||||
if (holderFile.exists()) {
|
|
||||||
try { // if holder file exists, read assets version string
|
|
||||||
FileReader fileReader = new FileReader(holderFile);
|
|
||||||
|
|
||||||
try {
|
|
||||||
BufferedReader br = new BufferedReader(fileReader);
|
|
||||||
|
|
||||||
try {
|
|
||||||
String line;
|
|
||||||
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
text.append(line);
|
|
||||||
}
|
|
||||||
}finally {
|
|
||||||
try {
|
|
||||||
br.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
fileReader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, "", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if version differs from current app version or null, try to delete certificates folder
|
|
||||||
if (!text.toString().contains(versionName))
|
|
||||||
try {
|
|
||||||
boolean deleteResult = holderFile.delete();
|
|
||||||
if (!deleteResult)
|
|
||||||
Log.e(TAG, "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile.getAbsolutePath() + "'");
|
|
||||||
File certPath = new File(i2pdpath, "certificates");
|
|
||||||
deleteRecursive(certPath);
|
|
||||||
}
|
|
||||||
catch (Throwable tr) {
|
|
||||||
Log.e(TAG, "", tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy assets. If processed file exists, it won't be overwritten
|
|
||||||
copyAsset("addressbook");
|
|
||||||
copyAsset("certificates");
|
|
||||||
copyAsset("tunnels.d");
|
|
||||||
copyAsset("i2pd.conf");
|
|
||||||
copyAsset("subscriptions.txt");
|
|
||||||
copyAsset("tunnels.conf");
|
|
||||||
|
|
||||||
// update holder file about successful copying
|
|
||||||
FileWriter writer = new FileWriter(holderFile);
|
|
||||||
try {
|
|
||||||
writer.append(versionName);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
writer.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG,"on writer close", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable tr)
|
|
||||||
{
|
|
||||||
Log.e(TAG,"on assets copying", tr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("BatteryLife")
|
@SuppressLint("BatteryLife")
|
||||||
private void openBatteryOptimizationDialogIfNeeded() {
|
private void openBatteryOptimizationDialogIfNeeded() {
|
||||||
boolean questionEnabled = getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true);
|
boolean questionEnabled = getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true);
|
||||||
|
@ -642,33 +463,6 @@ public class I2PDActivity extends Activity {
|
||||||
return "show_battery_optimization" + (device == null ? "" : device);
|
return "show_battery_optimization" + (device == null ? "" : device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.M)
|
|
||||||
private void registerNetworkCallback() {
|
|
||||||
ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
NetworkRequest request = new NetworkRequest.Builder()
|
|
||||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
|
|
||||||
.build();
|
|
||||||
networkCallback = new NetworkStateCallback();
|
|
||||||
connectivityManager.registerNetworkCallback(request, networkCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
private final class NetworkStateCallback extends ConnectivityManager.NetworkCallback {
|
|
||||||
@Override
|
|
||||||
public void onAvailable(Network network) {
|
|
||||||
super.onAvailable(network);
|
|
||||||
I2PD_JNI.onNetworkStateChanged(true);
|
|
||||||
Log.i(TAG, "NetworkCallback.onAvailable");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLost(Network network) {
|
|
||||||
super.onLost(network);
|
|
||||||
I2PD_JNI.onNetworkStateChanged(false);
|
|
||||||
Log.i(TAG, " NetworkCallback.onLost");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void quit() {
|
private void quit() {
|
||||||
try {
|
try {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
|
39
android/src/org/purplei2p/i2pd/WebConsoleActivity.java
Normal file
39
android/src/org/purplei2p/i2pd/WebConsoleActivity.java
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package org.purplei2p.i2pd;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.webkit.WebSettings;
|
||||||
|
import android.webkit.WebView;
|
||||||
|
import android.webkit.WebViewClient;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class WebConsoleActivity extends Activity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_web_console);
|
||||||
|
|
||||||
|
Objects.requireNonNull(getActionBar()).setDisplayHomeAsUpEnabled(true);
|
||||||
|
|
||||||
|
final WebView webView = findViewById(R.id.webview1);
|
||||||
|
webView.setWebViewClient(new WebViewClient());
|
||||||
|
|
||||||
|
final WebSettings webSettings = webView.getSettings();
|
||||||
|
webSettings.setBuiltInZoomControls(true);
|
||||||
|
webSettings.setJavaScriptEnabled(false);
|
||||||
|
webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
if (id==android.R.id.home) {
|
||||||
|
finish();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
version: 2.33.0.{build}
|
version: 2.35.0.{build}
|
||||||
pull_requests:
|
pull_requests:
|
||||||
do_not_increment_build_number: true
|
do_not_increment_build_number: true
|
||||||
branches:
|
branches:
|
||||||
|
|
|
@ -11,9 +11,8 @@ if(WIN32 OR MSVC OR MSYS OR MINGW)
|
||||||
message(SEND_ERROR "cmake build for windows is not supported. Please use MSYS2 with makefiles in project root.")
|
message(SEND_ERROR "cmake build for windows is not supported. Please use MSYS2 with makefiles in project root.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# configurale options
|
# configurable options
|
||||||
option(WITH_AESNI "Use AES-NI instructions set" OFF)
|
option(WITH_AESNI "Use AES-NI instructions set" ON)
|
||||||
option(WITH_AVX "Use AVX instructions" OFF)
|
|
||||||
option(WITH_HARDENING "Use hardening compiler flags" OFF)
|
option(WITH_HARDENING "Use hardening compiler flags" OFF)
|
||||||
option(WITH_LIBRARY "Build library" ON)
|
option(WITH_LIBRARY "Build library" ON)
|
||||||
option(WITH_BINARY "Build binary" ON)
|
option(WITH_BINARY "Build binary" ON)
|
||||||
|
@ -189,13 +188,11 @@ if(UNIX)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_AESNI)
|
# Note: AES-NI and AVX is available on x86-based CPU's.
|
||||||
|
# Here also ARM64 implementation, but currently we don't support it.
|
||||||
|
if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386"))
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||||
add_definitions(-DAESNI)
|
add_definitions(-D__AES__)
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_AVX)
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_ADDRSANITIZER)
|
if(WITH_ADDRSANITIZER)
|
||||||
|
@ -309,7 +306,6 @@ message(STATUS "Architecture : ${ARCHITECTURE}")
|
||||||
message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}")
|
message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}")
|
||||||
message(STATUS "Options:")
|
message(STATUS "Options:")
|
||||||
message(STATUS " AESNI : ${WITH_AESNI}")
|
message(STATUS " AESNI : ${WITH_AESNI}")
|
||||||
message(STATUS " AVX : ${WITH_AVX}")
|
|
||||||
message(STATUS " HARDENING : ${WITH_HARDENING}")
|
message(STATUS " HARDENING : ${WITH_HARDENING}")
|
||||||
message(STATUS " LIBRARY : ${WITH_LIBRARY}")
|
message(STATUS " LIBRARY : ${WITH_LIBRARY}")
|
||||||
message(STATUS " BINARY : ${WITH_BINARY}")
|
message(STATUS " BINARY : ${WITH_BINARY}")
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
setlocal enableextensions enabledelayedexpansion
|
setlocal enableextensions enabledelayedexpansion
|
||||||
title Building i2pd
|
title Building i2pd
|
||||||
|
|
||||||
REM Copyright (c) 2013-2017, The PurpleI2P Project
|
REM Copyright (c) 2013-2020, 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
|
||||||
|
|
||||||
|
@ -23,17 +23,17 @@ 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"
|
||||||
|
|
||||||
REM detecting number of processors and subtract 1.
|
REM detecting number of processors
|
||||||
set /a threads=%NUMBER_OF_PROCESSORS%-1
|
set /a threads=%NUMBER_OF_PROCESSORS%
|
||||||
|
|
||||||
REM we must work in root of repo
|
REM we must work in root of repo
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
REM deleting old log files
|
REM deleting old log files
|
||||||
del /S build_*.log >> nul
|
del /S build_*.log >> nul 2>&1
|
||||||
|
|
||||||
echo Receiving latest commit and cleaning up...
|
echo Receiving latest commit and cleaning up...
|
||||||
%xSH% "git pull && make clean" > build/build_git.log 2>&1
|
%xSH% "git checkout contrib/* && git pull && make clean" > build\build.log 2>&1
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
REM set to variable current commit hash
|
REM set to variable current commit hash
|
||||||
|
@ -43,16 +43,17 @@ FOR /F "usebackq" %%a IN (`%xSH% 'git describe --tags'`) DO (
|
||||||
|
|
||||||
%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)
|
||||||
|
%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/*" >> build\build.log 2>&1
|
||||||
|
|
||||||
REM starting building
|
REM starting building
|
||||||
set MSYSTEM=MINGW32
|
set MSYSTEM=MINGW32
|
||||||
set bitness=32
|
set bitness=32
|
||||||
call :BUILDING
|
call :BUILDING
|
||||||
echo.
|
|
||||||
|
|
||||||
set MSYSTEM=MINGW64
|
set MSYSTEM=MINGW64
|
||||||
set bitness=64
|
set bitness=64
|
||||||
call :BUILDING
|
call :BUILDING
|
||||||
echo.
|
|
||||||
|
|
||||||
REM building for WinXP
|
REM building for WinXP
|
||||||
set "WD=C:\msys64-xp\usr\bin\"
|
set "WD=C:\msys64-xp\usr\bin\"
|
||||||
|
@ -62,7 +63,10 @@ set "xSH=%WD%bash -lc"
|
||||||
call :BUILDING_XP
|
call :BUILDING_XP
|
||||||
echo.
|
echo.
|
||||||
|
|
||||||
del README.txt >> nul
|
REM compile installer
|
||||||
|
C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_ver="%tag%" build\win_installer.iss >> build\build.log 2>&1
|
||||||
|
|
||||||
|
del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul
|
||||||
|
|
||||||
echo Build complete...
|
echo Build complete...
|
||||||
pause
|
pause
|
||||||
|
@ -70,20 +74,13 @@ 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%
|
||||||
echo Build AVX+AESNI...
|
%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
|
||||||
%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_avx_aesni_%tag%.log 2>&1
|
|
||||||
echo Build AVX...
|
|
||||||
%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip %FILELIST% && make clean" > build/build_win%bitness%_avx_%tag%.log 2>&1
|
|
||||||
echo Build AESNI...
|
|
||||||
%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1
|
|
||||||
echo Build without extensions...
|
|
||||||
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1
|
|
||||||
goto EOF
|
goto EOF
|
||||||
|
|
||||||
:BUILDING_XP
|
:BUILDING_XP
|
||||||
%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% && 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% && cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build\build_winxp_%tag%.log 2>&1
|
||||||
|
|
||||||
:EOF
|
:EOF
|
|
@ -1,6 +1,8 @@
|
||||||
#define I2Pd_AppName "i2pd"
|
#define I2Pd_AppName "i2pd"
|
||||||
#define I2Pd_ver "2.33.0"
|
|
||||||
#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}
|
||||||
|
@ -10,9 +12,9 @@ DefaultDirName={pf}\I2Pd
|
||||||
DefaultGroupName=I2Pd
|
DefaultGroupName=I2Pd
|
||||||
UninstallDisplayIcon={app}\I2Pd.exe
|
UninstallDisplayIcon={app}\I2Pd.exe
|
||||||
OutputDir=.
|
OutputDir=.
|
||||||
LicenseFile=../LICENSE
|
LicenseFile=..\LICENSE
|
||||||
OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver}
|
OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver}
|
||||||
SetupIconFile=mask.ico
|
SetupIconFile=..\Win32\mask.ico
|
||||||
InternalCompressLevel=ultra64
|
InternalCompressLevel=ultra64
|
||||||
Compression=lzma/ultra64
|
Compression=lzma/ultra64
|
||||||
SolidCompression=true
|
SolidCompression=true
|
||||||
|
@ -23,10 +25,12 @@ AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2}
|
||||||
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
|
||||||
|
CloseApplications=yes
|
||||||
|
|
||||||
[Files]
|
[Files]
|
||||||
Source: ..\i2pd_x86.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64
|
Source: ..\i2pd_x32.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64; MinVersion: 6.0
|
||||||
Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64
|
Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64; MinVersion: 6.0
|
||||||
|
Source: ..\i2pd_xp.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64; OnlyBelowVersion: 6.0
|
||||||
Source: ..\README.md; DestDir: {app}; DestName: Readme.txt; Flags: onlyifdoesntexist
|
Source: ..\README.md; DestDir: {app}; DestName: Readme.txt; Flags: onlyifdoesntexist
|
||||||
Source: ..\contrib\i2pd.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
Source: ..\contrib\i2pd.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
||||||
Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Copyright (c) 2013-2017, The PurpleI2P Project
|
# Copyright (c) 2013-2020, The PurpleI2P Project
|
||||||
#
|
#
|
||||||
# This file is part of Purple i2pd project and licensed under BSD3
|
# This file is part of Purple i2pd project and licensed under BSD3
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
# Copyright (c) 2013-2019, The PurpleI2P Project
|
# Copyright (c) 2013-2020, The PurpleI2P Project
|
||||||
#
|
#
|
||||||
# This file is part of Purple i2pd project and licensed under BSD3
|
# This file is part of Purple i2pd project and licensed under BSD3
|
||||||
#
|
#
|
||||||
|
@ -21,13 +21,13 @@ arch=$(uname -m)
|
||||||
|
|
||||||
screenfind=$(which screen)
|
screenfind=$(which screen)
|
||||||
if [ -z $screenfind ]; then
|
if [ -z $screenfind ]; then
|
||||||
echo "Can't find 'screen' installed. That script needs it!";
|
echo "Can't find 'screen' installed. That script needs it!";
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z i2pd-$arch ]; then
|
if [ -z i2pd-$arch ]; then
|
||||||
echo "Can't find i2pd binary for your archtecture.";
|
echo "Can't find i2pd binary for your archtecture.";
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
screen -AmdS i2pd ./i2pd-$arch --datadir=$DIR
|
screen -AmdS i2pd ./i2pd-$arch --datadir=$DIR
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFeTCCA2GgAwIBAgIEZZozujANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY
|
|
||||||
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
|
|
||||||
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNbWVlaEBtYWlsLmky
|
|
||||||
cDAeFw0xNDA2MjgyMjQ5MDlaFw0yNDA2MjcyMjQ5MDlaMG0xCzAJBgNVBAYTAlhY
|
|
||||||
MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v
|
|
||||||
dXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1tZWVoQG1haWwuaTJw
|
|
||||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnVnmPE4uUvCky0yCnnVH
|
|
||||||
cJEDqzwDPupx0zr0YDlhZk5VOPPecx5haayJ/V6nXPc1aVVWn+CHfedcF2aBgN4K
|
|
||||||
5aBueS/l6l5WHcv02DofAqlTmyAws3oQeR1qoTuW24cKRtLR7h5bxv63f6bgp6e+
|
|
||||||
RihFNez6UxErnRPuJOJEO2Im6EgVp6fz7tQ7R35zxAUeES2YILPySvzy2vYm/EEG
|
|
||||||
jXX7Ap2A5svVo90xCMOeUZ/55vLsjyIshN+tV87U4xwvAkUmwsmWVHm3BQpHkI6z
|
|
||||||
zMJie6epB8Bqm0GYm0EcElJH4OCxGTvDLoghpswbuUO7iy3JSfoL7ZCnoiQdK9K4
|
|
||||||
yVVChj8lG+r7KaTowK96iZep+sZefjOt5VFGuW2Fi/WBv3ldiLlJAo/ZfrUM4+vG
|
|
||||||
fyNBXbl6bX87uTCGOT1p3dazo+zJMsAZ+Y93DlM/mDEWFa1kKNrs74syzaWEqF4L
|
|
||||||
KQE6VoYn80OOzafSigTVQgSwUtQtB0XGhMzJhyxU2XHWe1LFIy7Pta0B+lDiZj7c
|
|
||||||
I8nXxYjsDfEu/Elj/Ra9N6bH0awmgB5JDa+Tbir+oEM5SyDfpSaCGuatdGxjweGI
|
|
||||||
kVmFU0SqCZV/8TXbIu6MUVzTZMZVT94edifFSRad4fqw7eZbSXlPu++3d1/btn6h
|
|
||||||
ibM04nkv0mm+FxCKB/wdAkECAwEAAaMhMB8wHQYDVR0OBBYEFO7jIkSRkoXyJcho
|
|
||||||
9/Q0gDOINa5EMA0GCSqGSIb3DQEBDQUAA4ICAQBzfWO7+8HWOKLaYWToJ6XZbpNF
|
|
||||||
3wXv1yC4W/HRR80m4JSsq9r0d7838Nvd7vLVP6MY6MaVb/JnV76FdQ5WQ6ticD0Y
|
|
||||||
o3zmpqqbKVSspN0lrkig4surT88AjfVQz/vEIzKNQEbpzc3hC2LCiE2u+cK/ix4j
|
|
||||||
b9RohnaPvwLnew5RNQRpcmk+XejaNITISr2yQIwXL7TEYy8HdGCfzFSSFhKe9vkb
|
|
||||||
GsWS5ASrUzRoprswmlgRe8gEHI+d51Z7mWgna0/5mBz9bH/3QXtpxlLWm3bVV+kt
|
|
||||||
pZjQDTHE0GqG2YsD1Gmp4LU/JFhCojMTtiPCXmr9KFtpiVlx06DuKm5PC8Ak+5w+
|
|
||||||
m/DQYYfv9z+AA5Y430bjnzwg67bhqVyyek4wcDQinFswv3h4bIB7CJujDcEqXXza
|
|
||||||
lhG1ufPPCUTMrVjh7AShohZraqlSlyQPY9vEppLwD4W1d+MqDHM7ljOH7gQYaUPi
|
|
||||||
wE30AdXEOxLZcT3aRKxkKf2esNofSuUC/+NXQvPjpuI4UJKO3eegi+M9dbnKoNWs
|
|
||||||
MPPLPpycecWPheFYM5K6Ao63cjlUY2wYwCfDTFgjA5q8i/Rp7i6Z6fLE3YWJ4VdR
|
|
||||||
WOFB7hlluQ//jMW6M1qz6IYXmlUjcXl81VEvlOH/QBNrPvX3I3SYXYgVRnVGUudB
|
|
||||||
o3eNsanvTU+TIFBh2Q==
|
|
||||||
-----END CERTIFICATE-----
|
|
|
@ -229,3 +229,12 @@ verify = true
|
||||||
[persist]
|
[persist]
|
||||||
## Save peer profiles on disk (default: true)
|
## Save peer profiles on disk (default: true)
|
||||||
# profiles = true
|
# profiles = true
|
||||||
|
|
||||||
|
[cpuext]
|
||||||
|
## Use CPU AES-NI instructions set when work with cryptography when available (default: true)
|
||||||
|
# aesni = true
|
||||||
|
## Use CPU AVX instructions set when work with cryptography when available (default: true)
|
||||||
|
# avx = true
|
||||||
|
## Force usage of CPU instructions set, even if they not found
|
||||||
|
## DO NOT TOUCH that option if you really don't know what are you doing!
|
||||||
|
# force = false
|
|
@ -1,7 +1,7 @@
|
||||||
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
%define git_hash %(git rev-parse HEAD | cut -c -7)
|
||||||
|
|
||||||
Name: i2pd-git
|
Name: i2pd-git
|
||||||
Version: 2.33.0
|
Version: 2.35.0
|
||||||
Release: git%{git_hash}%{?dist}
|
Release: git%{git_hash}%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd
|
Conflicts: i2pd
|
||||||
|
@ -56,18 +56,31 @@ cd build
|
||||||
%endif
|
%endif
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?mageia} > 7
|
%if 0%{?fedora} >= 33
|
||||||
pushd build
|
pushd %{_target_platform}
|
||||||
make %{?_smp_mflags}
|
|
||||||
popd
|
|
||||||
%else
|
|
||||||
make %{?_smp_mflags}
|
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?mageia} > 7
|
||||||
|
pushd build
|
||||||
|
%endif
|
||||||
|
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
|
%if 0%{?fedora} >= 33
|
||||||
|
popd
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?mageia} > 7
|
||||||
|
popd
|
||||||
|
%endif
|
||||||
|
|
||||||
%install
|
%install
|
||||||
pushd build
|
pushd build
|
||||||
|
|
||||||
|
%if 0%{?fedora} >= 33
|
||||||
|
pushd %{_target_platform}
|
||||||
|
%endif
|
||||||
|
|
||||||
%if 0%{?mageia}
|
%if 0%{?mageia}
|
||||||
pushd build
|
pushd build
|
||||||
%endif
|
%endif
|
||||||
|
@ -124,6 +137,12 @@ getent passwd i2pd >/dev/null || \
|
||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Nov 30 2020 orignal <i2porignal@yandex.ru> - 2.35.0
|
||||||
|
- update to 2.35.0
|
||||||
|
|
||||||
|
* Tue Oct 27 2020 orignal <i2porignal@yandex.ru> - 2.34.0
|
||||||
|
- update to 2.34.0
|
||||||
|
|
||||||
* Mon Aug 24 2020 orignal <i2porignal@yandex.ru> - 2.33.0
|
* Mon Aug 24 2020 orignal <i2porignal@yandex.ru> - 2.33.0
|
||||||
- update to 2.33.0
|
- update to 2.33.0
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Name: i2pd
|
Name: i2pd
|
||||||
Version: 2.33.0
|
Version: 2.35.0
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: I2P router written in C++
|
Summary: I2P router written in C++
|
||||||
Conflicts: i2pd-git
|
Conflicts: i2pd-git
|
||||||
|
@ -54,18 +54,31 @@ cd build
|
||||||
%endif
|
%endif
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
%if 0%{?mageia} > 7
|
%if 0%{?fedora} >= 33
|
||||||
pushd build
|
pushd %{_target_platform}
|
||||||
make %{?_smp_mflags}
|
|
||||||
popd
|
|
||||||
%else
|
|
||||||
make %{?_smp_mflags}
|
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?mageia} > 7
|
||||||
|
pushd build
|
||||||
|
%endif
|
||||||
|
|
||||||
|
make %{?_smp_mflags}
|
||||||
|
|
||||||
|
%if 0%{?fedora} >= 33
|
||||||
|
popd
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%if 0%{?mageia} > 7
|
||||||
|
popd
|
||||||
|
%endif
|
||||||
|
|
||||||
%install
|
%install
|
||||||
pushd build
|
pushd build
|
||||||
|
|
||||||
|
%if 0%{?fedora} >= 33
|
||||||
|
pushd %{_target_platform}
|
||||||
|
%endif
|
||||||
|
|
||||||
%if 0%{?mageia}
|
%if 0%{?mageia}
|
||||||
pushd build
|
pushd build
|
||||||
%endif
|
%endif
|
||||||
|
@ -122,6 +135,12 @@ getent passwd i2pd >/dev/null || \
|
||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Nov 30 2020 orignal <i2porignal@yandex.ru> - 2.35.0
|
||||||
|
- update to 2.35.0
|
||||||
|
|
||||||
|
* Tue Oct 27 2020 orignal <i2porignal@yandex.ru> - 2.34.0
|
||||||
|
- update to 2.34.0
|
||||||
|
|
||||||
* Mon Aug 24 2020 orignal <i2porignal@yandex.ru> - 2.33.0
|
* Mon Aug 24 2020 orignal <i2porignal@yandex.ru> - 2.33.0
|
||||||
- update to 2.33.0
|
- update to 2.33.0
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,10 @@ namespace i2p
|
||||||
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
||||||
|
|
||||||
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
|
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
|
||||||
i2p::crypto::InitCrypto (precomputation);
|
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
|
||||||
|
bool avx; i2p::config::GetOption("cpuext.avx", avx);
|
||||||
|
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
|
||||||
|
i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
|
||||||
|
|
||||||
int netID; i2p::config::GetOption("netid", netID);
|
int netID; i2p::config::GetOption("netid", netID);
|
||||||
i2p::context.SetNetID (netID);
|
i2p::context.SetNetID (netID);
|
||||||
|
|
|
@ -30,8 +30,9 @@
|
||||||
#include "Daemon.h"
|
#include "Daemon.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ECIESX25519AEADRatchetSession.h"
|
#include "ECIESX25519AEADRatchetSession.h"
|
||||||
|
|
||||||
#ifdef WIN32_APP
|
#ifdef WIN32_APP
|
||||||
#include "Win32/Win32App.h"
|
#include "Win32App.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For image and info
|
// For image and info
|
||||||
|
@ -69,7 +70,7 @@ namespace http {
|
||||||
" .menu { float: left; } .menu a, .commands a { display: block; }\r\n"
|
" .menu { float: left; } .menu a, .commands a { display: block; }\r\n"
|
||||||
" .listitem { display: block; 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"
|
||||||
" .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
" .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n"
|
||||||
" .content { float: left; font-size: 1em; margin-left: 4em; max-width: 46em; overflow: auto; }\r\n"
|
" .content { float: left; font-size: 1em; margin-left: 4em; max-width: 45em; overflow: auto; }\r\n"
|
||||||
" .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n"
|
" .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n"
|
||||||
" .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n"
|
" .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n"
|
||||||
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
|
" caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n"
|
||||||
|
@ -270,8 +271,18 @@ namespace http {
|
||||||
}
|
}
|
||||||
s << "<br>\r\n";
|
s << "<br>\r\n";
|
||||||
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
|
||||||
if (auto remains = Daemon.gracefulShutdownInterval)
|
if (auto remains = Daemon.gracefulShutdownInterval) {
|
||||||
s << "<b>Stopping in:</b> " << remains << " seconds<br>\r\n";
|
s << "<b>Stopping in:</b> ";
|
||||||
|
ShowUptime(s, remains);
|
||||||
|
s << "<br>\r\n";
|
||||||
|
}
|
||||||
|
#elif defined(WIN32_APP)
|
||||||
|
if (i2p::win32::g_GracefulShutdownEndtime != 0) {
|
||||||
|
uint16_t remains = (i2p::win32::g_GracefulShutdownEndtime - GetTickCount()) / 1000;
|
||||||
|
s << "<b>Stopping in:</b> ";
|
||||||
|
ShowUptime(s, remains);
|
||||||
|
s << "<br>\r\n";
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
auto family = i2p::context.GetFamily ();
|
auto family = i2p::context.GetFamily ();
|
||||||
if (family.length () > 0)
|
if (family.length () > 0)
|
||||||
|
@ -838,6 +849,7 @@ namespace http {
|
||||||
case i2p::client::eSAMSocketTypeSession : s << "session"; break;
|
case i2p::client::eSAMSocketTypeSession : s << "session"; break;
|
||||||
case i2p::client::eSAMSocketTypeStream : s << "stream"; break;
|
case i2p::client::eSAMSocketTypeStream : s << "stream"; break;
|
||||||
case i2p::client::eSAMSocketTypeAcceptor : s << "acceptor"; break;
|
case i2p::client::eSAMSocketTypeAcceptor : s << "acceptor"; break;
|
||||||
|
case i2p::client::eSAMSocketTypeForward : s << "forward"; break;
|
||||||
default: s << "unknown"; break;
|
default: s << "unknown"; break;
|
||||||
}
|
}
|
||||||
s << " [" << it->GetSocket ().remote_endpoint() << "]";
|
s << " [" << it->GetSocket ().remote_endpoint() << "]";
|
||||||
|
|
12
debian/changelog
vendored
12
debian/changelog
vendored
|
@ -1,3 +1,15 @@
|
||||||
|
i2pd (2.35.0-1) unstable; urgency=high
|
||||||
|
|
||||||
|
* updated to version 2.35.0/0.9.48
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Mon, 30 Nov 2020 16:00:00 +0000
|
||||||
|
|
||||||
|
i2pd (2.34.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
* updated to version 2.34.0
|
||||||
|
|
||||||
|
-- orignal <orignal@i2pmail.org> Tue, 27 Oct 2020 16:00:00 +0000
|
||||||
|
|
||||||
i2pd (2.33.0-1) unstable; urgency=medium
|
i2pd (2.33.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
* updated to version 2.33.0/0.9.47
|
* updated to version 2.33.0/0.9.47
|
||||||
|
|
2
debian/compat
vendored
2
debian/compat
vendored
|
@ -1 +1 @@
|
||||||
9
|
10
|
15
debian/patches/01-tune-build-opts.patch
vendored
15
debian/patches/01-tune-build-opts.patch
vendored
|
@ -1,15 +0,0 @@
|
||||||
Index: i2pd/Makefile
|
|
||||||
===================================================================
|
|
||||||
--- i2pd.orig/Makefile
|
|
||||||
+++ i2pd/Makefile
|
|
||||||
@@ -13,8 +13,8 @@ DAEMON_SRC_DIR := daemon
|
|
||||||
|
|
||||||
include filelist.mk
|
|
||||||
|
|
||||||
-USE_AESNI := yes
|
|
||||||
-USE_AVX := yes
|
|
||||||
+USE_AESNI := no
|
|
||||||
+USE_AVX := no
|
|
||||||
USE_STATIC := no
|
|
||||||
USE_MESHNET := no
|
|
||||||
USE_UPNP := no
|
|
3
debian/patches/series
vendored
3
debian/patches/series
vendored
|
@ -1,2 +1 @@
|
||||||
01-tune-build-opts.patch
|
01-fix-1210.patch
|
||||||
02-fix-1210.patch
|
|
||||||
|
|
|
@ -27,37 +27,32 @@ namespace cpu
|
||||||
bool aesni = false;
|
bool aesni = false;
|
||||||
bool avx = false;
|
bool avx = false;
|
||||||
|
|
||||||
void Detect()
|
void Detect(bool AesSwitch, bool AvxSwitch, bool force)
|
||||||
{
|
{
|
||||||
#if defined(__AES__) || defined(__AVX__)
|
|
||||||
|
|
||||||
#if defined(__x86_64__) || defined(__i386__)
|
#if defined(__x86_64__) || defined(__i386__)
|
||||||
int info[4];
|
int info[4];
|
||||||
__cpuid(0, info[0], info[1], info[2], info[3]);
|
__cpuid(0, info[0], info[1], info[2], info[3]);
|
||||||
if (info[0] >= 0x00000001) {
|
if (info[0] >= 0x00000001) {
|
||||||
__cpuid(0x00000001, info[0], info[1], info[2], info[3]);
|
__cpuid(0x00000001, info[0], info[1], info[2], info[3]);
|
||||||
#ifdef __AES__
|
#if defined (_WIN32) && (WINVER == 0x0501) // WinXP
|
||||||
aesni = info[2] & bit_AES; // AESNI
|
if (AesSwitch && force) { // only if forced
|
||||||
#endif // __AES__
|
#else
|
||||||
#ifdef __AVX__
|
if ((info[2] & bit_AES && AesSwitch) || (AesSwitch && force)) {
|
||||||
avx = info[2] & bit_AVX; // AVX
|
#endif
|
||||||
#endif // __AVX__
|
aesni = true;
|
||||||
|
}
|
||||||
|
#if defined (_WIN32) && (WINVER == 0x0501) // WinXP
|
||||||
|
if (AvxSwitch && force) { // only if forced
|
||||||
|
#else
|
||||||
|
if ((info[2] & bit_AVX && AvxSwitch) || (AvxSwitch && force)) {
|
||||||
|
#endif
|
||||||
|
avx = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // defined(__x86_64__) || defined(__i386__)
|
#endif // defined(__x86_64__) || defined(__i386__)
|
||||||
|
|
||||||
#ifdef __AES__
|
LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled"));
|
||||||
if(aesni)
|
LogPrint(eLogInfo, "AVX ", (avx ? "enabled" : "disabled"));
|
||||||
{
|
|
||||||
LogPrint(eLogInfo, "AESNI enabled");
|
|
||||||
}
|
|
||||||
#endif // __AES__
|
|
||||||
#ifdef __AVX__
|
|
||||||
if(avx)
|
|
||||||
{
|
|
||||||
LogPrint(eLogInfo, "AVX enabled");
|
|
||||||
}
|
|
||||||
#endif // __AVX__
|
|
||||||
#endif // defined(__AES__) || defined(__AVX__)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ namespace cpu
|
||||||
extern bool aesni;
|
extern bool aesni;
|
||||||
extern bool avx;
|
extern bool avx;
|
||||||
|
|
||||||
void Detect();
|
void Detect(bool AesSwitch, bool AvxSwitch, bool force);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,11 +47,11 @@ namespace config {
|
||||||
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
|
("ifname", value<std::string>()->default_value(""), "Network interface to bind to")
|
||||||
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
|
("ifname4", value<std::string>()->default_value(""), "Network interface to bind to for ipv4")
|
||||||
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
|
("ifname6", value<std::string>()->default_value(""), "Network interface to bind to for ipv6")
|
||||||
("nat", value<bool>()->default_value(true), "Should we assume we are behind NAT? (default: enabled)")
|
("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)")
|
||||||
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
|
||||||
("ipv4", value<bool>()->default_value(true), "Enable communication through ipv4 (default: enabled)")
|
("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)")
|
||||||
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)")
|
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)")
|
||||||
("reservedrange", value<bool>()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)")
|
("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)")
|
||||||
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
|
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
|
||||||
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)")
|
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)")
|
||||||
("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)")
|
||||||
|
@ -59,8 +59,8 @@ namespace config {
|
||||||
("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(""), "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", value<bool>()->default_value(false), "Ignored. Always false")
|
("ntcp", bool_switch()->default_value(false), "Ignored. Always false")
|
||||||
("ssu", value<bool>()->default_value(true), "Enable SSU transport (default: enabled)")
|
("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)")
|
||||||
("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
|
("ntcpproxy", value<std::string>()->default_value(""), "Ignored")
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
|
("svcctl", value<std::string>()->default_value(""), "Windows service management ('install' or 'remove')")
|
||||||
|
@ -197,13 +197,12 @@ namespace config {
|
||||||
("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://reseed.i2p-projekt.de/,"
|
||||||
"https://reseed.diva.exchange/,"
|
"https://reseed.diva.exchange/,"
|
||||||
"https://reseed.i2p2.no/,"
|
|
||||||
"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/"
|
||||||
), "Reseed URLs, separated by comma")
|
), "Reseed URLs, separated by comma")
|
||||||
;
|
;
|
||||||
|
@ -266,6 +265,13 @@ namespace config {
|
||||||
("persist.addressbook", value<bool>()->default_value(true), "Persist full addresses (default: true)")
|
("persist.addressbook", value<bool>()->default_value(true), "Persist full addresses (default: true)")
|
||||||
;
|
;
|
||||||
|
|
||||||
|
options_description cpuext("CPU encryption extensions options");
|
||||||
|
cpuext.add_options()
|
||||||
|
("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used")
|
||||||
|
("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used")
|
||||||
|
("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines")
|
||||||
|
;
|
||||||
|
|
||||||
m_OptionsDesc
|
m_OptionsDesc
|
||||||
.add(general)
|
.add(general)
|
||||||
.add(limits)
|
.add(limits)
|
||||||
|
@ -286,6 +292,7 @@ namespace config {
|
||||||
.add(ntcp2)
|
.add(ntcp2)
|
||||||
.add(nettime)
|
.add(nettime)
|
||||||
.add(persist)
|
.add(persist)
|
||||||
|
.add(cpuext)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,7 +119,7 @@ namespace crypto
|
||||||
|
|
||||||
~CryptoConstants ()
|
~CryptoConstants ()
|
||||||
{
|
{
|
||||||
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
|
BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ namespace crypto
|
||||||
bn2buf (y, encrypted + len, len);
|
bn2buf (y, encrypted + len, len);
|
||||||
RAND_bytes (encrypted + 2*len, 256 - 2*len);
|
RAND_bytes (encrypted + 2*len, 256 - 2*len);
|
||||||
}
|
}
|
||||||
// ecryption key and iv
|
// encryption key and iv
|
||||||
EC_POINT_mul (curve, p, nullptr, key, k, ctx);
|
EC_POINT_mul (curve, p, nullptr, key, k, ctx);
|
||||||
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
|
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr);
|
||||||
uint8_t keyBuf[64], iv[64], shared[32];
|
uint8_t keyBuf[64], iv[64], shared[32];
|
||||||
|
@ -638,7 +638,7 @@ namespace crypto
|
||||||
{
|
{
|
||||||
uint64_t buf[256];
|
uint64_t buf[256];
|
||||||
uint64_t hash[12]; // 96 bytes
|
uint64_t hash[12]; // 96 bytes
|
||||||
#ifdef __AVX__
|
#if defined(__x86_64__) || defined(__i386__)
|
||||||
if(i2p::cpu::avx)
|
if(i2p::cpu::avx)
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
|
@ -657,7 +657,7 @@ namespace crypto
|
||||||
:
|
:
|
||||||
: [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
|
: [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads),
|
||||||
[buf]"r"(buf), [hash]"r"(hash)
|
[buf]"r"(buf), [hash]"r"(hash)
|
||||||
: "memory", "%xmm0" // TODO: change to %ymm0 later
|
: "memory", "%xmm0" // TODO: change to %ymm0 later
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -688,7 +688,7 @@ namespace crypto
|
||||||
// concatenate with msg
|
// concatenate with msg
|
||||||
memcpy (buf + 8, msg, len);
|
memcpy (buf + 8, msg, len);
|
||||||
// calculate first hash
|
// calculate first hash
|
||||||
MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
|
MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes
|
||||||
|
|
||||||
// calculate digest
|
// calculate digest
|
||||||
MD5((uint8_t *)hash, 96, digest);
|
MD5((uint8_t *)hash, 96, digest);
|
||||||
|
@ -696,35 +696,28 @@ namespace crypto
|
||||||
|
|
||||||
// AES
|
// AES
|
||||||
#ifdef __AES__
|
#ifdef __AES__
|
||||||
#ifdef ARM64AES
|
|
||||||
void init_aesenc(void){
|
|
||||||
// TODO: Implementation
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define KeyExpansion256(round0,round1) \
|
#define KeyExpansion256(round0,round1) \
|
||||||
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
"pshufd $0xff, %%xmm2, %%xmm2 \n" \
|
||||||
"movaps %%xmm1, %%xmm4 \n" \
|
"movaps %%xmm1, %%xmm4 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm1 \n" \
|
"pxor %%xmm4, %%xmm1 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm1 \n" \
|
"pxor %%xmm4, %%xmm1 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm1 \n" \
|
"pxor %%xmm4, %%xmm1 \n" \
|
||||||
"pxor %%xmm2, %%xmm1 \n" \
|
"pxor %%xmm2, %%xmm1 \n" \
|
||||||
"movaps %%xmm1, "#round0"(%[sched]) \n" \
|
"movaps %%xmm1, "#round0"(%[sched]) \n" \
|
||||||
"aeskeygenassist $0, %%xmm1, %%xmm4 \n" \
|
"aeskeygenassist $0, %%xmm1, %%xmm4 \n" \
|
||||||
"pshufd $0xaa, %%xmm4, %%xmm2 \n" \
|
"pshufd $0xaa, %%xmm4, %%xmm2 \n" \
|
||||||
"movaps %%xmm3, %%xmm4 \n" \
|
"movaps %%xmm3, %%xmm4 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm3 \n" \
|
"pxor %%xmm4, %%xmm3 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm3 \n" \
|
"pxor %%xmm4, %%xmm3 \n" \
|
||||||
"pslldq $4, %%xmm4 \n" \
|
"pslldq $4, %%xmm4 \n" \
|
||||||
"pxor %%xmm4, %%xmm3 \n" \
|
"pxor %%xmm4, %%xmm3 \n" \
|
||||||
"pxor %%xmm2, %%xmm3 \n" \
|
"pxor %%xmm2, %%xmm3 \n" \
|
||||||
"movaps %%xmm3, "#round1"(%[sched]) \n"
|
"movaps %%xmm3, "#round1"(%[sched]) \n"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __AES__
|
#ifdef __AES__
|
||||||
|
@ -750,16 +743,16 @@ namespace crypto
|
||||||
KeyExpansion256(192,208)
|
KeyExpansion256(192,208)
|
||||||
"aeskeygenassist $64, %%xmm3, %%xmm2 \n"
|
"aeskeygenassist $64, %%xmm3, %%xmm2 \n"
|
||||||
// key expansion final
|
// key expansion final
|
||||||
"pshufd $0xff, %%xmm2, %%xmm2 \n"
|
"pshufd $0xff, %%xmm2, %%xmm2 \n"
|
||||||
"movaps %%xmm1, %%xmm4 \n"
|
"movaps %%xmm1, %%xmm4 \n"
|
||||||
"pslldq $4, %%xmm4 \n"
|
"pslldq $4, %%xmm4 \n"
|
||||||
"pxor %%xmm4, %%xmm1 \n"
|
"pxor %%xmm4, %%xmm1 \n"
|
||||||
"pslldq $4, %%xmm4 \n"
|
"pslldq $4, %%xmm4 \n"
|
||||||
"pxor %%xmm4, %%xmm1 \n"
|
"pxor %%xmm4, %%xmm1 \n"
|
||||||
"pslldq $4, %%xmm4 \n"
|
"pslldq $4, %%xmm4 \n"
|
||||||
"pxor %%xmm4, %%xmm1 \n"
|
"pxor %%xmm4, %%xmm1 \n"
|
||||||
"pxor %%xmm2, %%xmm1 \n"
|
"pxor %%xmm2, %%xmm1 \n"
|
||||||
"movups %%xmm1, 224(%[sched]) \n"
|
"movups %%xmm1, 224(%[sched]) \n"
|
||||||
: // output
|
: // output
|
||||||
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
|
: [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input
|
||||||
: "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged
|
: "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged
|
||||||
|
@ -794,9 +787,9 @@ namespace crypto
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
EncryptAES256(sched)
|
EncryptAES256(sched)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -833,9 +826,9 @@ namespace crypto
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
DecryptAES256(sched)
|
DecryptAES256(sched)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
: : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -848,7 +841,7 @@ namespace crypto
|
||||||
|
|
||||||
#ifdef __AES__
|
#ifdef __AES__
|
||||||
#define CallAESIMC(offset) \
|
#define CallAESIMC(offset) \
|
||||||
"movaps "#offset"(%[shed]), %%xmm0 \n" \
|
"movaps "#offset"(%[shed]), %%xmm0 \n" \
|
||||||
"aesimc %%xmm0, %%xmm0 \n" \
|
"aesimc %%xmm0, %%xmm0 \n" \
|
||||||
"movaps %%xmm0, "#offset"(%[shed]) \n"
|
"movaps %%xmm0, "#offset"(%[shed]) \n"
|
||||||
#endif
|
#endif
|
||||||
|
@ -873,7 +866,7 @@ namespace crypto
|
||||||
if(i2p::cpu::aesni)
|
if(i2p::cpu::aesni)
|
||||||
{
|
{
|
||||||
ExpandKey (key); // expand encryption key first
|
ExpandKey (key); // expand encryption key first
|
||||||
// then invert it using aesimc
|
// then invert it using aesimc
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
CallAESIMC(16)
|
CallAESIMC(16)
|
||||||
|
@ -906,18 +899,18 @@ namespace crypto
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
EncryptAES256(sched)
|
EncryptAES256(sched)
|
||||||
"movaps %%xmm0, %%xmm1 \n"
|
"movaps %%xmm0, %%xmm1 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
"movups %%xmm1, (%[iv]) \n"
|
"movups %%xmm1, (%[iv]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||||
|
@ -951,12 +944,12 @@ namespace crypto
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
EncryptAES256(sched)
|
EncryptAES256(sched)
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"movups %%xmm0, (%[iv]) \n"
|
"movups %%xmm0, (%[iv]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
: [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out)
|
[in]"r"(in), [out]"r"(out)
|
||||||
|
@ -975,19 +968,19 @@ namespace crypto
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"movaps %%xmm0, %%xmm2 \n"
|
"movaps %%xmm0, %%xmm2 \n"
|
||||||
DecryptAES256(sched)
|
DecryptAES256(sched)
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"movaps %%xmm2, %%xmm1 \n"
|
"movaps %%xmm2, %%xmm1 \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
"movups %%xmm1, (%[iv]) \n"
|
"movups %%xmm1, (%[iv]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
[in]"r"(in), [out]"r"(out), [num]"r"(numBlocks)
|
||||||
|
@ -1021,12 +1014,12 @@ namespace crypto
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
"movups (%[iv]), %%xmm1 \n"
|
"movups (%[iv]), %%xmm1 \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[iv]) \n"
|
"movups %%xmm0, (%[iv]) \n"
|
||||||
DecryptAES256(sched)
|
DecryptAES256(sched)
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
:
|
:
|
||||||
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
: [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()),
|
||||||
[in]"r"(in), [out]"r"(out)
|
[in]"r"(in), [out]"r"(out)
|
||||||
|
@ -1046,7 +1039,7 @@ namespace crypto
|
||||||
__asm__
|
__asm__
|
||||||
(
|
(
|
||||||
// encrypt IV
|
// encrypt IV
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
EncryptAES256(sched_iv)
|
EncryptAES256(sched_iv)
|
||||||
"movaps %%xmm0, %%xmm1 \n"
|
"movaps %%xmm0, %%xmm1 \n"
|
||||||
// double IV encryption
|
// double IV encryption
|
||||||
|
@ -1056,11 +1049,11 @@ namespace crypto
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
EncryptAES256(sched_l)
|
EncryptAES256(sched_l)
|
||||||
"movaps %%xmm0, %%xmm1 \n"
|
"movaps %%xmm0, %%xmm1 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
:
|
:
|
||||||
|
@ -1097,11 +1090,11 @@ namespace crypto
|
||||||
"1: \n"
|
"1: \n"
|
||||||
"add $16, %[in] \n"
|
"add $16, %[in] \n"
|
||||||
"add $16, %[out] \n"
|
"add $16, %[out] \n"
|
||||||
"movups (%[in]), %%xmm0 \n"
|
"movups (%[in]), %%xmm0 \n"
|
||||||
"movaps %%xmm0, %%xmm2 \n"
|
"movaps %%xmm0, %%xmm2 \n"
|
||||||
DecryptAES256(sched_l)
|
DecryptAES256(sched_l)
|
||||||
"pxor %%xmm1, %%xmm0 \n"
|
"pxor %%xmm1, %%xmm0 \n"
|
||||||
"movups %%xmm0, (%[out]) \n"
|
"movups %%xmm0, (%[out]) \n"
|
||||||
"movaps %%xmm2, %%xmm1 \n"
|
"movaps %%xmm2, %%xmm1 \n"
|
||||||
"dec %[num] \n"
|
"dec %[num] \n"
|
||||||
"jnz 1b \n"
|
"jnz 1b \n"
|
||||||
|
@ -1323,9 +1316,24 @@ namespace crypto
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NoiseSymmetricState::MixHash (const uint8_t * buf, size_t len)
|
||||||
|
{
|
||||||
|
SHA256_CTX ctx;
|
||||||
|
SHA256_Init (&ctx);
|
||||||
|
SHA256_Update (&ctx, m_H, 32);
|
||||||
|
SHA256_Update (&ctx, buf, len);
|
||||||
|
SHA256_Final (m_H, &ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret)
|
||||||
|
{
|
||||||
|
HKDF (m_CK, sharedSecret, 32, "", m_CK);
|
||||||
|
// new ck is m_CK[0:31], key is m_CK[32:63]
|
||||||
|
}
|
||||||
|
|
||||||
// init and terminate
|
// init and terminate
|
||||||
|
|
||||||
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
/* std::vector <std::unique_ptr<std::mutex> > m_OpenSSLMutexes;
|
||||||
static void OpensslLockingCallback(int mode, int type, const char * file, int line)
|
static void OpensslLockingCallback(int mode, int type, const char * file, int line)
|
||||||
{
|
{
|
||||||
if (type > 0 && (size_t)type < m_OpenSSLMutexes.size ())
|
if (type > 0 && (size_t)type < m_OpenSSLMutexes.size ())
|
||||||
|
@ -1337,10 +1345,9 @@ namespace crypto
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force)
|
||||||
void InitCrypto (bool precomputation)
|
|
||||||
{
|
{
|
||||||
i2p::cpu::Detect ();
|
i2p::cpu::Detect (aesni, avx, force);
|
||||||
#if LEGACY_OPENSSL
|
#if LEGACY_OPENSSL
|
||||||
SSL_library_init ();
|
SSL_library_init ();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -169,9 +169,6 @@ namespace crypto
|
||||||
|
|
||||||
|
|
||||||
#ifdef __AES__
|
#ifdef __AES__
|
||||||
#ifdef ARM64AES
|
|
||||||
void init_aesenc(void) __attribute__((constructor));
|
|
||||||
#endif
|
|
||||||
class ECBCryptoAESNI
|
class ECBCryptoAESNI
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -311,8 +308,18 @@ namespace crypto
|
||||||
|
|
||||||
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32
|
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32
|
||||||
|
|
||||||
|
// Noise
|
||||||
|
|
||||||
|
struct NoiseSymmetricState
|
||||||
|
{
|
||||||
|
uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/;
|
||||||
|
|
||||||
|
void MixHash (const uint8_t * buf, size_t len);
|
||||||
|
void MixKey (const uint8_t * sharedSecret);
|
||||||
|
};
|
||||||
|
|
||||||
// init and terminate
|
// init and terminate
|
||||||
void InitCrypto (bool precomputation);
|
void InitCrypto (bool precomputation, bool aesni, bool avx, bool force);
|
||||||
void TerminateCrypto ();
|
void TerminateCrypto ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -560,8 +560,8 @@ namespace client
|
||||||
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ());
|
||||||
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4);
|
||||||
auto msg = i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound);
|
auto msg = i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound);
|
||||||
if (floodfill->GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) // TODO: remove when implemented
|
if (floodfill->GetIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // TODO: remove whan implemented
|
||||||
msg = WrapMessage (floodfill, msg);
|
msg = WrapMessageForRouter (floodfill, msg);
|
||||||
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT));
|
||||||
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer,
|
||||||
shared_from_this (), std::placeholders::_1));
|
shared_from_this (), std::placeholders::_1));
|
||||||
|
@ -746,7 +746,7 @@ namespace client
|
||||||
request->excluded.insert (nextFloodfill->GetIdentHash ());
|
request->excluded.insert (nextFloodfill->GetIdentHash ());
|
||||||
request->requestTimeoutTimer.cancel ();
|
request->requestTimeoutTimer.cancel ();
|
||||||
|
|
||||||
bool isECIES = SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) &&
|
bool isECIES = SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) &&
|
||||||
nextFloodfill->GetVersion () >= MAKE_VERSION_NUMBER(0, 9, 46); // >= 0.9.46;
|
nextFloodfill->GetVersion () >= MAKE_VERSION_NUMBER(0, 9, 46); // >= 0.9.46;
|
||||||
uint8_t replyKey[32], replyTag[32];
|
uint8_t replyKey[32], replyTag[32];
|
||||||
RAND_bytes (replyKey, 32); // random session key
|
RAND_bytes (replyKey, 32); // random session key
|
||||||
|
@ -756,10 +756,9 @@ namespace client
|
||||||
else
|
else
|
||||||
AddSessionKey (replyKey, replyTag);
|
AddSessionKey (replyKey, replyTag);
|
||||||
|
|
||||||
auto msg = CreateLeaseSetDatabaseLookupMsg (dest, request->excluded,
|
auto msg = CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES);
|
||||||
request->replyTunnel, replyKey, replyTag, isECIES);
|
if (nextFloodfill->GetIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // TODO: remove whan implemented
|
||||||
if (nextFloodfill->GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) // TODO: remove when implemented
|
msg = WrapMessageForRouter (nextFloodfill, msg);
|
||||||
msg = WrapMessage (nextFloodfill, msg);
|
|
||||||
request->outboundTunnel->SendTunnelDataMsg (
|
request->outboundTunnel->SendTunnelDataMsg (
|
||||||
{
|
{
|
||||||
i2p::tunnel::TunnelMessageBlock
|
i2p::tunnel::TunnelMessageBlock
|
||||||
|
@ -846,8 +845,8 @@ namespace client
|
||||||
|
|
||||||
i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const
|
i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const
|
||||||
{
|
{
|
||||||
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
|
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||||
return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET;
|
return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD;
|
||||||
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -902,7 +901,7 @@ namespace client
|
||||||
else
|
else
|
||||||
encryptionKey->GenerateKeys ();
|
encryptionKey->GenerateKeys ();
|
||||||
encryptionKey->CreateDecryptor ();
|
encryptionKey->CreateDecryptor ();
|
||||||
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||||
{
|
{
|
||||||
m_ECIESx25519EncryptionKey.reset (encryptionKey);
|
m_ECIESx25519EncryptionKey.reset (encryptionKey);
|
||||||
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
|
||||||
|
@ -1219,7 +1218,7 @@ namespace client
|
||||||
|
|
||||||
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||||
{
|
{
|
||||||
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||||
if (m_ECIESx25519EncryptionKey && m_ECIESx25519EncryptionKey->decryptor)
|
if (m_ECIESx25519EncryptionKey && m_ECIESx25519EncryptionKey->decryptor)
|
||||||
return m_ECIESx25519EncryptionKey->decryptor->Decrypt (encrypted, data, ctx, true);
|
return m_ECIESx25519EncryptionKey->decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor)
|
if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor)
|
||||||
|
@ -1231,12 +1230,12 @@ namespace client
|
||||||
|
|
||||||
bool ClientDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
|
bool ClientDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
|
||||||
{
|
{
|
||||||
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET ? (bool)m_ECIESx25519EncryptionKey : (bool)m_StandardEncryptionKey;
|
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519EncryptionKey : (bool)m_StandardEncryptionKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
|
const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
|
||||||
{
|
{
|
||||||
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||||
return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub : nullptr;
|
return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub : nullptr;
|
||||||
return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub : nullptr;
|
return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub : nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,15 +176,6 @@ namespace garlic
|
||||||
memcpy (m_H, hh, 32);
|
memcpy (m_H, hh, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ECIESX25519AEADRatchetSession::MixHash (const uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
SHA256_CTX ctx;
|
|
||||||
SHA256_Init (&ctx);
|
|
||||||
SHA256_Update (&ctx, m_H, 32);
|
|
||||||
SHA256_Update (&ctx, buf, len);
|
|
||||||
SHA256_Final (m_H, &ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ECIESX25519AEADRatchetSession::CreateNonce (uint64_t seqn, uint8_t * nonce)
|
void ECIESX25519AEADRatchetSession::CreateNonce (uint64_t seqn, uint8_t * nonce)
|
||||||
{
|
{
|
||||||
memset (nonce, 0, 4);
|
memset (nonce, 0, 4);
|
||||||
|
@ -245,7 +236,7 @@ namespace garlic
|
||||||
if (!GetOwner ()) return false;
|
if (!GetOwner ()) return false;
|
||||||
// we are Bob
|
// we are Bob
|
||||||
// KDF1
|
// KDF1
|
||||||
MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET), 32); // h = SHA256(h || bpk)
|
MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD), 32); // h = SHA256(h || bpk)
|
||||||
|
|
||||||
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
|
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
|
||||||
{
|
{
|
||||||
|
@ -256,8 +247,8 @@ namespace garlic
|
||||||
MixHash (m_Aepk, 32); // h = SHA256(h || aepk)
|
MixHash (m_Aepk, 32); // h = SHA256(h || aepk)
|
||||||
|
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, aepk)
|
GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, aepk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
MixKey (sharedSecret);
|
||||||
|
|
||||||
// decrypt flags/static
|
// decrypt flags/static
|
||||||
uint8_t nonce[12], fs[32];
|
uint8_t nonce[12], fs[32];
|
||||||
|
@ -276,8 +267,8 @@ namespace garlic
|
||||||
{
|
{
|
||||||
// static key, fs is apk
|
// static key, fs is apk
|
||||||
memcpy (m_RemoteStaticKey, fs, 32);
|
memcpy (m_RemoteStaticKey, fs, 32);
|
||||||
GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, apk)
|
GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, apk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
MixKey (sharedSecret);
|
||||||
}
|
}
|
||||||
else // all zeros flags
|
else // all zeros flags
|
||||||
CreateNonce (1, nonce);
|
CreateNonce (1, nonce);
|
||||||
|
@ -289,10 +280,13 @@ namespace garlic
|
||||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext)
|
|
||||||
m_State = eSessionStateNewSessionReceived;
|
m_State = eSessionStateNewSessionReceived;
|
||||||
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
|
if (isStatic)
|
||||||
|
{
|
||||||
|
MixHash (buf, len); // h = SHA256(h || ciphertext)
|
||||||
|
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
|
||||||
|
}
|
||||||
HandlePayload (payload.data (), len - 16, nullptr, 0);
|
HandlePayload (payload.data (), len - 16, nullptr, 0);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -452,7 +446,7 @@ namespace garlic
|
||||||
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 ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic)
|
||||||
{
|
{
|
||||||
ResetKeys ();
|
ResetKeys ();
|
||||||
// we are Alice, bpk is m_RemoteStaticKey
|
// we are Alice, bpk is m_RemoteStaticKey
|
||||||
|
@ -469,32 +463,48 @@ namespace garlic
|
||||||
MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk)
|
MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk)
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk)
|
m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
MixKey (sharedSecret);
|
||||||
// encrypt static key section
|
// encrypt flags/static key section
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (0, nonce);
|
CreateNonce (0, nonce);
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
|
const uint8_t * fs;
|
||||||
|
if (isStatic)
|
||||||
|
fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD);
|
||||||
|
else
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed ");
|
memset (out + offset, 0, 32); // all zeros flags section
|
||||||
|
fs = out + offset;
|
||||||
|
}
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed ");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MixHash (out + offset, 48); // h = SHA256(h || ciphertext)
|
MixHash (out + offset, 48); // h = SHA256(h || ciphertext)
|
||||||
offset += 48;
|
offset += 48;
|
||||||
// KDF2
|
// KDF2
|
||||||
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bpk)
|
if (isStatic)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
{
|
||||||
|
GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk)
|
||||||
|
MixKey (sharedSecret);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CreateNonce (1, nonce);
|
||||||
// encrypt payload
|
// encrypt payload
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt
|
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext)
|
|
||||||
|
|
||||||
m_State = eSessionStateNewSessionSent;
|
m_State = eSessionStateNewSessionSent;
|
||||||
if (GetOwner ())
|
if (isStatic)
|
||||||
GenerateMoreReceiveTags (CreateNewSessionTagset (), ECIESX25519_NSR_NUM_GENERATED_TAGS);
|
{
|
||||||
|
MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext)
|
||||||
|
if (GetOwner ())
|
||||||
|
GenerateMoreReceiveTags (CreateNewSessionTagset (), ECIESX25519_NSR_NUM_GENERATED_TAGS);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,9 +530,9 @@ namespace garlic
|
||||||
MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk)
|
MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk)
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
m_EphemeralKeys->Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk)
|
m_EphemeralKeys->Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
|
MixKey (sharedSecret);
|
||||||
m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk)
|
m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
MixKey (sharedSecret);
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (0, nonce);
|
CreateNonce (0, nonce);
|
||||||
// calculate hash for zero length
|
// calculate hash for zero length
|
||||||
|
@ -607,9 +617,9 @@ namespace garlic
|
||||||
{
|
{
|
||||||
// only fist time, we assume ephemeral keys the same
|
// only fist time, we assume ephemeral keys the same
|
||||||
m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk)
|
m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
|
MixKey (sharedSecret);
|
||||||
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk)
|
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk)
|
||||||
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
|
MixKey (sharedSecret);
|
||||||
}
|
}
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
CreateNonce (0, nonce);
|
CreateNonce (0, nonce);
|
||||||
|
@ -784,6 +794,11 @@ namespace garlic
|
||||||
return nullptr;
|
return nullptr;
|
||||||
len += 72;
|
len += 72;
|
||||||
break;
|
break;
|
||||||
|
case eSessionStateOneTime:
|
||||||
|
if (!NewOutgoingSessionMessage (payload.data (), payload.size (), buf, m->maxLen, false))
|
||||||
|
return nullptr;
|
||||||
|
len += 96;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -794,6 +809,12 @@ namespace garlic
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapOneTimeMessage (std::shared_ptr<const I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
m_State = eSessionStateOneTime;
|
||||||
|
return WrapSingleMessage (msg);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first)
|
std::vector<uint8_t> ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first)
|
||||||
{
|
{
|
||||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||||
|
@ -878,7 +899,7 @@ namespace garlic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// msg
|
// msg
|
||||||
if (msg && m_Destination)
|
if (msg)
|
||||||
offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset);
|
offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset);
|
||||||
// ack
|
// ack
|
||||||
if (m_AckRequests.size () > 0)
|
if (m_AckRequests.size () > 0)
|
||||||
|
@ -990,8 +1011,11 @@ namespace garlic
|
||||||
|
|
||||||
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags)
|
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < numTags; i++)
|
if (GetOwner ())
|
||||||
GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset);
|
{
|
||||||
|
for (int i = 0; i < numTags; i++)
|
||||||
|
GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace garlic
|
||||||
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after
|
||||||
const int ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT = 600; // in seconds
|
const int ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT = 600; // in seconds
|
||||||
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
|
const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180
|
||||||
const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 4096; // number of tags we request new tagset after
|
const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after
|
||||||
const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24;
|
const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24;
|
||||||
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 160;
|
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 160;
|
||||||
const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12;
|
const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12;
|
||||||
|
@ -129,7 +129,9 @@ namespace garlic
|
||||||
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
|
const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
|
||||||
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
|
const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04;
|
||||||
|
|
||||||
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
|
class ECIESX25519AEADRatchetSession: public GarlicRoutingSession,
|
||||||
|
private i2p::crypto::NoiseSymmetricState,
|
||||||
|
public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
|
||||||
{
|
{
|
||||||
enum SessionState
|
enum SessionState
|
||||||
{
|
{
|
||||||
|
@ -137,7 +139,8 @@ namespace garlic
|
||||||
eSessionStateNewSessionReceived,
|
eSessionStateNewSessionReceived,
|
||||||
eSessionStateNewSessionSent,
|
eSessionStateNewSessionSent,
|
||||||
eSessionStateNewSessionReplySent,
|
eSessionStateNewSessionReplySent,
|
||||||
eSessionStateEstablished
|
eSessionStateEstablished,
|
||||||
|
eSessionStateOneTime
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DHRatchet
|
struct DHRatchet
|
||||||
|
@ -155,7 +158,8 @@ namespace garlic
|
||||||
|
|
||||||
bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<RatchetTagSet> receiveTagset, int index = 0);
|
bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr<RatchetTagSet> receiveTagset, int index = 0);
|
||||||
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
std::shared_ptr<I2NPMessage> WrapOneTimeMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
|
||||||
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
|
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
|
||||||
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
|
void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); }
|
||||||
|
|
||||||
|
@ -169,12 +173,12 @@ namespace garlic
|
||||||
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
|
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
|
||||||
|
|
||||||
bool IsRatchets () const { return true; };
|
bool IsRatchets () const { return true; };
|
||||||
|
bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; };
|
||||||
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void ResetKeys ();
|
void ResetKeys ();
|
||||||
void MixHash (const uint8_t * buf, size_t len);
|
|
||||||
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
void CreateNonce (uint64_t seqn, uint8_t * nonce);
|
||||||
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes
|
||||||
std::shared_ptr<RatchetTagSet> CreateNewSessionTagset ();
|
std::shared_ptr<RatchetTagSet> CreateNewSessionTagset ();
|
||||||
|
@ -185,7 +189,7 @@ namespace garlic
|
||||||
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset, int index);
|
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset, int index);
|
||||||
void HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset);
|
void HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset);
|
||||||
|
|
||||||
bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic = true);
|
||||||
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||||
bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||||
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen);
|
||||||
|
@ -199,7 +203,7 @@ namespace garlic
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32];
|
uint8_t m_RemoteStaticKey[32];
|
||||||
uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only
|
uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only
|
||||||
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;
|
||||||
|
|
|
@ -46,13 +46,13 @@ namespace fs {
|
||||||
dataDir = cmdline_param;
|
dataDir = cmdline_param;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if defined(WIN32) || defined(_WIN32)
|
#ifdef _WIN32
|
||||||
char localAppData[MAX_PATH];
|
char localAppData[MAX_PATH];
|
||||||
|
|
||||||
// check executable directory first
|
// check executable directory first
|
||||||
if(!GetModuleFileName(NULL, localAppData, MAX_PATH))
|
if(!GetModuleFileName(NULL, localAppData, MAX_PATH))
|
||||||
{
|
{
|
||||||
#if defined(WIN32_APP)
|
#ifdef WIN32_APP
|
||||||
MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
|
MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "Error: Unable to get application path!");
|
fprintf(stderr, "Error: Unable to get application path!");
|
||||||
|
@ -70,7 +70,7 @@ namespace fs {
|
||||||
{
|
{
|
||||||
if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK)
|
if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK)
|
||||||
{
|
{
|
||||||
#if defined(WIN32_APP)
|
#ifdef WIN32_APP
|
||||||
MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
|
MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK);
|
||||||
#else
|
#else
|
||||||
fprintf(stderr, "Error: Unable to get AppData path!");
|
fprintf(stderr, "Error: Unable to get AppData path!");
|
||||||
|
|
|
@ -506,7 +506,7 @@ namespace garlic
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
|
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||||
{
|
{
|
||||||
// try ECIESx25519 tag
|
// try ECIESx25519 tag
|
||||||
uint64_t tag;
|
uint64_t tag;
|
||||||
|
@ -536,7 +536,7 @@ namespace garlic
|
||||||
decryption->Decrypt(buf + 514, length - 514, buf + 514);
|
decryption->Decrypt(buf + 514, length - 514, buf + 514);
|
||||||
HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
|
HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
|
||||||
}
|
}
|
||||||
else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
|
else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||||
{
|
{
|
||||||
// otherwise ECIESx25519
|
// otherwise ECIESx25519
|
||||||
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
|
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
|
||||||
|
@ -709,18 +709,27 @@ namespace garlic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<I2NPMessage> GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
std::shared_ptr<I2NPMessage> GarlicDestination::WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet)
|
std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
auto session = GetRoutingSession (destination, attachLeaseSet);
|
if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||||
return session->WrapSingleMessage (msg);
|
{
|
||||||
|
auto session = std::make_shared<ECIESX25519AEADRatchetSession>(this, false);
|
||||||
|
session->SetRemoteStaticKey (router->GetIdentity ()->GetEncryptionPublicKey ());
|
||||||
|
return session->WrapOneTimeMessage (msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto session = GetRoutingSession (router, false);
|
||||||
|
return session->WrapSingleMessage (msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
||||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
||||||
{
|
{
|
||||||
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET &&
|
if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD &&
|
||||||
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
|
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD))
|
||||||
{
|
{
|
||||||
ECIESX25519AEADRatchetSessionPtr session;
|
ECIESX25519AEADRatchetSessionPtr session;
|
||||||
uint8_t staticKey[32];
|
uint8_t staticKey[32];
|
||||||
|
@ -762,6 +771,7 @@ namespace garlic
|
||||||
}
|
}
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GarlicDestination::CleanupExpiredTags ()
|
void GarlicDestination::CleanupExpiredTags ()
|
||||||
|
|
|
@ -114,6 +114,7 @@ namespace garlic
|
||||||
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession
|
||||||
virtual bool MessageConfirmed (uint32_t msgID);
|
virtual bool MessageConfirmed (uint32_t msgID);
|
||||||
virtual bool IsRatchets () const { return false; };
|
virtual bool IsRatchets () const { return false; };
|
||||||
|
virtual bool IsReadyToSend () const { return true; };
|
||||||
virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only
|
virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only
|
||||||
|
|
||||||
void SetLeaseSetUpdated ()
|
void SetLeaseSetUpdated ()
|
||||||
|
@ -237,8 +238,8 @@ namespace garlic
|
||||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
||||||
void CleanupExpiredTags ();
|
void CleanupExpiredTags ();
|
||||||
void RemoveDeliveryStatusSession (uint32_t msgID);
|
void RemoveDeliveryStatusSession (uint32_t msgID);
|
||||||
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
std::shared_ptr<I2NPMessage> WrapMessageForRouter (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||||
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false);
|
std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
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, const uint8_t * tag); // one tag
|
void AddECIESx25519Key (const uint8_t * key, const uint8_t * tag); // one tag
|
||||||
|
|
|
@ -361,39 +361,82 @@ namespace i2p
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
||||||
BN_CTX * ctx = BN_CTX_new ();
|
BN_CTX * ctx = BN_CTX_new ();
|
||||||
i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
|
bool success = i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
|
||||||
BN_CTX_free (ctx);
|
BN_CTX_free (ctx);
|
||||||
|
if(!success) return false;
|
||||||
|
uint8_t retCode = 0;
|
||||||
|
bool isECIES = i2p::context.IsECIES ();
|
||||||
// replace record to reply
|
// replace record to reply
|
||||||
if (i2p::context.AcceptsTunnels () &&
|
if (i2p::context.AcceptsTunnels () &&
|
||||||
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
|
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
|
||||||
!i2p::transport::transports.IsBandwidthExceeded () &&
|
!i2p::transport::transports.IsBandwidthExceeded () &&
|
||||||
!i2p::transport::transports.IsTransitBandwidthExceeded ())
|
!i2p::transport::transports.IsTransitBandwidthExceeded ())
|
||||||
{
|
{
|
||||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
auto transitTunnel = isECIES ?
|
||||||
|
i2p::tunnel::CreateTransitTunnel (
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||||
|
clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
|
clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||||
|
clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||||
|
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
|
||||||
|
clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) :
|
||||||
|
i2p::tunnel::CreateTransitTunnel (
|
||||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||||
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||||
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
|
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
|
||||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40);
|
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40);
|
||||||
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
|
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
|
||||||
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30)
|
retCode = 30; // always reject with bandwidth reason (30)
|
||||||
|
|
||||||
//TODO: fill filler
|
if (isECIES)
|
||||||
SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret
|
{
|
||||||
record + BUILD_RESPONSE_RECORD_HASH_OFFSET);
|
memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options
|
||||||
|
record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode;
|
||||||
|
SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret
|
||||||
|
record + BUILD_RESPONSE_RECORD_HASH_OFFSET);
|
||||||
|
}
|
||||||
// encrypt reply
|
// encrypt reply
|
||||||
i2p::crypto::CBCEncryption encryption;
|
i2p::crypto::CBCEncryption encryption;
|
||||||
for (int j = 0; j < num; j++)
|
for (int j = 0; j < num; j++)
|
||||||
{
|
{
|
||||||
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
|
||||||
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
|
||||||
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
|
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
|
||||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
if (isECIES)
|
||||||
|
{
|
||||||
|
if (j == i)
|
||||||
|
{
|
||||||
|
uint8_t nonce[12];
|
||||||
|
memset (nonce, 0, 12);
|
||||||
|
auto noiseState = std::move (i2p::context.GetCurrentNoiseState ());
|
||||||
|
if (!noiseState || !i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||||
|
noiseState->m_H, 32, noiseState->m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||||
|
encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||||
|
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||||
|
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||||
|
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -405,7 +448,7 @@ namespace i2p
|
||||||
{
|
{
|
||||||
int num = buf[0];
|
int num = buf[0];
|
||||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
||||||
if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1)
|
if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len);
|
LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len);
|
||||||
return;
|
return;
|
||||||
|
@ -430,28 +473,55 @@ namespace i2p
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
if (i2p::context.IsECIES ())
|
||||||
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
|
||||||
{
|
{
|
||||||
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel
|
uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||||
|
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||||
{
|
{
|
||||||
// so we send it to reply tunnel
|
if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel
|
||||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
{
|
||||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
// so we send it to reply tunnel
|
||||||
eI2NPVariableTunnelBuildReply, buf, len,
|
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
|
eI2NPVariableTunnelBuildReply, buf, len,
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||||
|
bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
|
||||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
|
||||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
|
||||||
|
if (HandleBuildRequestRecords (num, buf + 1, clearText))
|
||||||
|
{
|
||||||
|
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel
|
||||||
|
{
|
||||||
|
// so we send it to reply tunnel
|
||||||
|
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||||
|
eI2NPVariableTunnelBuildReply, buf, len,
|
||||||
|
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||||
|
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||||
|
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
|
void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
if (len < NUM_TUNNEL_BUILD_RECORDS*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE)
|
if (i2p::context.IsECIES ())
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "TunnelBuild is too old for ECIES router");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (len < NUM_TUNNEL_BUILD_RECORDS*TUNNEL_BUILD_RECORD_SIZE)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "TunnelBuild message is too short ", len);
|
LogPrint (eLogError, "TunnelBuild message is too short ", len);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -98,6 +98,7 @@ namespace i2p
|
||||||
const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464;
|
const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464;
|
||||||
|
|
||||||
// ECIES BuildResponseRecord
|
// ECIES BuildResponseRecord
|
||||||
|
const size_t ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET = 0;
|
||||||
const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511;
|
const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511;
|
||||||
|
|
||||||
enum I2NPMessageType
|
enum I2NPMessageType
|
||||||
|
|
|
@ -48,10 +48,10 @@ namespace data
|
||||||
|
|
||||||
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
|
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType)
|
||||||
{
|
{
|
||||||
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||||
{
|
{
|
||||||
memcpy (m_StandardIdentity.publicKey, publicKey, 32);
|
memcpy (m_StandardIdentity.publicKey, publicKey, 32);
|
||||||
RAND_bytes (m_StandardIdentity.publicKey, 224);
|
RAND_bytes (m_StandardIdentity.publicKey + 32, 224);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
memcpy (m_StandardIdentity.publicKey, publicKey, 256);
|
memcpy (m_StandardIdentity.publicKey, publicKey, 256);
|
||||||
|
@ -426,7 +426,7 @@ namespace data
|
||||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||||
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
|
return std::make_shared<i2p::crypto::ElGamalEncryptor>(key);
|
||||||
break;
|
break;
|
||||||
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET:
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD:
|
||||||
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetEncryptor>(key);
|
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetEncryptor>(key);
|
||||||
break;
|
break;
|
||||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
||||||
|
@ -476,7 +476,7 @@ namespace data
|
||||||
|
|
||||||
size_t PrivateKeys::GetFullLen () const
|
size_t PrivateKeys::GetFullLen () const
|
||||||
{
|
{
|
||||||
size_t ret = m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen ();
|
size_t ret = m_Public->GetFullLen () + GetPrivateKeyLen () + m_Public->GetSigningPrivateKeyLen ();
|
||||||
if (IsOfflineSignature ())
|
if (IsOfflineSignature ())
|
||||||
ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen;
|
ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen;
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -486,9 +486,10 @@ namespace data
|
||||||
{
|
{
|
||||||
m_Public = std::make_shared<IdentityEx>();
|
m_Public = std::make_shared<IdentityEx>();
|
||||||
size_t ret = m_Public->FromBuffer (buf, len);
|
size_t ret = m_Public->FromBuffer (buf, len);
|
||||||
if (!ret || ret + 256 > len) return 0; // overflow
|
auto cryptoKeyLen = GetPrivateKeyLen ();
|
||||||
memcpy (m_PrivateKey, buf + ret, 256); // private key always 256
|
if (!ret || ret + cryptoKeyLen > len) return 0; // overflow
|
||||||
ret += 256;
|
memcpy (m_PrivateKey, buf + ret, cryptoKeyLen);
|
||||||
|
ret += cryptoKeyLen;
|
||||||
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
||||||
if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow
|
if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow
|
||||||
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
|
memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize);
|
||||||
|
@ -540,8 +541,9 @@ namespace data
|
||||||
size_t PrivateKeys::ToBuffer (uint8_t * buf, size_t len) const
|
size_t PrivateKeys::ToBuffer (uint8_t * buf, size_t len) const
|
||||||
{
|
{
|
||||||
size_t ret = m_Public->ToBuffer (buf, len);
|
size_t ret = m_Public->ToBuffer (buf, len);
|
||||||
memcpy (buf + ret, m_PrivateKey, 256); // private key always 256
|
auto cryptoKeyLen = GetPrivateKeyLen ();
|
||||||
ret += 256;
|
memcpy (buf + ret, m_PrivateKey, cryptoKeyLen);
|
||||||
|
ret += cryptoKeyLen;
|
||||||
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen ();
|
||||||
if(ret + signingPrivateKeySize > len) return 0; // overflow
|
if(ret + signingPrivateKeySize > len) return 0; // overflow
|
||||||
if (IsOfflineSignature ())
|
if (IsOfflineSignature ())
|
||||||
|
@ -657,6 +659,12 @@ namespace data
|
||||||
return IsOfflineSignature () ? m_TransientSignatureLen : m_Public->GetSignatureLen ();
|
return IsOfflineSignature () ? m_TransientSignatureLen : m_Public->GetSignatureLen ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t PrivateKeys::GetPrivateKeyLen () const
|
||||||
|
{
|
||||||
|
// private key length always 256, but type 4
|
||||||
|
return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t * PrivateKeys::GetPadding()
|
uint8_t * PrivateKeys::GetPadding()
|
||||||
{
|
{
|
||||||
if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
|
if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519)
|
||||||
|
@ -679,6 +687,9 @@ namespace data
|
||||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||||
return std::make_shared<i2p::crypto::ElGamalDecryptor>(key);
|
return std::make_shared<i2p::crypto::ElGamalDecryptor>(key);
|
||||||
break;
|
break;
|
||||||
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD:
|
||||||
|
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
|
||||||
|
break;
|
||||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC:
|
||||||
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
|
case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST:
|
||||||
return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key);
|
return std::make_shared<i2p::crypto::ECIESP256Decryptor>(key);
|
||||||
|
@ -686,9 +697,6 @@ namespace data
|
||||||
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
||||||
return std::make_shared<i2p::crypto::ECIESGOSTR3410Decryptor>(key);
|
return std::make_shared<i2p::crypto::ECIESGOSTR3410Decryptor>(key);
|
||||||
break;
|
break;
|
||||||
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET:
|
|
||||||
return std::make_shared<i2p::crypto::ECIESX25519AEADRatchetDecryptor>(key);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
|
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
|
||||||
};
|
};
|
||||||
|
@ -768,7 +776,7 @@ namespace data
|
||||||
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC:
|
||||||
i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub);
|
i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub);
|
||||||
break;
|
break;
|
||||||
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET:
|
case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD:
|
||||||
i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub);
|
i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -820,7 +828,7 @@ namespace data
|
||||||
XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
|
XORMetric operator^(const IdentHash& key1, const IdentHash& key2)
|
||||||
{
|
{
|
||||||
XORMetric m;
|
XORMetric m;
|
||||||
#ifdef __AVX__
|
#if defined(__x86_64__) || defined(__i386__)
|
||||||
if(i2p::cpu::avx)
|
if(i2p::cpu::avx)
|
||||||
{
|
{
|
||||||
__asm__
|
__asm__
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace data
|
||||||
|
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0;
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1;
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET = 4;
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD = 4;
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later
|
||||||
const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES
|
const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES
|
||||||
|
|
||||||
|
@ -183,6 +183,7 @@ namespace data
|
||||||
|
|
||||||
void CreateSigner () const;
|
void CreateSigner () const;
|
||||||
void CreateSigner (SigningKeyType keyType) const;
|
void CreateSigner (SigningKeyType keyType) const;
|
||||||
|
size_t GetPrivateKeyLen () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -39,21 +39,6 @@ namespace transport
|
||||||
delete[] m_SessionConfirmedBuffer;
|
delete[] m_SessionConfirmedBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial)
|
|
||||||
{
|
|
||||||
i2p::crypto::HKDF (m_CK, inputKeyMaterial, 32, "", m_CK);
|
|
||||||
// ck is m_CK[0:31], k is m_CK[32:63]
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTCP2Establisher::MixHash (const uint8_t * buf, size_t len)
|
|
||||||
{
|
|
||||||
SHA256_CTX ctx;
|
|
||||||
SHA256_Init (&ctx);
|
|
||||||
SHA256_Update (&ctx, m_H, 32);
|
|
||||||
SHA256_Update (&ctx, buf, len);
|
|
||||||
SHA256_Final (m_H, &ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub)
|
void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub)
|
||||||
{
|
{
|
||||||
static const uint8_t protocolNameHash[] =
|
static const uint8_t protocolNameHash[] =
|
||||||
|
@ -757,6 +742,10 @@ namespace transport
|
||||||
void NTCP2Session::ReceiveLength ()
|
void NTCP2Session::ReceiveLength ()
|
||||||
{
|
{
|
||||||
if (IsTerminated ()) return;
|
if (IsTerminated ()) return;
|
||||||
|
#ifdef __linux__
|
||||||
|
const int one = 1;
|
||||||
|
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
|
||||||
|
#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));
|
||||||
}
|
}
|
||||||
|
@ -808,6 +797,10 @@ namespace transport
|
||||||
void NTCP2Session::Receive ()
|
void NTCP2Session::Receive ()
|
||||||
{
|
{
|
||||||
if (IsTerminated ()) return;
|
if (IsTerminated ()) return;
|
||||||
|
#ifdef __linux__
|
||||||
|
const int one = 1;
|
||||||
|
setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
|
||||||
|
#endif
|
||||||
boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (),
|
boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (),
|
||||||
std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace transport
|
||||||
// RouterInfo flags
|
// RouterInfo flags
|
||||||
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
|
||||||
|
|
||||||
struct NTCP2Establisher
|
struct NTCP2Establisher: private i2p::crypto::NoiseSymmetricState
|
||||||
{
|
{
|
||||||
NTCP2Establisher ();
|
NTCP2Establisher ();
|
||||||
~NTCP2Establisher ();
|
~NTCP2Establisher ();
|
||||||
|
@ -94,8 +94,6 @@ namespace transport
|
||||||
void KDF3Alice (); // for SessionConfirmed part 2
|
void KDF3Alice (); // for SessionConfirmed part 2
|
||||||
void KDF3Bob ();
|
void KDF3Bob ();
|
||||||
|
|
||||||
void MixKey (const uint8_t * inputKeyMaterial);
|
|
||||||
void MixHash (const uint8_t * buf, size_t len);
|
|
||||||
void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
|
void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
|
||||||
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
|
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
|
||||||
void CreateEphemeralKey ();
|
void CreateEphemeralKey ();
|
||||||
|
@ -112,7 +110,7 @@ namespace transport
|
||||||
|
|
||||||
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
|
||||||
uint8_t m_RemoteEphemeralPublicKey[32]; // x25519
|
uint8_t m_RemoteEphemeralPublicKey[32]; // x25519
|
||||||
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[64] /* [ck, k]*/;
|
uint8_t m_RemoteStaticKey[32], m_IV[16];
|
||||||
i2p::data::IdentHash m_RemoteIdentHash;
|
i2p::data::IdentHash m_RemoteIdentHash;
|
||||||
uint16_t m3p2Len;
|
uint16_t m3p2Len;
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,9 @@ namespace data
|
||||||
case eI2NPDatabaseLookup:
|
case eI2NPDatabaseLookup:
|
||||||
HandleDatabaseLookupMsg (msg);
|
HandleDatabaseLookupMsg (msg);
|
||||||
break;
|
break;
|
||||||
|
case eI2NPDeliveryStatus:
|
||||||
|
HandleDeliveryStatusMsg (msg);
|
||||||
|
break;
|
||||||
case eI2NPDummyMsg:
|
case eI2NPDummyMsg:
|
||||||
// plain RouterInfo from NTCP2 with flags for now
|
// plain RouterInfo from NTCP2 with flags for now
|
||||||
HandleNTCP2RouterInfoMsg (msg);
|
HandleNTCP2RouterInfoMsg (msg);
|
||||||
|
@ -148,11 +151,22 @@ namespace data
|
||||||
lastDestinationCleanup = ts;
|
lastDestinationCleanup = ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL) // update timestamp and publish
|
// publish
|
||||||
|
if (!m_HiddenMode && i2p::transport::transports.IsOnline ())
|
||||||
{
|
{
|
||||||
i2p::context.UpdateTimestamp (ts);
|
bool publish = false;
|
||||||
if (!m_HiddenMode) Publish ();
|
if (m_PublishReplyToken)
|
||||||
lastPublish = ts;
|
{
|
||||||
|
if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true;
|
||||||
|
}
|
||||||
|
else if (i2p::context.GetLastUpdateTime () > lastPublish ||
|
||||||
|
ts - lastPublish >= NETDB_PUBLISH_INTERVAL) publish = true;
|
||||||
|
if (publish) // update timestamp and publish
|
||||||
|
{
|
||||||
|
i2p::context.UpdateTimestamp (ts);
|
||||||
|
Publish ();
|
||||||
|
lastPublish = ts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
|
if (ts - lastExploratory >= 30) // exploratory every 30 seconds
|
||||||
{
|
{
|
||||||
|
@ -226,7 +240,7 @@ namespace data
|
||||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||||
if (wasFloodfill)
|
if (wasFloodfill)
|
||||||
m_Floodfills.remove (r);
|
m_Floodfills.remove (r);
|
||||||
else
|
else if (r->IsEligibleFloodfill ())
|
||||||
m_Floodfills.push_back (r);
|
m_Floodfills.push_back (r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,7 +263,7 @@ namespace data
|
||||||
if (inserted)
|
if (inserted)
|
||||||
{
|
{
|
||||||
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64());
|
||||||
if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable
|
if (r->IsFloodfill () && r->IsEligibleFloodfill ())
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
std::unique_lock<std::mutex> l(m_FloodfillsMutex);
|
||||||
m_Floodfills.push_back (r);
|
m_Floodfills.push_back (r);
|
||||||
|
@ -992,6 +1006,16 @@ namespace data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetDb::HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg)
|
||||||
|
{
|
||||||
|
if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
|
||||||
|
{
|
||||||
|
LogPrint (eLogInfo, "NetDb: Publishing confirmed. reply token=", m_PublishReplyToken);
|
||||||
|
m_PublishExcluded.clear ();
|
||||||
|
m_PublishReplyToken = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NetDb::Explore (int numDestinations)
|
void NetDb::Explore (int numDestinations)
|
||||||
{
|
{
|
||||||
// new requests
|
// new requests
|
||||||
|
@ -1045,18 +1069,22 @@ namespace data
|
||||||
void NetDb::Publish ()
|
void NetDb::Publish ()
|
||||||
{
|
{
|
||||||
i2p::context.UpdateStats (); // for floodfill
|
i2p::context.UpdateStats (); // for floodfill
|
||||||
std::set<IdentHash> excluded; // TODO: fill up later
|
|
||||||
for (int i = 0; i < 2; i++)
|
if (m_PublishExcluded.size () > NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS)
|
||||||
{
|
{
|
||||||
auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded);
|
LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again");
|
||||||
if (floodfill)
|
m_PublishExcluded.clear ();
|
||||||
{
|
}
|
||||||
uint32_t replyToken;
|
|
||||||
RAND_bytes ((uint8_t *)&replyToken, 4);
|
auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded);
|
||||||
LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
if (floodfill)
|
||||||
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
{
|
||||||
excluded.insert (floodfill->GetIdentHash ());
|
uint32_t replyToken;
|
||||||
}
|
RAND_bytes ((uint8_t *)&replyToken, 4);
|
||||||
|
LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken);
|
||||||
|
m_PublishExcluded.insert (floodfill->GetIdentHash ());
|
||||||
|
m_PublishReplyToken = replyToken;
|
||||||
|
transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,10 @@ namespace data
|
||||||
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_PUBLISH_INTERVAL = 60 * 40;
|
const int NETDB_PUBLISH_INTERVAL = 60 * 40;
|
||||||
|
const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds
|
||||||
|
const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15;
|
||||||
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
|
const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36
|
||||||
|
const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 28); // 0.9.28
|
||||||
|
|
||||||
/** function for visiting a leaseset stored in a floodfill */
|
/** function for visiting a leaseset stored in a floodfill */
|
||||||
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
|
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
|
||||||
|
@ -77,6 +80,7 @@ namespace data
|
||||||
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
|
||||||
|
void HandleDeliveryStatusMsg (std::shared_ptr<const I2NPMessage> msg);
|
||||||
|
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter () const;
|
||||||
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
|
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
|
||||||
|
@ -115,6 +119,8 @@ namespace data
|
||||||
|
|
||||||
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
void ClearRouterInfos () { m_RouterInfos.clear (); };
|
||||||
|
|
||||||
|
uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void Load ();
|
void Load ();
|
||||||
|
@ -162,9 +168,11 @@ namespace data
|
||||||
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
||||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
||||||
|
|
||||||
|
|
||||||
/** true if in hidden mode */
|
/** true if in hidden mode */
|
||||||
bool m_HiddenMode;
|
bool m_HiddenMode;
|
||||||
|
|
||||||
|
std::set<IdentHash> m_PublishExcluded;
|
||||||
|
uint32_t m_PublishReplyToken = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NetDb netdb;
|
extern NetDb netdb;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Family.h"
|
#include "Family.h"
|
||||||
|
#include "TunnelConfig.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
|
@ -41,6 +42,13 @@ namespace i2p
|
||||||
CreateNewRouter ();
|
CreateNewRouter ();
|
||||||
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
||||||
UpdateRouterInfo ();
|
UpdateRouterInfo ();
|
||||||
|
if (IsECIES ())
|
||||||
|
{
|
||||||
|
auto initState = new i2p::crypto::NoiseSymmetricState ();
|
||||||
|
i2p::tunnel::InitBuildRequestRecordNoiseState (*initState);
|
||||||
|
initState->MixHash (GetIdentity ()->GetEncryptionPublicKey (), 32); // h = SHA256(h || hepk)
|
||||||
|
m_InitialNoiseState.reset (initState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::CreateNewRouter ()
|
void RouterContext::CreateNewRouter ()
|
||||||
|
@ -81,7 +89,7 @@ namespace i2p
|
||||||
host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string();
|
host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string();
|
||||||
|
|
||||||
if (ssu)
|
if (ssu)
|
||||||
routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
|
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
||||||
}
|
}
|
||||||
if (ipv6)
|
if (ipv6)
|
||||||
{
|
{
|
||||||
|
@ -95,7 +103,7 @@ namespace i2p
|
||||||
host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string();
|
host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string();
|
||||||
|
|
||||||
if (ssu)
|
if (ssu)
|
||||||
routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ());
|
routerInfo.AddSSUAddress (host.c_str(), port, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
routerInfo.SetCaps (i2p::data::RouterInfo::eReachable |
|
||||||
|
@ -478,7 +486,7 @@ namespace i2p
|
||||||
if (ssu)
|
if (ssu)
|
||||||
{
|
{
|
||||||
std::string host = "::1"; // TODO: read host
|
std::string host = "::1"; // TODO: read host
|
||||||
m_RouterInfo.AddSSUAddress (host.c_str (), port, GetIdentHash ());
|
m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// NTCP2
|
// NTCP2
|
||||||
|
@ -556,31 +564,42 @@ namespace i2p
|
||||||
|
|
||||||
bool RouterContext::Load ()
|
bool RouterContext::Load ()
|
||||||
{
|
{
|
||||||
std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary);
|
{
|
||||||
if (!fk.is_open ()) return false;
|
std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary);
|
||||||
fk.seekg (0, std::ios::end);
|
if (!fk.is_open ()) return false;
|
||||||
size_t len = fk.tellg();
|
fk.seekg (0, std::ios::end);
|
||||||
fk.seekg (0, std::ios::beg);
|
size_t len = fk.tellg();
|
||||||
|
fk.seekg (0, std::ios::beg);
|
||||||
|
|
||||||
if (len == sizeof (i2p::data::Keys)) // old keys file format
|
if (len == sizeof (i2p::data::Keys)) // old keys file format
|
||||||
{
|
{
|
||||||
i2p::data::Keys keys;
|
i2p::data::Keys keys;
|
||||||
fk.read ((char *)&keys, sizeof (keys));
|
fk.read ((char *)&keys, sizeof (keys));
|
||||||
m_Keys = keys;
|
m_Keys = keys;
|
||||||
|
}
|
||||||
|
else // new keys file format
|
||||||
|
{
|
||||||
|
uint8_t * buf = new uint8_t[len];
|
||||||
|
fk.read ((char *)buf, len);
|
||||||
|
m_Keys.FromBuffer (buf, len);
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else // new keys file format
|
std::shared_ptr<const i2p::data::IdentityEx> oldIdentity;
|
||||||
|
if (m_Keys.GetPublic ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
|
||||||
{
|
{
|
||||||
uint8_t * buf = new uint8_t[len];
|
// update keys
|
||||||
fk.read ((char *)buf, len);
|
LogPrint (eLogInfo, "Router: router keys are obsolete. Creating new");
|
||||||
m_Keys.FromBuffer (buf, len);
|
oldIdentity = m_Keys.GetPublic ();
|
||||||
delete[] buf;
|
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
|
||||||
}
|
SaveKeys ();
|
||||||
|
}
|
||||||
// read NTCP2 keys if available
|
// read NTCP2 keys if available
|
||||||
std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary);
|
std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary);
|
||||||
if (n2k)
|
if (n2k)
|
||||||
{
|
{
|
||||||
n2k.seekg (0, std::ios::end);
|
n2k.seekg (0, std::ios::end);
|
||||||
len = n2k.tellg();
|
size_t len = n2k.tellg();
|
||||||
n2k.seekg (0, std::ios::beg);
|
n2k.seekg (0, std::ios::beg);
|
||||||
if (len == sizeof (NTCP2PrivateKeys))
|
if (len == sizeof (NTCP2PrivateKeys))
|
||||||
{
|
{
|
||||||
|
@ -590,17 +609,15 @@ namespace i2p
|
||||||
n2k.close ();
|
n2k.close ();
|
||||||
}
|
}
|
||||||
// read RouterInfo
|
// read RouterInfo
|
||||||
m_RouterInfo.SetRouterIdentity (GetIdentity ());
|
m_RouterInfo.SetRouterIdentity (oldIdentity ? oldIdentity : GetIdentity ());
|
||||||
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO));
|
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO));
|
||||||
if (!routerInfo.IsUnreachable ()) // router.info looks good
|
if (!routerInfo.IsUnreachable ()) // router.info looks good
|
||||||
{
|
{
|
||||||
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ());
|
||||||
|
if (oldIdentity)
|
||||||
|
m_RouterInfo.SetRouterIdentity (GetIdentity ()); // from new keys
|
||||||
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
|
m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION);
|
||||||
m_RouterInfo.SetProperty ("router.version", I2P_VERSION);
|
m_RouterInfo.SetProperty ("router.version", I2P_VERSION);
|
||||||
|
|
||||||
// Migration to 0.9.24. TODO: remove later
|
|
||||||
m_RouterInfo.DeleteProperty ("coreVersion");
|
|
||||||
m_RouterInfo.DeleteProperty ("stat_uptime");
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -645,6 +662,15 @@ namespace i2p
|
||||||
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
|
i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len)
|
||||||
|
{
|
||||||
|
auto msg = CreateI2NPMessage (typeID, payload, len);
|
||||||
|
if (!msg) return false;
|
||||||
|
i2p::HandleI2NPMessage (msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
void RouterContext::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||||
|
@ -653,8 +679,13 @@ namespace i2p
|
||||||
|
|
||||||
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET))
|
||||||
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
i2p::data::netdb.PostI2NPMsg (msg);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(m_GarlicMutex);
|
||||||
|
i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RouterContext::CleanupDestination ()
|
void RouterContext::CleanupDestination ()
|
||||||
|
@ -673,9 +704,32 @@ namespace i2p
|
||||||
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
|
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const
|
bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx)
|
||||||
{
|
{
|
||||||
return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, false) : false;
|
if (!m_Decryptor) return false;
|
||||||
|
if (IsECIES ())
|
||||||
|
{
|
||||||
|
if (!m_InitialNoiseState) return false;
|
||||||
|
// m_InitialNoiseState is h = SHA256(h || hepk)
|
||||||
|
m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState));
|
||||||
|
m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk)
|
||||||
|
uint8_t sharedSecret[32];
|
||||||
|
m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false);
|
||||||
|
m_CurrentNoiseState->MixKey (sharedSecret);
|
||||||
|
encrypted += 32;
|
||||||
|
uint8_t nonce[12];
|
||||||
|
memset (nonce, 0, 12);
|
||||||
|
if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE,
|
||||||
|
m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK + 32, nonce, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, false)) // decrypt
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_CurrentNoiseState->MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return m_Decryptor->Decrypt (encrypted, data, ctx, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()
|
i2p::crypto::X25519Keys& RouterContext::GetStaticKeys ()
|
||||||
|
|
|
@ -84,7 +84,7 @@ namespace i2p
|
||||||
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
|
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
|
||||||
int GetNetID () const { return m_NetID; };
|
int GetNetID () const { return m_NetID; };
|
||||||
void SetNetID (int netID) { m_NetID = netID; };
|
void SetNetID (int netID) { m_NetID = netID; };
|
||||||
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
|
bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
|
||||||
|
|
||||||
void UpdatePort (int port); // called from Daemon
|
void UpdatePort (int port); // called from Daemon
|
||||||
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||||
|
@ -109,7 +109,9 @@ namespace i2p
|
||||||
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
|
bool SupportsV4 () const { return m_RouterInfo.IsV4 (); };
|
||||||
void SetSupportsV6 (bool supportsV6);
|
void SetSupportsV6 (bool supportsV6);
|
||||||
void SetSupportsV4 (bool supportsV4);
|
void SetSupportsV4 (bool supportsV4);
|
||||||
|
bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||||
|
std::unique_ptr<i2p::crypto::NoiseSymmetricState>& GetCurrentNoiseState () { return m_CurrentNoiseState; };
|
||||||
|
|
||||||
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove
|
||||||
void UpdateStats ();
|
void UpdateStats ();
|
||||||
void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing
|
void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing
|
||||||
|
@ -133,7 +135,7 @@ namespace i2p
|
||||||
|
|
||||||
// implements GarlicDestination
|
// implements GarlicDestination
|
||||||
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
void HandleI2NPMessage (const uint8_t * buf, size_t len);
|
||||||
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented
|
bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -160,6 +162,8 @@ namespace i2p
|
||||||
std::mutex m_GarlicMutex;
|
std::mutex m_GarlicMutex;
|
||||||
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
std::unique_ptr<NTCP2PrivateKeys> m_NTCP2Keys;
|
||||||
std::unique_ptr<i2p::crypto::X25519Keys> m_StaticKeys;
|
std::unique_ptr<i2p::crypto::X25519Keys> m_StaticKeys;
|
||||||
|
// for ECIESx25519
|
||||||
|
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_InitialNoiseState, m_CurrentNoiseState;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern RouterContext context;
|
extern RouterContext context;
|
||||||
|
|
|
@ -719,7 +719,10 @@ namespace data
|
||||||
addr->date = 0;
|
addr->date = 0;
|
||||||
addr->ssu.reset (new SSUExt ());
|
addr->ssu.reset (new SSUExt ());
|
||||||
addr->ssu->mtu = mtu;
|
addr->ssu->mtu = mtu;
|
||||||
memcpy (addr->ssu->key, key, 32);
|
if (key)
|
||||||
|
memcpy (addr->ssu->key, key, 32);
|
||||||
|
else
|
||||||
|
RAND_bytes (addr->ssu->key, 32);
|
||||||
for (const auto& it: *m_Addresses) // don't insert same address twice
|
for (const auto& it: *m_Addresses) // don't insert same address twice
|
||||||
if (*it == *addr) return;
|
if (*it == *addr) return;
|
||||||
m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
|
m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4;
|
||||||
|
@ -945,5 +948,12 @@ namespace data
|
||||||
if (encryptor)
|
if (encryptor)
|
||||||
encryptor->Encrypt (data, encrypted, ctx, true);
|
encryptor->Encrypt (data, encrypted, ctx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RouterInfo::IsEligibleFloodfill () const
|
||||||
|
{
|
||||||
|
// floodfill must be reachable, >= 0.9.28 and not DSA
|
||||||
|
return IsReachable () && m_Version >= NETDB_MIN_FLOODFILL_VERSION &&
|
||||||
|
GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,7 +184,8 @@ namespace data
|
||||||
bool IsHidden () const { return m_Caps & eHidden; };
|
bool IsHidden () const { return m_Caps & eHidden; };
|
||||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||||
|
bool IsEligibleFloodfill () const;
|
||||||
|
|
||||||
uint8_t GetCaps () const { return m_Caps; };
|
uint8_t GetCaps () const { return m_Caps; };
|
||||||
void SetCaps (uint8_t caps);
|
void SetCaps (uint8_t caps);
|
||||||
void SetCaps (const char * caps);
|
void SetCaps (const char * caps);
|
||||||
|
|
|
@ -13,6 +13,10 @@
|
||||||
#include "NetDb.hpp"
|
#include "NetDb.hpp"
|
||||||
#include "SSU.h"
|
#include "SSU.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <boost/winapi/error_codes.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace transport
|
namespace transport
|
||||||
|
@ -247,11 +251,17 @@ namespace transport
|
||||||
|
|
||||||
void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
|
void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
|
||||||
{
|
{
|
||||||
if (!ecode ||
|
if (!ecode
|
||||||
ecode == boost::asio::error::connection_refused ||
|
|| ecode == boost::asio::error::connection_refused
|
||||||
ecode == boost::asio::error::connection_reset ||
|
|| ecode == boost::asio::error::connection_reset
|
||||||
ecode == boost::asio::error::network_unreachable ||
|
|| ecode == boost::asio::error::network_unreachable
|
||||||
ecode == boost::asio::error::host_unreachable)
|
|| ecode == boost::asio::error::host_unreachable
|
||||||
|
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|
||||||
|
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|
||||||
|
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|
||||||
|
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|
||||||
|
#endif
|
||||||
|
)
|
||||||
// just try continue reading when received ICMP response otherwise socket can crash,
|
// just try continue reading when received ICMP response otherwise socket can crash,
|
||||||
// but better to find out which host were sent it and mark that router as unreachable
|
// but better to find out which host were sent it and mark that router as unreachable
|
||||||
{
|
{
|
||||||
|
@ -300,11 +310,17 @@ namespace transport
|
||||||
|
|
||||||
void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
|
void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
|
||||||
{
|
{
|
||||||
if (!ecode ||
|
if (!ecode
|
||||||
ecode == boost::asio::error::connection_refused ||
|
|| ecode == boost::asio::error::connection_refused
|
||||||
ecode == boost::asio::error::connection_reset ||
|
|| ecode == boost::asio::error::connection_reset
|
||||||
ecode == boost::asio::error::network_unreachable ||
|
|| ecode == boost::asio::error::network_unreachable
|
||||||
ecode == boost::asio::error::host_unreachable)
|
|| ecode == boost::asio::error::host_unreachable
|
||||||
|
#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO
|
||||||
|
|| ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_
|
||||||
|
|| ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_
|
||||||
|
|| ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_
|
||||||
|
#endif
|
||||||
|
)
|
||||||
// just try continue reading when received ICMP response otherwise socket can crash,
|
// just try continue reading when received ICMP response otherwise socket can crash,
|
||||||
// but better to find out which host were sent it and mark that router as unreachable
|
// but better to find out which host were sent it and mark that router as unreachable
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,14 +30,15 @@ namespace transport
|
||||||
if (router)
|
if (router)
|
||||||
{
|
{
|
||||||
// we are client
|
// we are client
|
||||||
auto address = router->GetSSUAddress (false);
|
auto address = IsV6 () ? router->GetSSUV6Address () : router->GetSSUAddress (true);
|
||||||
if (address) m_IntroKey = address->ssu->key;
|
if (address) m_IntroKey = address->ssu->key;
|
||||||
m_Data.AdjustPacketSize (router); // mtu
|
m_Data.AdjustPacketSize (router); // mtu
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// we are server
|
// we are server
|
||||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
|
auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () :
|
||||||
|
i2p::context.GetRouterInfo ().GetSSUAddress (true);
|
||||||
if (address) m_IntroKey = address->ssu->key;
|
if (address) m_IntroKey = address->ssu->key;
|
||||||
}
|
}
|
||||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||||
|
|
|
@ -21,10 +21,18 @@ namespace stream
|
||||||
{
|
{
|
||||||
void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler)
|
void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler)
|
||||||
{
|
{
|
||||||
m_Buffers.push_back (std::make_shared<SendBuffer>(buf, len, handler));
|
Add (std::make_shared<SendBuffer>(buf, len, handler));
|
||||||
m_Size += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendBufferQueue::Add (std::shared_ptr<SendBuffer> buf)
|
||||||
|
{
|
||||||
|
if (buf)
|
||||||
|
{
|
||||||
|
m_Buffers.push_back (buf);
|
||||||
|
m_Size += buf->len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t SendBufferQueue::Get (uint8_t * buf, size_t len)
|
size_t SendBufferQueue::Get (uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
@ -325,7 +333,7 @@ namespace stream
|
||||||
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
if (flags & PACKET_FLAG_SIGNATURE_INCLUDED)
|
||||||
{
|
{
|
||||||
uint8_t signature[256];
|
uint8_t signature[256];
|
||||||
auto signatureLen = m_RemoteIdentity->GetSignatureLen ();
|
auto signatureLen = m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : m_RemoteIdentity->GetSignatureLen ();
|
||||||
if(signatureLen <= sizeof(signature))
|
if(signatureLen <= sizeof(signature))
|
||||||
{
|
{
|
||||||
memcpy (signature, optionData, signatureLen);
|
memcpy (signature, optionData, signatureLen);
|
||||||
|
@ -756,7 +764,7 @@ namespace stream
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_RoutingSession || !m_RoutingSession->GetOwner ()) // expired and detached
|
if (!m_RoutingSession || !m_RoutingSession->GetOwner () || !m_RoutingSession->IsReadyToSend ()) // expired and detached or new session sent
|
||||||
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
|
m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true);
|
||||||
if (!m_CurrentOutboundTunnel && m_RoutingSession) // first message to send
|
if (!m_CurrentOutboundTunnel && m_RoutingSession) // first message to send
|
||||||
{
|
{
|
||||||
|
|
|
@ -111,6 +111,11 @@ namespace stream
|
||||||
buf = new uint8_t[len];
|
buf = new uint8_t[len];
|
||||||
memcpy (buf, b, len);
|
memcpy (buf, b, len);
|
||||||
}
|
}
|
||||||
|
SendBuffer (size_t l): // creat empty buffer
|
||||||
|
len(l), offset (0)
|
||||||
|
{
|
||||||
|
buf = new uint8_t[len];
|
||||||
|
}
|
||||||
~SendBuffer ()
|
~SendBuffer ()
|
||||||
{
|
{
|
||||||
delete[] buf;
|
delete[] buf;
|
||||||
|
@ -129,6 +134,7 @@ namespace stream
|
||||||
~SendBufferQueue () { CleanUp (); };
|
~SendBufferQueue () { CleanUp (); };
|
||||||
|
|
||||||
void Add (const uint8_t * buf, size_t len, SendHandler handler);
|
void Add (const uint8_t * buf, size_t len, SendHandler handler);
|
||||||
|
void Add (std::shared_ptr<SendBuffer> buf);
|
||||||
size_t Get (uint8_t * buf, size_t len);
|
size_t Get (uint8_t * buf, size_t len);
|
||||||
size_t GetSize () const { return m_Size; };
|
size_t GetSize () const { return m_Size; };
|
||||||
bool IsEmpty () const { return m_Buffers.empty (); };
|
bool IsEmpty () const { return m_Buffers.empty (); };
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "I2PEndian.h"
|
#include "I2PEndian.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
#ifndef _WIN64
|
#ifndef _WIN64
|
||||||
#define _USE_32BIT_TIME_T
|
#define _USE_32BIT_TIME_T
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -124,7 +124,7 @@ namespace tunnel
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
memset (nonce, 0, 12);
|
memset (nonce, 0, 12);
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (record, TUNNEL_BUILD_RECORD_SIZE - 16,
|
if (!i2p::crypto::AEADChaCha20Poly1305 (record, TUNNEL_BUILD_RECORD_SIZE - 16,
|
||||||
hop->h, 32, hop->ck, nonce, record, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt
|
hop->m_H, 32, hop->m_CK, nonce, record, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed");
|
LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed");
|
||||||
return false;
|
return false;
|
||||||
|
@ -474,7 +474,7 @@ namespace tunnel
|
||||||
{
|
{
|
||||||
std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready
|
std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready
|
||||||
|
|
||||||
uint64_t lastTs = 0;
|
uint64_t lastTs = 0, lastPoolsTs = 0;
|
||||||
while (m_IsRunning)
|
while (m_IsRunning)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -535,12 +535,20 @@ namespace tunnel
|
||||||
while (msg);
|
while (msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
if (i2p::transport::transports.IsOnline())
|
||||||
if (ts - lastTs >= 15 && i2p::transport::transports.IsOnline()) // manage tunnels every 15 seconds
|
|
||||||
{
|
{
|
||||||
ManageTunnels ();
|
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||||
lastTs = ts;
|
if (ts - lastTs >= 15) // manage tunnels every 15 seconds
|
||||||
}
|
{
|
||||||
|
ManageTunnels ();
|
||||||
|
lastTs = ts;
|
||||||
|
}
|
||||||
|
if (ts - lastPoolsTs >= 5) // manage pools every 5 seconds
|
||||||
|
{
|
||||||
|
ManageTunnelPools (ts);
|
||||||
|
lastPoolsTs = ts;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (std::exception& ex)
|
catch (std::exception& ex)
|
||||||
{
|
{
|
||||||
|
@ -582,7 +590,6 @@ namespace tunnel
|
||||||
ManageInboundTunnels ();
|
ManageInboundTunnels ();
|
||||||
ManageOutboundTunnels ();
|
ManageOutboundTunnels ();
|
||||||
ManageTransitTunnels ();
|
ManageTransitTunnels ();
|
||||||
ManageTunnelPools ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnels::ManagePendingTunnels ()
|
void Tunnels::ManagePendingTunnels ()
|
||||||
|
@ -794,16 +801,13 @@ namespace tunnel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Tunnels::ManageTunnelPools ()
|
void Tunnels::ManageTunnelPools (uint64_t ts)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> l(m_PoolsMutex);
|
std::unique_lock<std::mutex> l(m_PoolsMutex);
|
||||||
for (auto& pool : m_Pools)
|
for (auto& pool : m_Pools)
|
||||||
{
|
{
|
||||||
if (pool && pool->IsActive ())
|
if (pool && pool->IsActive ())
|
||||||
{
|
pool->ManageTunnels (ts);
|
||||||
pool->CreateTunnels ();
|
|
||||||
pool->TestTunnels ();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,7 +230,7 @@ namespace tunnel
|
||||||
void ManagePendingTunnels ();
|
void ManagePendingTunnels ();
|
||||||
template<class PendingTunnels>
|
template<class PendingTunnels>
|
||||||
void ManagePendingTunnels (PendingTunnels& pendingTunnels);
|
void ManagePendingTunnels (PendingTunnels& pendingTunnels);
|
||||||
void ManageTunnelPools ();
|
void ManageTunnelPools (uint64_t ts);
|
||||||
|
|
||||||
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel ();
|
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel ();
|
||||||
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel ();
|
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel ();
|
||||||
|
@ -249,7 +249,7 @@ namespace tunnel
|
||||||
std::list<std::shared_ptr<TunnelPool>> m_Pools;
|
std::list<std::shared_ptr<TunnelPool>> m_Pools;
|
||||||
std::shared_ptr<TunnelPool> m_ExploratoryPool;
|
std::shared_ptr<TunnelPool> m_ExploratoryPool;
|
||||||
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
|
i2p::util::Queue<std::shared_ptr<I2NPMessage> > m_Queue;
|
||||||
|
|
||||||
// some stats
|
// some stats
|
||||||
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;
|
int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include "Crypto.h"
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "Transports.h"
|
#include "Transports.h"
|
||||||
#include "Timestamp.h"
|
#include "Timestamp.h"
|
||||||
|
@ -128,9 +127,7 @@ namespace tunnel
|
||||||
void TunnelHopConfig::EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor,
|
void TunnelHopConfig::EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor,
|
||||||
const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx)
|
const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx)
|
||||||
{
|
{
|
||||||
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
|
InitBuildRequestRecordNoiseState (*this);
|
||||||
memcpy (ck, protocolName, 32); // ck = h = protocol_name || 0
|
|
||||||
SHA256 (ck, 32, h); // h = SHA256(h);
|
|
||||||
uint8_t hepk[32];
|
uint8_t hepk[32];
|
||||||
encryptor->Encrypt (nullptr, hepk, nullptr, false);
|
encryptor->Encrypt (nullptr, hepk, nullptr, false);
|
||||||
MixHash (hepk, 32); // h = SHA256(h || hepk)
|
MixHash (hepk, 32); // h = SHA256(h || hepk)
|
||||||
|
@ -140,13 +137,11 @@ namespace tunnel
|
||||||
encrypted += 32;
|
encrypted += 32;
|
||||||
uint8_t sharedSecret[32];
|
uint8_t sharedSecret[32];
|
||||||
ephemeralKeys->Agree (hepk, sharedSecret); // x25519(sesk, hepk)
|
ephemeralKeys->Agree (hepk, sharedSecret); // x25519(sesk, hepk)
|
||||||
uint8_t keydata[64];
|
MixKey (sharedSecret);
|
||||||
i2p::crypto::HKDF (ck, sharedSecret, 32, "", keydata);
|
|
||||||
memcpy (ck, keydata, 32);
|
|
||||||
uint8_t nonce[12];
|
uint8_t nonce[12];
|
||||||
memset (nonce, 0, 12);
|
memset (nonce, 0, 12);
|
||||||
if (!i2p::crypto::AEADChaCha20Poly1305 (plainText, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, h, 32,
|
if (!i2p::crypto::AEADChaCha20Poly1305 (plainText, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, m_H, 32,
|
||||||
keydata + 32, nonce, encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16, true)) // encrypt
|
m_CK + 32, nonce, encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16, true)) // encrypt
|
||||||
{
|
{
|
||||||
LogPrint (eLogWarning, "Tunnel: Plaintext AEAD encryption failed");
|
LogPrint (eLogWarning, "Tunnel: Plaintext AEAD encryption failed");
|
||||||
return;
|
return;
|
||||||
|
@ -154,13 +149,16 @@ namespace tunnel
|
||||||
MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext)
|
MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext)
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelHopConfig::MixHash (const uint8_t * buf, size_t len)
|
void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state)
|
||||||
{
|
{
|
||||||
SHA256_CTX ctx;
|
static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars
|
||||||
SHA256_Init (&ctx);
|
static const uint8_t hh[32] =
|
||||||
SHA256_Update (&ctx, h, 32);
|
{
|
||||||
SHA256_Update (&ctx, buf, len);
|
0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1,
|
||||||
SHA256_Final (h, &ctx);
|
0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54
|
||||||
}
|
}; // SHA256 (protocol_name || 0)
|
||||||
|
memcpy (state.m_CK, protocolName, 32); // ck = h = protocol_name || 0
|
||||||
|
memcpy (state.m_H, hh, 32); // h = SHA256(h)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,12 +12,13 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "Identity.h"
|
#include "Identity.h"
|
||||||
#include "RouterContext.h"
|
#include "RouterContext.h"
|
||||||
|
#include "Crypto.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
struct TunnelHopConfig
|
struct TunnelHopConfig: public i2p::crypto::NoiseSymmetricState
|
||||||
{
|
{
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> ident;
|
std::shared_ptr<const i2p::data::IdentityEx> ident;
|
||||||
i2p::data::IdentHash nextIdent;
|
i2p::data::IdentHash nextIdent;
|
||||||
|
@ -30,7 +31,6 @@ namespace tunnel
|
||||||
|
|
||||||
TunnelHopConfig * next, * prev;
|
TunnelHopConfig * next, * prev;
|
||||||
int recordIndex; // record # in tunnel build message
|
int recordIndex; // record # in tunnel build message
|
||||||
uint8_t ck[32], h[32]; // for ECIES
|
|
||||||
|
|
||||||
TunnelHopConfig (std::shared_ptr<const i2p::data::IdentityEx> r);
|
TunnelHopConfig (std::shared_ptr<const i2p::data::IdentityEx> r);
|
||||||
|
|
||||||
|
@ -39,13 +39,14 @@ namespace tunnel
|
||||||
void SetNext (TunnelHopConfig * n);
|
void SetNext (TunnelHopConfig * n);
|
||||||
void SetPrev (TunnelHopConfig * p);
|
void SetPrev (TunnelHopConfig * p);
|
||||||
|
|
||||||
bool IsECIES () const { return ident->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; };
|
bool IsECIES () const { return ident->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; };
|
||||||
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx);
|
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx);
|
||||||
void EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor,
|
void EncryptECIES (std::shared_ptr<i2p::crypto::CryptoKeyEncryptor>& encryptor,
|
||||||
const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx);
|
const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx);
|
||||||
void MixHash (const uint8_t * buf, size_t len);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state);
|
||||||
|
|
||||||
class TunnelConfig
|
class TunnelConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -26,9 +26,10 @@ namespace tunnel
|
||||||
{
|
{
|
||||||
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
|
TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels):
|
||||||
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops),
|
||||||
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true),
|
m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels),
|
||||||
m_CustomPeerSelector(nullptr)
|
m_IsActive (true), m_CustomPeerSelector(nullptr)
|
||||||
{
|
{
|
||||||
|
m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + rand () % TUNNEL_POOL_MANAGE_INTERVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
TunnelPool::~TunnelPool ()
|
TunnelPool::~TunnelPool ()
|
||||||
|
@ -118,7 +119,6 @@ namespace tunnel
|
||||||
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex);
|
||||||
m_OutboundTunnels.insert (createdTunnel);
|
m_OutboundTunnels.insert (createdTunnel);
|
||||||
}
|
}
|
||||||
//CreatePairedInboundTunnel (createdTunnel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TunnelPool::TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel)
|
void TunnelPool::TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel)
|
||||||
|
@ -235,6 +235,15 @@ namespace tunnel
|
||||||
for (const auto& it : m_InboundTunnels)
|
for (const auto& it : m_InboundTunnels)
|
||||||
if (it->IsEstablished ()) num++;
|
if (it->IsEstablished ()) num++;
|
||||||
}
|
}
|
||||||
|
if (!num && !m_OutboundTunnels.empty ())
|
||||||
|
{
|
||||||
|
for (auto it: m_OutboundTunnels)
|
||||||
|
{
|
||||||
|
CreatePairedInboundTunnel (it);
|
||||||
|
num++;
|
||||||
|
if (num >= m_NumInboundTunnels) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
for (int i = num; i < m_NumInboundTunnels; i++)
|
for (int i = num; i < m_NumInboundTunnels; i++)
|
||||||
CreateInboundTunnel ();
|
CreateInboundTunnel ();
|
||||||
|
|
||||||
|
@ -313,6 +322,16 @@ namespace tunnel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TunnelPool::ManageTunnels (uint64_t ts)
|
||||||
|
{
|
||||||
|
if (ts > m_NextManageTime)
|
||||||
|
{
|
||||||
|
CreateTunnels ();
|
||||||
|
TestTunnels ();
|
||||||
|
m_NextManageTime = ts + TUNNEL_POOL_MANAGE_INTERVAL + (rand () % TUNNEL_POOL_MANAGE_INTERVAL)/2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg)
|
||||||
{
|
{
|
||||||
if (m_LocalDestination)
|
if (m_LocalDestination)
|
||||||
|
@ -342,17 +361,24 @@ namespace tunnel
|
||||||
}
|
}
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
// restore from test failed state if any
|
|
||||||
if (test.first->GetState () == eTunnelStateTestFailed)
|
|
||||||
test.first->SetState (eTunnelStateEstablished);
|
|
||||||
if (test.second->GetState () == eTunnelStateTestFailed)
|
|
||||||
test.second->SetState (eTunnelStateEstablished);
|
|
||||||
uint64_t dlt = i2p::util::GetMillisecondsSinceEpoch () - timestamp;
|
uint64_t dlt = i2p::util::GetMillisecondsSinceEpoch () - timestamp;
|
||||||
LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", dlt, " milliseconds");
|
LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", dlt, " milliseconds");
|
||||||
// update latency
|
|
||||||
uint64_t latency = dlt / 2;
|
uint64_t latency = dlt / 2;
|
||||||
test.first->AddLatencySample(latency);
|
// restore from test failed state if any
|
||||||
test.second->AddLatencySample(latency);
|
if (test.first)
|
||||||
|
{
|
||||||
|
if (test.first->GetState () == eTunnelStateTestFailed)
|
||||||
|
test.first->SetState (eTunnelStateEstablished);
|
||||||
|
// update latency
|
||||||
|
test.first->AddLatencySample(latency);
|
||||||
|
}
|
||||||
|
if (test.second)
|
||||||
|
{
|
||||||
|
if (test.second->GetState () == eTunnelStateTestFailed)
|
||||||
|
test.second->SetState (eTunnelStateEstablished);
|
||||||
|
// update latency
|
||||||
|
test.second->AddLatencySample(latency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -27,6 +27,8 @@ namespace i2p
|
||||||
{
|
{
|
||||||
namespace tunnel
|
namespace tunnel
|
||||||
{
|
{
|
||||||
|
const int TUNNEL_POOL_MANAGE_INTERVAL = 10; // in seconds
|
||||||
|
|
||||||
class Tunnel;
|
class Tunnel;
|
||||||
class InboundTunnel;
|
class InboundTunnel;
|
||||||
class OutboundTunnel;
|
class OutboundTunnel;
|
||||||
|
@ -69,6 +71,7 @@ namespace tunnel
|
||||||
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
|
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded = nullptr) const;
|
||||||
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
|
std::shared_ptr<OutboundTunnel> GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) const;
|
||||||
void TestTunnels ();
|
void TestTunnels ();
|
||||||
|
void ManageTunnels (uint64_t ts);
|
||||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||||
void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
|
void ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg);
|
||||||
|
|
||||||
|
@ -123,6 +126,7 @@ namespace tunnel
|
||||||
mutable std::mutex m_TestsMutex;
|
mutable std::mutex m_TestsMutex;
|
||||||
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
|
std::map<uint32_t, std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > m_Tests;
|
||||||
bool m_IsActive;
|
bool m_IsActive;
|
||||||
|
uint64_t m_NextManageTime; // in seconds
|
||||||
std::mutex m_CustomPeerSelectorMutex;
|
std::mutex m_CustomPeerSelectorMutex;
|
||||||
ITunnelPeerSelector * m_CustomPeerSelector;
|
ITunnelPeerSelector * m_CustomPeerSelector;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,10 @@ namespace api
|
||||||
i2p::fs::Init();
|
i2p::fs::Init();
|
||||||
|
|
||||||
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
|
bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation);
|
||||||
i2p::crypto::InitCrypto (precomputation);
|
bool aesni; i2p::config::GetOption("cpuext.aesni", aesni);
|
||||||
|
bool avx; i2p::config::GetOption("cpuext.avx", avx);
|
||||||
|
bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt);
|
||||||
|
i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt);
|
||||||
|
|
||||||
int netID; i2p::config::GetOption("netid", netID);
|
int netID; i2p::config::GetOption("netid", netID);
|
||||||
i2p::context.SetNetID (netID);
|
i2p::context.SetNetID (netID);
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -56,7 +56,7 @@ int inet_pton_xp(int af, const char *src, void *dst)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else /* !WIN32 => UNIX */
|
#else /* !_WIN32 => UNIX */
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <ifaddrs.h>
|
#include <ifaddrs.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -109,7 +109,7 @@ namespace util
|
||||||
|
|
||||||
namespace net
|
namespace net
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
bool IsWindowsXPorLater()
|
bool IsWindowsXPorLater()
|
||||||
{
|
{
|
||||||
static bool isRequested = false;
|
static bool isRequested = false;
|
||||||
|
@ -333,13 +333,13 @@ namespace net
|
||||||
|
|
||||||
return mtu;
|
return mtu;
|
||||||
}
|
}
|
||||||
#endif // WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
int GetMTU(const boost::asio::ip::address& localAddress)
|
int GetMTU(const boost::asio::ip::address& localAddress)
|
||||||
{
|
{
|
||||||
int fallback = localAddress.is_v6 () ? 1280 : 620; // fallback MTU
|
int fallback = localAddress.is_v6 () ? 1280 : 620; // fallback MTU
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
return GetMTUWindows(localAddress, fallback);
|
return GetMTUWindows(localAddress, fallback);
|
||||||
#else
|
#else
|
||||||
return GetMTUUnix(localAddress, fallback);
|
return GetMTUUnix(localAddress, fallback);
|
||||||
|
@ -349,7 +349,7 @@ namespace net
|
||||||
|
|
||||||
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6)
|
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6)
|
||||||
{
|
{
|
||||||
#ifdef WIN32
|
#ifdef _WIN32
|
||||||
LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32");
|
LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32");
|
||||||
if(ipv6)
|
if(ipv6)
|
||||||
return boost::asio::ip::address::from_string("::1");
|
return boost::asio::ip::address::from_string("::1");
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
#define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c)
|
||||||
|
|
||||||
#define I2PD_VERSION_MAJOR 2
|
#define I2PD_VERSION_MAJOR 2
|
||||||
#define I2PD_VERSION_MINOR 33
|
#define I2PD_VERSION_MINOR 35
|
||||||
#define I2PD_VERSION_MICRO 0
|
#define I2PD_VERSION_MICRO 0
|
||||||
#define I2PD_VERSION_PATCH 0
|
#define I2PD_VERSION_PATCH 0
|
||||||
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
|
|
||||||
#define I2P_VERSION_MAJOR 0
|
#define I2P_VERSION_MAJOR 0
|
||||||
#define I2P_VERSION_MINOR 9
|
#define I2P_VERSION_MINOR 9
|
||||||
#define I2P_VERSION_MICRO 47
|
#define I2P_VERSION_MICRO 48
|
||||||
#define I2P_VERSION_PATCH 0
|
#define I2P_VERSION_PATCH 0
|
||||||
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
#define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO)
|
||||||
|
|
|
@ -454,17 +454,18 @@ namespace client
|
||||||
auto it = m_Addresses.find (name);
|
auto it = m_Addresses.find (name);
|
||||||
if (it != m_Addresses.end ()) // already exists ?
|
if (it != m_Addresses.end ()) // already exists ?
|
||||||
{
|
{
|
||||||
if (it->second->IsIdentHash () && it->second->identHash != ident->GetIdentHash ()) // address changed?
|
if (it->second->IsIdentHash () && it->second->identHash != ident->GetIdentHash () && // address changed?
|
||||||
|
ident->GetSigningKeyType () != i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) // don't replace by DSA
|
||||||
{
|
{
|
||||||
it->second->identHash = ident->GetIdentHash ();
|
it->second->identHash = ident->GetIdentHash ();
|
||||||
m_Storage->AddAddress (ident);
|
m_Storage->AddAddress (ident);
|
||||||
|
m_Storage->RemoveAddress (it->second->identHash);
|
||||||
LogPrint (eLogInfo, "Addressbook: updated host: ", name);
|
LogPrint (eLogInfo, "Addressbook: updated host: ", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//m_Addresses.emplace (name, std::make_shared<Address>(ident->GetIdentHash ()));
|
m_Addresses.emplace (name, std::make_shared<Address>(ident->GetIdentHash ()));
|
||||||
m_Addresses[name] = std::make_shared<Address>(ident->GetIdentHash ()); // for gcc 4.7
|
|
||||||
m_Storage->AddAddress (ident);
|
m_Storage->AddAddress (ident);
|
||||||
if (is_update)
|
if (is_update)
|
||||||
LogPrint (eLogInfo, "Addressbook: added new host: ", name);
|
LogPrint (eLogInfo, "Addressbook: added new host: ", name);
|
||||||
|
|
|
@ -590,7 +590,8 @@ namespace client
|
||||||
localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
|
localDestination = CreateNewMatchedTunnelDestination(k, dest, &options);
|
||||||
else
|
else
|
||||||
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
|
localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options);
|
||||||
destinations[keys] = localDestination;
|
if (keys != "transient")
|
||||||
|
destinations[keys] = localDestination;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,12 @@ namespace client
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2CPDestination::Stop ()
|
||||||
|
{
|
||||||
|
LeaseSetDestination::Stop ();
|
||||||
|
m_Owner = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
|
void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key)
|
||||||
{
|
{
|
||||||
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), key);
|
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), key);
|
||||||
|
@ -46,7 +52,7 @@ namespace client
|
||||||
|
|
||||||
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const
|
||||||
{
|
{
|
||||||
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && m_ECIESx25519Decryptor)
|
if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor)
|
||||||
return m_ECIESx25519Decryptor->Decrypt (encrypted, data, ctx, true);
|
return m_ECIESx25519Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
if (m_Decryptor)
|
if (m_Decryptor)
|
||||||
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
return m_Decryptor->Decrypt (encrypted, data, ctx, true);
|
||||||
|
@ -57,14 +63,14 @@ namespace client
|
||||||
|
|
||||||
const uint8_t * I2CPDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
|
const uint8_t * I2CPDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
|
||||||
{
|
{
|
||||||
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && m_ECIESx25519Decryptor)
|
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor)
|
||||||
return m_ECIESx25519Decryptor->GetPubicKey ();
|
return m_ECIESx25519Decryptor->GetPubicKey ();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
|
bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const
|
||||||
{
|
{
|
||||||
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType;
|
return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +78,8 @@ namespace client
|
||||||
{
|
{
|
||||||
uint32_t length = bufbe32toh (buf);
|
uint32_t length = bufbe32toh (buf);
|
||||||
if (length > len - 4) length = len - 4;
|
if (length > len - 4) length = len - 4;
|
||||||
m_Owner->SendMessagePayloadMessage (buf + 4, length);
|
if (m_Owner)
|
||||||
|
m_Owner->SendMessagePayloadMessage (buf + 4, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
|
void I2CPDestination::CreateNewLeaseSet (std::vector<std::shared_ptr<i2p::tunnel::InboundTunnel> > tunnels)
|
||||||
|
@ -82,9 +89,16 @@ namespace client
|
||||||
m_LeaseSetExpirationTime = ls.GetExpirationTime ();
|
m_LeaseSetExpirationTime = ls.GetExpirationTime ();
|
||||||
uint8_t * leases = ls.GetLeases ();
|
uint8_t * leases = ls.GetLeases ();
|
||||||
leases[-1] = tunnels.size ();
|
leases[-1] = tunnels.size ();
|
||||||
htobe16buf (leases - 3, m_Owner->GetSessionID ());
|
if (m_Owner)
|
||||||
size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size ();
|
{
|
||||||
m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l);
|
uint16_t sessionID = m_Owner->GetSessionID ();
|
||||||
|
if (sessionID != 0xFFFF)
|
||||||
|
{
|
||||||
|
htobe16buf (leases - 3, sessionID);
|
||||||
|
size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size ();
|
||||||
|
m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
|
void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len)
|
||||||
|
@ -119,7 +133,8 @@ namespace client
|
||||||
[s, msg, remote, nonce]()
|
[s, msg, remote, nonce]()
|
||||||
{
|
{
|
||||||
bool sent = s->SendMsg (msg, remote);
|
bool sent = s->SendMsg (msg, remote);
|
||||||
s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
if (s->m_Owner)
|
||||||
|
s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -130,9 +145,10 @@ namespace client
|
||||||
if (ls)
|
if (ls)
|
||||||
{
|
{
|
||||||
bool sent = s->SendMsg (msg, ls);
|
bool sent = s->SendMsg (msg, ls);
|
||||||
s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
if (s->m_Owner)
|
||||||
|
s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure);
|
||||||
}
|
}
|
||||||
else
|
else if (s->m_Owner)
|
||||||
s->m_Owner->SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLeaseSet);
|
s->m_Owner->SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLeaseSet);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -227,12 +243,13 @@ namespace client
|
||||||
|
|
||||||
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket):
|
I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr<proto::socket> socket):
|
||||||
m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF),
|
m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF),
|
||||||
m_MessageID (0), m_IsSendAccepted (true)
|
m_MessageID (0), m_IsSendAccepted (true), m_IsSending (false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CPSession::~I2CPSession ()
|
I2CPSession::~I2CPSession ()
|
||||||
{
|
{
|
||||||
|
Terminate ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::Start ()
|
void I2CPSession::Start ()
|
||||||
|
@ -343,40 +360,76 @@ namespace client
|
||||||
m_Socket->close ();
|
m_Socket->close ();
|
||||||
m_Socket = nullptr;
|
m_Socket = nullptr;
|
||||||
}
|
}
|
||||||
m_Owner.RemoveSession (GetSessionID ());
|
if (!m_SendQueue.IsEmpty ())
|
||||||
LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " terminated");
|
m_SendQueue.CleanUp ();
|
||||||
|
if (m_SessionID != 0xFFFF)
|
||||||
|
{
|
||||||
|
m_Owner.RemoveSession (GetSessionID ());
|
||||||
|
LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " terminated");
|
||||||
|
m_SessionID = 0xFFFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
|
void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len)
|
||||||
{
|
{
|
||||||
if (len > I2CP_MAX_MESSAGE_LENGTH)
|
auto l = len + I2CP_HEADER_SIZE;
|
||||||
|
if (l > I2CP_MAX_MESSAGE_LENGTH)
|
||||||
{
|
{
|
||||||
LogPrint (eLogError, "I2CP: Message to send is too long ", len);
|
LogPrint (eLogError, "I2CP: Message to send is too long ", l);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto socket = m_Socket;
|
auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr;
|
||||||
if (socket)
|
uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer;
|
||||||
|
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len);
|
||||||
|
buf[I2CP_HEADER_TYPE_OFFSET] = type;
|
||||||
|
memcpy (buf + I2CP_HEADER_SIZE, payload, len);
|
||||||
|
if (sendBuf)
|
||||||
|
{
|
||||||
|
if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE)
|
||||||
|
m_SendQueue.Add (sendBuf);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "I2CP: send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
auto l = len + I2CP_HEADER_SIZE;
|
auto socket = m_Socket;
|
||||||
uint8_t * buf = new uint8_t[l];
|
if (socket)
|
||||||
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len);
|
{
|
||||||
buf[I2CP_HEADER_TYPE_OFFSET] = type;
|
m_IsSending = true;
|
||||||
memcpy (buf + I2CP_HEADER_SIZE, payload, len);
|
boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l),
|
||||||
boost::asio::async_write (*socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (),
|
boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent,
|
||||||
std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (),
|
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
std::placeholders::_1, std::placeholders::_2, buf));
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
|
||||||
|
{
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
if (ecode != boost::asio::error::operation_aborted)
|
||||||
|
Terminate ();
|
||||||
|
}
|
||||||
|
else if (!m_SendQueue.IsEmpty ())
|
||||||
|
{
|
||||||
|
auto socket = m_Socket;
|
||||||
|
if (socket)
|
||||||
|
{
|
||||||
|
auto len = m_SendQueue.Get (m_SendBuffer, I2CP_MAX_MESSAGE_LENGTH);
|
||||||
|
boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, len),
|
||||||
|
boost::asio::transfer_all (),std::bind(&I2CPSession::HandleI2CPMessageSent,
|
||||||
|
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m_IsSending = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LogPrint (eLogError, "I2CP: Can't write to the socket");
|
m_IsSending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf)
|
|
||||||
{
|
|
||||||
delete[] buf;
|
|
||||||
if (ecode && ecode != boost::asio::error::operation_aborted)
|
|
||||||
Terminate ();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len)
|
std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t l = buf[0];
|
uint8_t l = buf[0];
|
||||||
|
@ -492,11 +545,7 @@ namespace client
|
||||||
{
|
{
|
||||||
SendSessionStatusMessage (0); // destroy
|
SendSessionStatusMessage (0); // destroy
|
||||||
LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " destroyed");
|
LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " destroyed");
|
||||||
if (m_Destination)
|
Terminate ();
|
||||||
{
|
|
||||||
m_Destination->Stop ();
|
|
||||||
m_Destination = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void I2CPSession::ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len)
|
void I2CPSession::ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len)
|
||||||
|
@ -621,7 +670,7 @@ namespace client
|
||||||
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type
|
uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type
|
||||||
uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length
|
uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length
|
||||||
if (offset + keyLen > len) return;
|
if (offset + keyLen > len) return;
|
||||||
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
|
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
|
||||||
m_Destination->SetECIESx25519EncryptionPrivateKey (buf + offset);
|
m_Destination->SetECIESx25519EncryptionPrivateKey (buf + offset);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -807,16 +856,40 @@ namespace client
|
||||||
{
|
{
|
||||||
// we don't use SendI2CPMessage to eliminate additional copy
|
// we don't use SendI2CPMessage to eliminate additional copy
|
||||||
auto l = len + 10 + I2CP_HEADER_SIZE;
|
auto l = len + 10 + I2CP_HEADER_SIZE;
|
||||||
uint8_t * buf = new uint8_t[l];
|
if (l > I2CP_MAX_MESSAGE_LENGTH)
|
||||||
|
{
|
||||||
|
LogPrint (eLogError, "I2CP: Message to send is too long ", l);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto sendBuf = m_IsSending ? std::make_shared<i2p::stream::SendBuffer> (l) : nullptr;
|
||||||
|
uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer;
|
||||||
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10);
|
htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10);
|
||||||
buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE;
|
buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE;
|
||||||
htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID);
|
htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID);
|
||||||
htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++);
|
htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++);
|
||||||
htobe32buf (buf + I2CP_HEADER_SIZE + 6, len);
|
htobe32buf (buf + I2CP_HEADER_SIZE + 6, len);
|
||||||
memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len);
|
memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len);
|
||||||
boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (),
|
if (sendBuf)
|
||||||
std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (),
|
{
|
||||||
std::placeholders::_1, std::placeholders::_2, buf));
|
if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE)
|
||||||
|
m_SendQueue.Add (sendBuf);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogPrint (eLogWarning, "I2CP: send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto socket = m_Socket;
|
||||||
|
if (socket)
|
||||||
|
{
|
||||||
|
m_IsSending = true;
|
||||||
|
boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l),
|
||||||
|
boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent,
|
||||||
|
shared_from_this (), std::placeholders::_1, std::placeholders::_2));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread):
|
I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread):
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "Destination.h"
|
#include "Destination.h"
|
||||||
|
#include "Streaming.h"
|
||||||
|
|
||||||
namespace i2p
|
namespace i2p
|
||||||
{
|
{
|
||||||
|
@ -25,6 +26,7 @@ namespace client
|
||||||
const uint8_t I2CP_PROTOCOL_BYTE = 0x2A;
|
const uint8_t I2CP_PROTOCOL_BYTE = 0x2A;
|
||||||
const size_t I2CP_SESSION_BUFFER_SIZE = 4096;
|
const size_t I2CP_SESSION_BUFFER_SIZE = 4096;
|
||||||
const size_t I2CP_MAX_MESSAGE_LENGTH = 65535;
|
const size_t I2CP_MAX_MESSAGE_LENGTH = 65535;
|
||||||
|
const size_t I2CP_MAX_SEND_QUEUE_SIZE = 1024*1024; // in bytes, 1M
|
||||||
|
|
||||||
const size_t I2CP_HEADER_LENGTH_OFFSET = 0;
|
const size_t I2CP_HEADER_LENGTH_OFFSET = 0;
|
||||||
const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4;
|
const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4;
|
||||||
|
@ -70,6 +72,8 @@ namespace client
|
||||||
I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
|
I2CPDestination (boost::asio::io_service& service, std::shared_ptr<I2CPSession> owner,
|
||||||
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params);
|
std::shared_ptr<const i2p::data::IdentityEx> identity, bool isPublic, const std::map<std::string, std::string>& params);
|
||||||
~I2CPDestination () {};
|
~I2CPDestination () {};
|
||||||
|
|
||||||
|
void Stop ();
|
||||||
|
|
||||||
void SetEncryptionPrivateKey (const uint8_t * key);
|
void SetEncryptionPrivateKey (const uint8_t * key);
|
||||||
void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; };
|
void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; };
|
||||||
|
@ -166,12 +170,12 @@ namespace client
|
||||||
void HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleMessage ();
|
void HandleMessage ();
|
||||||
void Terminate ();
|
void Terminate ();
|
||||||
|
|
||||||
void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf);
|
void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
|
|
||||||
std::string ExtractString (const uint8_t * buf, size_t len);
|
std::string ExtractString (const uint8_t * buf, size_t len);
|
||||||
size_t PutString (uint8_t * buf, size_t len, const std::string& str);
|
size_t PutString (uint8_t * buf, size_t len, const std::string& str);
|
||||||
void ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping);
|
void ExtractMapping (const uint8_t * buf, size_t len, std::map<std::string, std::string>& mapping);
|
||||||
|
|
||||||
void SendSessionStatusMessage (uint8_t status);
|
void SendSessionStatusMessage (uint8_t status);
|
||||||
void SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity);
|
void SendHostReplyMessage (uint32_t requestID, std::shared_ptr<const i2p::data::IdentityEx> identity);
|
||||||
|
|
||||||
|
@ -186,6 +190,11 @@ namespace client
|
||||||
uint16_t m_SessionID;
|
uint16_t m_SessionID;
|
||||||
uint32_t m_MessageID;
|
uint32_t m_MessageID;
|
||||||
bool m_IsSendAccepted;
|
bool m_IsSendAccepted;
|
||||||
|
|
||||||
|
// to client
|
||||||
|
bool m_IsSending;
|
||||||
|
uint8_t m_SendBuffer[I2CP_MAX_MESSAGE_LENGTH];
|
||||||
|
i2p::stream::SendBufferQueue m_SendQueue;
|
||||||
};
|
};
|
||||||
typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len);
|
typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len);
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace client
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case eSAMSocketTypeAcceptor:
|
case eSAMSocketTypeAcceptor:
|
||||||
|
case eSAMSocketTypeForward:
|
||||||
{
|
{
|
||||||
if (Session)
|
if (Session)
|
||||||
{
|
{
|
||||||
|
@ -198,7 +199,7 @@ namespace client
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg);
|
LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg);
|
||||||
|
|
||||||
if (!m_IsSilent)
|
if (!m_IsSilent || m_SocketType == eSAMSocketTypeForward)
|
||||||
boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
|
boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (),
|
||||||
std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
|
std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (),
|
||||||
std::placeholders::_1, std::placeholders::_2, close));
|
std::placeholders::_1, std::placeholders::_2, close));
|
||||||
|
@ -263,6 +264,8 @@ namespace client
|
||||||
ProcessStreamConnect (separator + 1, bytes_transferred - (separator - m_Buffer) - 1, bytes_transferred - (eol - m_Buffer) - 1);
|
ProcessStreamConnect (separator + 1, bytes_transferred - (separator - m_Buffer) - 1, bytes_transferred - (eol - m_Buffer) - 1);
|
||||||
else if (!strcmp (m_Buffer, SAM_STREAM_ACCEPT))
|
else if (!strcmp (m_Buffer, SAM_STREAM_ACCEPT))
|
||||||
ProcessStreamAccept (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
ProcessStreamAccept (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
||||||
|
else if (!strcmp (m_Buffer, SAM_STREAM_FORWARD))
|
||||||
|
ProcessStreamForward (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
||||||
else if (!strcmp (m_Buffer, SAM_DEST_GENERATE))
|
else if (!strcmp (m_Buffer, SAM_DEST_GENERATE))
|
||||||
ProcessDestGenerate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
ProcessDestGenerate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1);
|
||||||
else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP))
|
else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP))
|
||||||
|
@ -358,12 +361,12 @@ namespace client
|
||||||
|
|
||||||
std::shared_ptr<boost::asio::ip::udp::endpoint> forward = nullptr;
|
std::shared_ptr<boost::asio::ip::udp::endpoint> forward = nullptr;
|
||||||
if ((type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) &&
|
if ((type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) &&
|
||||||
params.find(SAM_VALUE_HOST) != params.end() && params.find(SAM_VALUE_PORT) != params.end())
|
params.find(SAM_PARAM_HOST) != params.end() && params.find(SAM_PARAM_PORT) != params.end())
|
||||||
{
|
{
|
||||||
// udp forward selected
|
// udp forward selected
|
||||||
boost::system::error_code e;
|
boost::system::error_code e;
|
||||||
// TODO: support hostnames in udp forward
|
// TODO: support hostnames in udp forward
|
||||||
auto addr = boost::asio::ip::address::from_string(params[SAM_VALUE_HOST], e);
|
auto addr = boost::asio::ip::address::from_string(params[SAM_PARAM_HOST], e);
|
||||||
if (e)
|
if (e)
|
||||||
{
|
{
|
||||||
// not an ip address
|
// not an ip address
|
||||||
|
@ -371,7 +374,7 @@ namespace client
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto port = std::stoi(params[SAM_VALUE_PORT]);
|
auto port = std::stoi(params[SAM_PARAM_PORT]);
|
||||||
if (port == -1)
|
if (port == -1)
|
||||||
{
|
{
|
||||||
SendI2PError("Invalid port");
|
SendI2PError("Invalid port");
|
||||||
|
@ -469,6 +472,11 @@ namespace client
|
||||||
void SAMSocket::ProcessStreamConnect (char * buf, size_t len, size_t rem)
|
void SAMSocket::ProcessStreamConnect (char * buf, size_t len, size_t rem)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAM: stream connect: ", buf);
|
LogPrint (eLogDebug, "SAM: stream connect: ", buf);
|
||||||
|
if ( m_SocketType != eSAMSocketTypeUnknown)
|
||||||
|
{
|
||||||
|
SendI2PError ("Socket already in use");
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
ExtractParams (buf, params);
|
ExtractParams (buf, params);
|
||||||
std::string& id = params[SAM_PARAM_ID];
|
std::string& id = params[SAM_PARAM_ID];
|
||||||
|
@ -544,6 +552,11 @@ namespace client
|
||||||
void SAMSocket::ProcessStreamAccept (char * buf, size_t len)
|
void SAMSocket::ProcessStreamAccept (char * buf, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAM: stream accept: ", buf);
|
LogPrint (eLogDebug, "SAM: stream accept: ", buf);
|
||||||
|
if ( m_SocketType != eSAMSocketTypeUnknown)
|
||||||
|
{
|
||||||
|
SendI2PError ("Socket already in use");
|
||||||
|
return;
|
||||||
|
}
|
||||||
std::map<std::string, std::string> params;
|
std::map<std::string, std::string> params;
|
||||||
ExtractParams (buf, params);
|
ExtractParams (buf, params);
|
||||||
std::string& id = params[SAM_PARAM_ID];
|
std::string& id = params[SAM_PARAM_ID];
|
||||||
|
@ -565,6 +578,53 @@ namespace client
|
||||||
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SAMSocket::ProcessStreamForward (char * buf, size_t len)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "SAM: stream forward: ", buf);
|
||||||
|
std::map<std::string, std::string> params;
|
||||||
|
ExtractParams (buf, params);
|
||||||
|
std::string& id = params[SAM_PARAM_ID];
|
||||||
|
auto session = m_Owner.FindSession (id);
|
||||||
|
if (!session)
|
||||||
|
{
|
||||||
|
SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (session->localDestination->IsAcceptingStreams ())
|
||||||
|
{
|
||||||
|
SendI2PError ("Already accepting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto it = params.find (SAM_PARAM_PORT);
|
||||||
|
if (it == params.end ())
|
||||||
|
{
|
||||||
|
SendI2PError ("PORT is missing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto port = std::stoi (it->second);
|
||||||
|
if (port <= 0 || port >= 0xFFFF)
|
||||||
|
{
|
||||||
|
SendI2PError ("Invalid PORT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boost::system::error_code ec;
|
||||||
|
auto ep = m_Socket.remote_endpoint (ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
SendI2PError ("Socket error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ep.port (port);
|
||||||
|
m_SocketType = eSAMSocketTypeForward;
|
||||||
|
m_ID = id;
|
||||||
|
m_IsAccepting = true;
|
||||||
|
std::string& silent = params[SAM_PARAM_SILENT];
|
||||||
|
if (silent == SAM_VALUE_TRUE) m_IsSilent = true;
|
||||||
|
session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward,
|
||||||
|
shared_from_this (), std::placeholders::_1, ep));
|
||||||
|
SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false);
|
||||||
|
}
|
||||||
|
|
||||||
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
|
size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
|
LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len);
|
||||||
|
@ -917,6 +977,43 @@ namespace client
|
||||||
LogPrint (eLogWarning, "SAM: I2P acceptor has been reset");
|
LogPrint (eLogWarning, "SAM: I2P acceptor has been reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SAMSocket::HandleI2PForward (std::shared_ptr<i2p::stream::Stream> stream,
|
||||||
|
boost::asio::ip::tcp::endpoint ep)
|
||||||
|
{
|
||||||
|
if (stream)
|
||||||
|
{
|
||||||
|
LogPrint (eLogDebug, "SAM: incoming forward I2P connection for session ", m_ID);
|
||||||
|
auto newSocket = std::make_shared<SAMSocket>(m_Owner);
|
||||||
|
newSocket->SetSocketType (eSAMSocketTypeStream);
|
||||||
|
auto s = shared_from_this ();
|
||||||
|
newSocket->GetSocket ().async_connect (ep,
|
||||||
|
[s, newSocket, stream](const boost::system::error_code& ecode)
|
||||||
|
{
|
||||||
|
if (!ecode)
|
||||||
|
{
|
||||||
|
s->m_Owner.AddSocket (newSocket);
|
||||||
|
newSocket->Receive ();
|
||||||
|
newSocket->m_Stream = stream;
|
||||||
|
newSocket->m_ID = s->m_ID;
|
||||||
|
if (!s->m_IsSilent)
|
||||||
|
{
|
||||||
|
// get remote peer address
|
||||||
|
auto dest = stream->GetRemoteIdentity()->ToBase64 ();
|
||||||
|
memcpy (newSocket->m_StreamBuffer, dest.c_str (), dest.length ());
|
||||||
|
newSocket->m_StreamBuffer[dest.length ()] = '\n';
|
||||||
|
newSocket->HandleI2PReceive (boost::system::error_code (),dest.length () + 1); // we send identity like it has been received from stream
|
||||||
|
}
|
||||||
|
else
|
||||||
|
newSocket->I2PReceive ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
stream->AsyncClose ();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LogPrint (eLogWarning, "SAM: I2P forward acceptor has been reset");
|
||||||
|
}
|
||||||
|
|
||||||
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAM: datagram received ", len);
|
LogPrint (eLogDebug, "SAM: datagram received ", len);
|
||||||
|
@ -1072,6 +1169,12 @@ namespace client
|
||||||
std::placeholders::_1, newSocket));
|
std::placeholders::_1, newSocket));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SAMBridge::AddSocket(std::shared_ptr<SAMSocket> socket)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_OpenSocketsMutex);
|
||||||
|
m_OpenSockets.push_back(socket);
|
||||||
|
}
|
||||||
|
|
||||||
void SAMBridge::RemoveSocket(const std::shared_ptr<SAMSocket> & socket)
|
void SAMBridge::RemoveSocket(const std::shared_ptr<SAMSocket> & socket)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(m_OpenSocketsMutex);
|
std::unique_lock<std::mutex> lock(m_OpenSocketsMutex);
|
||||||
|
@ -1087,10 +1190,7 @@ namespace client
|
||||||
if (!ec)
|
if (!ec)
|
||||||
{
|
{
|
||||||
LogPrint (eLogDebug, "SAM: new connection from ", ep);
|
LogPrint (eLogDebug, "SAM: new connection from ", ep);
|
||||||
{
|
AddSocket (socket);
|
||||||
std::unique_lock<std::mutex> l(m_OpenSocketsMutex);
|
|
||||||
m_OpenSockets.push_back(socket);
|
|
||||||
}
|
|
||||||
socket->ReceiveHandshake ();
|
socket->ReceiveHandshake ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -48,6 +48,7 @@ namespace client
|
||||||
const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
|
const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n";
|
||||||
const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
|
const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n";
|
||||||
const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
|
const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT";
|
||||||
|
const char SAM_STREAM_FORWARD[] = "STREAM FORWARD";
|
||||||
const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND";
|
const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND";
|
||||||
const char SAM_RAW_SEND[] = "RAW SEND";
|
const char SAM_RAW_SEND[] = "RAW SEND";
|
||||||
const char SAM_DEST_GENERATE[] = "DEST GENERATE";
|
const char SAM_DEST_GENERATE[] = "DEST GENERATE";
|
||||||
|
@ -69,14 +70,14 @@ namespace client
|
||||||
const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE";
|
const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE";
|
||||||
const char SAM_PARAM_CRYPTO_TYPE[] = "CRYPTO_TYPE";
|
const char SAM_PARAM_CRYPTO_TYPE[] = "CRYPTO_TYPE";
|
||||||
const char SAM_PARAM_SIZE[] = "SIZE";
|
const char SAM_PARAM_SIZE[] = "SIZE";
|
||||||
|
const char SAM_PARAM_HOST[] = "HOST";
|
||||||
|
const char SAM_PARAM_PORT[] = "PORT";
|
||||||
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
|
const char SAM_VALUE_TRANSIENT[] = "TRANSIENT";
|
||||||
const char SAM_VALUE_STREAM[] = "STREAM";
|
const char SAM_VALUE_STREAM[] = "STREAM";
|
||||||
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
|
const char SAM_VALUE_DATAGRAM[] = "DATAGRAM";
|
||||||
const char SAM_VALUE_RAW[] = "RAW";
|
const char SAM_VALUE_RAW[] = "RAW";
|
||||||
const char SAM_VALUE_TRUE[] = "true";
|
const char SAM_VALUE_TRUE[] = "true";
|
||||||
const char SAM_VALUE_FALSE[] = "false";
|
const char SAM_VALUE_FALSE[] = "false";
|
||||||
const char SAM_VALUE_HOST[] = "HOST";
|
|
||||||
const char SAM_VALUE_PORT[] = "PORT";
|
|
||||||
|
|
||||||
enum SAMSocketType
|
enum SAMSocketType
|
||||||
{
|
{
|
||||||
|
@ -84,6 +85,7 @@ namespace client
|
||||||
eSAMSocketTypeSession,
|
eSAMSocketTypeSession,
|
||||||
eSAMSocketTypeStream,
|
eSAMSocketTypeStream,
|
||||||
eSAMSocketTypeAcceptor,
|
eSAMSocketTypeAcceptor,
|
||||||
|
eSAMSocketTypeForward,
|
||||||
eSAMSocketTypeTerminated
|
eSAMSocketTypeTerminated
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,6 +123,7 @@ namespace client
|
||||||
void I2PReceive ();
|
void I2PReceive ();
|
||||||
void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
|
||||||
void HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream);
|
void HandleI2PAccept (std::shared_ptr<i2p::stream::Stream> stream);
|
||||||
|
void HandleI2PForward (std::shared_ptr<i2p::stream::Stream> stream, boost::asio::ip::tcp::endpoint ep);
|
||||||
void HandleWriteI2PData (const boost::system::error_code& ecode, size_t sz);
|
void HandleWriteI2PData (const boost::system::error_code& ecode, size_t sz);
|
||||||
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
void HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
void HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
|
||||||
|
@ -128,6 +131,7 @@ namespace client
|
||||||
void ProcessSessionCreate (char * buf, size_t len);
|
void ProcessSessionCreate (char * buf, size_t len);
|
||||||
void ProcessStreamConnect (char * buf, size_t len, size_t rem);
|
void ProcessStreamConnect (char * buf, size_t len, size_t rem);
|
||||||
void ProcessStreamAccept (char * buf, size_t len);
|
void ProcessStreamAccept (char * buf, size_t len);
|
||||||
|
void ProcessStreamForward (char * buf, size_t len);
|
||||||
void ProcessDestGenerate (char * buf, size_t len);
|
void ProcessDestGenerate (char * buf, size_t len);
|
||||||
void ProcessNamingLookup (char * buf, size_t len);
|
void ProcessNamingLookup (char * buf, size_t len);
|
||||||
void SendI2PError(const std::string & msg);
|
void SendI2PError(const std::string & msg);
|
||||||
|
@ -205,6 +209,7 @@ namespace client
|
||||||
/** send raw data to remote endpoint from our UDP Socket */
|
/** send raw data to remote endpoint from our UDP Socket */
|
||||||
void SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote);
|
void SendTo(const uint8_t * buf, size_t len, std::shared_ptr<boost::asio::ip::udp::endpoint> remote);
|
||||||
|
|
||||||
|
void AddSocket(std::shared_ptr<SAMSocket> socket);
|
||||||
void RemoveSocket(const std::shared_ptr<SAMSocket> & socket);
|
void RemoveSocket(const std::shared_ptr<SAMSocket> & socket);
|
||||||
|
|
||||||
bool ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const;
|
bool ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const;
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
<translation type="qt" />
|
<translation type="qt" />
|
||||||
|
|
||||||
<releases>
|
<releases>
|
||||||
|
<release version="2.35.0" date="2020-11-30" />
|
||||||
|
<release version="2.34.0" date="2020-10-27" />
|
||||||
<release version="2.33.0" date="2020-08-24" />
|
<release version="2.33.0" date="2020-08-24" />
|
||||||
<release version="2.32.1" date="2020-06-02" />
|
<release version="2.32.1" date="2020-06-02" />
|
||||||
<release version="2.32.0" date="2020-05-25" />
|
<release version="2.32.0" date="2020-05-25" />
|
||||||
|
|
|
@ -17,7 +17,7 @@ BEGIN
|
||||||
VALUE "FileDescription", "I2Pd Qt"
|
VALUE "FileDescription", "I2Pd Qt"
|
||||||
VALUE "FileVersion", I2PD_VERSION
|
VALUE "FileVersion", I2PD_VERSION
|
||||||
VALUE "InternalName", "i2pd-qt"
|
VALUE "InternalName", "i2pd-qt"
|
||||||
VALUE "LegalCopyright", "Copyright (C) 2013-2018, The PurpleI2P Project"
|
VALUE "LegalCopyright", "Copyright (C) 2013-2020, The PurpleI2P Project"
|
||||||
VALUE "LegalTrademarks1", "Distributed under the BSD 3-Clause software license, see the accompanying file COPYING or https://opensource.org/licenses/BSD-3-Clause."
|
VALUE "LegalTrademarks1", "Distributed under the BSD 3-Clause software license, see the accompanying file COPYING or https://opensource.org/licenses/BSD-3-Clause."
|
||||||
VALUE "OriginalFilename", "i2pd_qt.exe"
|
VALUE "OriginalFilename", "i2pd_qt.exe"
|
||||||
VALUE "ProductName", "i2pd-qt"
|
VALUE "ProductName", "i2pd-qt"
|
||||||
|
|
|
@ -4,81 +4,19 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
TARGET = i2pd_qt
|
TARGET = i2pd_qt
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized
|
QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-deprecated-copy
|
||||||
CONFIG += strict_c++ c++11
|
CONFIG += strict_c++ c++11
|
||||||
|
|
||||||
DEFINES += USE_UPNP
|
|
||||||
|
|
||||||
CONFIG(debug, debug|release) {
|
CONFIG(debug, debug|release) {
|
||||||
message(Debug build)
|
message(Debug build)
|
||||||
DEFINES += DEBUG_WITH_DEFAULT_LOGGING
|
DEFINES += DEBUG_WITH_DEFAULT_LOGGING
|
||||||
|
I2PDMAKE += DEBUG=yes
|
||||||
} else {
|
} else {
|
||||||
message(Release build)
|
message(Release build)
|
||||||
|
I2PDMAKE += DEBUG=no
|
||||||
}
|
}
|
||||||
|
|
||||||
SOURCES += DaemonQT.cpp mainwindow.cpp \
|
SOURCES += DaemonQT.cpp mainwindow.cpp \
|
||||||
../../libi2pd/api.cpp \
|
|
||||||
../../libi2pd/Base.cpp \
|
|
||||||
../../libi2pd/Blinding.cpp \
|
|
||||||
../../libi2pd/BloomFilter.cpp \
|
|
||||||
../../libi2pd/ChaCha20.cpp \
|
|
||||||
../../libi2pd/Config.cpp \
|
|
||||||
../../libi2pd/CPU.cpp \
|
|
||||||
../../libi2pd/Crypto.cpp \
|
|
||||||
../../libi2pd/CryptoKey.cpp \
|
|
||||||
../../libi2pd/Datagram.cpp \
|
|
||||||
../../libi2pd/Destination.cpp \
|
|
||||||
../../libi2pd/Ed25519.cpp \
|
|
||||||
../../libi2pd/Family.cpp \
|
|
||||||
../../libi2pd/FS.cpp \
|
|
||||||
../../libi2pd/Garlic.cpp \
|
|
||||||
../../libi2pd/Gost.cpp \
|
|
||||||
../../libi2pd/Gzip.cpp \
|
|
||||||
../../libi2pd/HTTP.cpp \
|
|
||||||
../../libi2pd/I2NPProtocol.cpp \
|
|
||||||
../../libi2pd/I2PEndian.cpp \
|
|
||||||
../../libi2pd/Identity.cpp \
|
|
||||||
../../libi2pd/LeaseSet.cpp \
|
|
||||||
../../libi2pd/Log.cpp \
|
|
||||||
../../libi2pd/NetDb.cpp \
|
|
||||||
../../libi2pd/NetDbRequests.cpp \
|
|
||||||
../../libi2pd/NTCP2.cpp \
|
|
||||||
../../libi2pd/Poly1305.cpp \
|
|
||||||
../../libi2pd/Profiling.cpp \
|
|
||||||
../../libi2pd/Reseed.cpp \
|
|
||||||
../../libi2pd/RouterContext.cpp \
|
|
||||||
../../libi2pd/RouterInfo.cpp \
|
|
||||||
../../libi2pd/Signature.cpp \
|
|
||||||
../../libi2pd/SSU.cpp \
|
|
||||||
../../libi2pd/SSUData.cpp \
|
|
||||||
../../libi2pd/SSUSession.cpp \
|
|
||||||
../../libi2pd/Streaming.cpp \
|
|
||||||
../../libi2pd/Timestamp.cpp \
|
|
||||||
../../libi2pd/TransitTunnel.cpp \
|
|
||||||
../../libi2pd/Transports.cpp \
|
|
||||||
../../libi2pd/Tunnel.cpp \
|
|
||||||
../../libi2pd/TunnelEndpoint.cpp \
|
|
||||||
../../libi2pd/TunnelGateway.cpp \
|
|
||||||
../../libi2pd/TunnelPool.cpp \
|
|
||||||
../../libi2pd/TunnelConfig.cpp \
|
|
||||||
../../libi2pd/util.cpp \
|
|
||||||
../../libi2pd/Elligator.cpp \
|
|
||||||
../../libi2pd/ECIESX25519AEADRatchetSession.cpp \
|
|
||||||
../../libi2pd_client/AddressBook.cpp \
|
|
||||||
../../libi2pd_client/BOB.cpp \
|
|
||||||
../../libi2pd_client/ClientContext.cpp \
|
|
||||||
../../libi2pd_client/HTTPProxy.cpp \
|
|
||||||
../../libi2pd_client/I2CP.cpp \
|
|
||||||
../../libi2pd_client/I2PService.cpp \
|
|
||||||
../../libi2pd_client/I2PTunnel.cpp \
|
|
||||||
../../libi2pd_client/MatchedDestination.cpp \
|
|
||||||
../../libi2pd_client/SAM.cpp \
|
|
||||||
../../libi2pd_client/SOCKS.cpp \
|
|
||||||
../../daemon/Daemon.cpp \
|
|
||||||
../../daemon/HTTPServer.cpp \
|
|
||||||
../../daemon/I2PControl.cpp \
|
|
||||||
../../daemon/i2pd.cpp \
|
|
||||||
../../daemon/UPnP.cpp \
|
|
||||||
ClientTunnelPane.cpp \
|
ClientTunnelPane.cpp \
|
||||||
MainWindowItems.cpp \
|
MainWindowItems.cpp \
|
||||||
ServerTunnelPane.cpp \
|
ServerTunnelPane.cpp \
|
||||||
|
@ -93,77 +31,14 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \
|
||||||
DelayedSaveManager.cpp \
|
DelayedSaveManager.cpp \
|
||||||
Saver.cpp \
|
Saver.cpp \
|
||||||
DelayedSaveManagerImpl.cpp \
|
DelayedSaveManagerImpl.cpp \
|
||||||
SaverImpl.cpp
|
SaverImpl.cpp \
|
||||||
|
../../daemon/Daemon.cpp \
|
||||||
|
../../daemon/HTTPServer.cpp \
|
||||||
|
../../daemon/I2PControl.cpp \
|
||||||
|
../../daemon/i2pd.cpp \
|
||||||
|
../../daemon/UPnP.cpp
|
||||||
|
|
||||||
HEADERS += DaemonQT.h mainwindow.h \
|
HEADERS += DaemonQT.h mainwindow.h \
|
||||||
../../libi2pd/api.h \
|
|
||||||
../../libi2pd/Base.h \
|
|
||||||
../../libi2pd/Blinding.h \
|
|
||||||
../../libi2pd/BloomFilter.h \
|
|
||||||
../../libi2pd/ChaCha20.h \
|
|
||||||
../../libi2pd/Config.h \
|
|
||||||
../../libi2pd/CPU.h \
|
|
||||||
../../libi2pd/Crypto.h \
|
|
||||||
../../libi2pd/CryptoKey.h \
|
|
||||||
../../libi2pd/Datagram.h \
|
|
||||||
../../libi2pd/Destination.h \
|
|
||||||
../../libi2pd/Ed25519.h \
|
|
||||||
../../libi2pd/Family.h \
|
|
||||||
../../libi2pd/FS.h \
|
|
||||||
../../libi2pd/Garlic.h \
|
|
||||||
../../libi2pd/Gost.h \
|
|
||||||
../../libi2pd/Gzip.h \
|
|
||||||
../../libi2pd/HTTP.h \
|
|
||||||
../../libi2pd/I2NPProtocol.h \
|
|
||||||
../../libi2pd/I2PEndian.h \
|
|
||||||
../../libi2pd/Identity.h \
|
|
||||||
../../libi2pd/LeaseSet.h \
|
|
||||||
../../libi2pd/LittleBigEndian.h \
|
|
||||||
../../libi2pd/Log.h \
|
|
||||||
../../libi2pd/NetDb.hpp \
|
|
||||||
../../libi2pd/NetDbRequests.h \
|
|
||||||
../../libi2pd/NTCP2.h \
|
|
||||||
../../libi2pd/Poly1305.h \
|
|
||||||
../../libi2pd/Profiling.h \
|
|
||||||
../../libi2pd/Queue.h \
|
|
||||||
../../libi2pd/Reseed.h \
|
|
||||||
../../libi2pd/RouterContext.h \
|
|
||||||
../../libi2pd/RouterInfo.h \
|
|
||||||
../../libi2pd/Signature.h \
|
|
||||||
../../libi2pd/Siphash.h \
|
|
||||||
../../libi2pd/SSU.h \
|
|
||||||
../../libi2pd/SSUData.h \
|
|
||||||
../../libi2pd/SSUSession.h \
|
|
||||||
../../libi2pd/Streaming.h \
|
|
||||||
../../libi2pd/Tag.h \
|
|
||||||
../../libi2pd/Timestamp.h \
|
|
||||||
../../libi2pd/TransitTunnel.h \
|
|
||||||
../../libi2pd/Transports.h \
|
|
||||||
../../libi2pd/TransportSession.h \
|
|
||||||
../../libi2pd/Tunnel.h \
|
|
||||||
../../libi2pd/TunnelBase.h \
|
|
||||||
../../libi2pd/TunnelConfig.h \
|
|
||||||
../../libi2pd/TunnelEndpoint.h \
|
|
||||||
../../libi2pd/TunnelGateway.h \
|
|
||||||
../../libi2pd/TunnelPool.h \
|
|
||||||
../../libi2pd/util.h \
|
|
||||||
../../libi2pd/version.h \
|
|
||||||
../../libi2pd/Elligator.h \
|
|
||||||
../../libi2pd/ECIESX25519AEADRatchetSession.h \
|
|
||||||
../../libi2pd_client/AddressBook.h \
|
|
||||||
../../libi2pd_client/BOB.h \
|
|
||||||
../../libi2pd_client/ClientContext.h \
|
|
||||||
../../libi2pd_client/HTTPProxy.h \
|
|
||||||
../../libi2pd_client/I2CP.h \
|
|
||||||
../../libi2pd_client/I2PService.h \
|
|
||||||
../../libi2pd_client/I2PTunnel.h \
|
|
||||||
../../libi2pd_client/MatchedDestination.h \
|
|
||||||
../../libi2pd_client/SAM.h \
|
|
||||||
../../libi2pd_client/SOCKS.h \
|
|
||||||
../../daemon/Daemon.h \
|
|
||||||
../../daemon/HTTPServer.h \
|
|
||||||
../../daemon/I2PControl.h \
|
|
||||||
../../daemon/UPnP.h \
|
|
||||||
ClientTunnelPane.h \
|
ClientTunnelPane.h \
|
||||||
MainWindowItems.h \
|
MainWindowItems.h \
|
||||||
ServerTunnelPane.h \
|
ServerTunnelPane.h \
|
||||||
|
@ -180,7 +55,12 @@ HEADERS += DaemonQT.h mainwindow.h \
|
||||||
DelayedSaveManager.h \
|
DelayedSaveManager.h \
|
||||||
Saver.h \
|
Saver.h \
|
||||||
DelayedSaveManagerImpl.h \
|
DelayedSaveManagerImpl.h \
|
||||||
SaverImpl.h
|
SaverImpl.h \
|
||||||
|
../../daemon/Daemon.h \
|
||||||
|
../../daemon/HTTPServer.h \
|
||||||
|
../../daemon/I2PControl.h \
|
||||||
|
../../daemon/UPnP.h
|
||||||
|
|
||||||
|
|
||||||
INCLUDEPATH += ../../libi2pd
|
INCLUDEPATH += ../../libi2pd
|
||||||
INCLUDEPATH += ../../libi2pd_client
|
INCLUDEPATH += ../../libi2pd_client
|
||||||
|
@ -193,7 +73,23 @@ FORMS += mainwindow.ui \
|
||||||
routercommandswidget.ui \
|
routercommandswidget.ui \
|
||||||
generalsettingswidget.ui
|
generalsettingswidget.ui
|
||||||
|
|
||||||
LIBS += -lz
|
LIBS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -lz
|
||||||
|
|
||||||
|
libi2pd.commands = @echo Building i2pd libraries
|
||||||
|
libi2pd.target = $$PWD/../../libi2pd.a
|
||||||
|
libi2pd.depends = i2pd FORCE
|
||||||
|
|
||||||
|
i2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes $$I2PDMAKE api_client
|
||||||
|
i2pd.target += $$PWD/../../libi2pdclient.a
|
||||||
|
i2pd.depends = FORCE
|
||||||
|
|
||||||
|
cleani2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) clean
|
||||||
|
cleani2pd.depends = clean
|
||||||
|
|
||||||
|
PRE_TARGETDEPS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a
|
||||||
|
QMAKE_EXTRA_TARGETS += cleani2pd i2pd libi2pd
|
||||||
|
CLEAN_DEPS += cleani2pd
|
||||||
|
|
||||||
|
|
||||||
macx {
|
macx {
|
||||||
message("using mac os x target")
|
message("using mac os x target")
|
||||||
|
@ -230,10 +126,12 @@ windows {
|
||||||
QMAKE_CXXFLAGS_RELEASE = -Os
|
QMAKE_CXXFLAGS_RELEASE = -Os
|
||||||
QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows
|
QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows
|
||||||
|
|
||||||
#linker's -s means "strip"
|
# linker's -s means "strip"
|
||||||
QMAKE_LFLAGS_RELEASE += -s
|
QMAKE_LFLAGS_RELEASE += -s
|
||||||
|
|
||||||
LIBS = -lminiupnpc \
|
LIBS = \
|
||||||
|
$$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a \
|
||||||
|
-lminiupnpc \
|
||||||
-lboost_system$$BOOST_SUFFIX \
|
-lboost_system$$BOOST_SUFFIX \
|
||||||
-lboost_date_time$$BOOST_SUFFIX \
|
-lboost_date_time$$BOOST_SUFFIX \
|
||||||
-lboost_filesystem$$BOOST_SUFFIX \
|
-lboost_filesystem$$BOOST_SUFFIX \
|
||||||
|
|
Loading…
Add table
Reference in a new issue