Merge pull request #1525 from PurpleI2P/openssl

recent changes
This commit is contained in:
orignal 2020-05-30 13:33:45 -04:00 committed by GitHub
commit b992fbab52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
186 changed files with 6237 additions and 4312 deletions

View File

@ -1,6 +1,56 @@
# 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.32.0] - 2020-05-25
### Added
- Multiple encryption types for local destinations
- Next key and tagset for ECIES-X25519-AEAD-Ratchet
- NTCP2 through SOCKS proxy
- Throw error message if any port to bind is occupied
- gzip parameter for UDP tunnels
- Show ECIES-X25519-AEAD-Ratchet sessions and tags on the web console
- Simplified implementation of gzip for no compression mode
- Allow ECIES-X25519-AEAD-Ratchet session restart after 2 minutes
- Added logrotate config for rpm package
### Changed
- Select peers for client tunnels among routers >= 0.9.36
- Check ECIES flag for encrypted lookup reply
- Streaming MTU size 1812 for ECIES-X25519-AEAD-Ratchet
- Don't calculate checksum for Data message send through ECIES-X25519-AEAD-Ratchet
- Catch network connectivity status for Windows
- Stop as soon as no more transit tunnels during graceful shutdown for Android
- RouterInfo gzip compression level depends on size
- Send response to received datagram from ECIES-X25519-AEAD-Ratchet session
- Update webconsole functional
- Increased max transit tunnels limit
- Reseeds list
- Dropped windows support in cmake
### Fixed
- Correct timestamp check for LeaseSet2
- Encrypted leaseset without authentication
- Change SOCKS proxy connection response for clients without socks5h support (#1336)
## [2.31.0] - 2020-04-10
### Added
- NTCP2 through HTTP proxy
- Publish LeaseSet2 for I2CP destinations
- Show status page on main activity for android
- Handle ECIESFlag in DatabaseLookup at floodfill
- C++17 features for eligible compilers
### Changed
- Droped Websockets and Lua support
- Send DeliveryStatusMsg for LeaseSet for ECIES-X25519-AEAD-Ratchet
- Keep sending new session reply until established for ECIES-X25519-AEAD-Ratchet
- Updated SSU log messages
- Reopen SSU socket on exception
- Security hardening headers in web console
- Various web console changes
- Various QT changes
### Fixed
- NTCP2 socket descriptors leak
- Race condition with router's identity in transport sessions
- Not terminated streams remain forever
## [2.30.0] - 2020-02-25 ## [2.30.0] - 2020-02-25
### Added ### Added
- Single threaded SAM - Single threaded SAM

View File

@ -41,7 +41,7 @@ else ifneq (, $(findstring freebsd, $(SYS))$(findstring openbsd, $(SYS)))
DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp DAEMON_SRC += $(DAEMON_SRC_DIR)/UnixDaemon.cpp
include Makefile.bsd include Makefile.bsd
else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS))) else ifneq (, $(findstring mingw, $(SYS))$(findstring cygwin, $(SYS)))
DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp DAEMON_SRC += Win32/DaemonWin32.cpp Win32/Win32Service.cpp Win32/Win32App.cpp Win32/Win32NetState.cpp
include Makefile.mingw include Makefile.mingw
else # not supported else # not supported
$(error Not supported platform) $(error Not supported platform)

View File

@ -20,7 +20,7 @@ else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # gcc 4.7 - 4.9
else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6 else ifeq ($(shell expr match ${CXXVER} "[5-6]"),1) # gcc 5 - 6
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
LDLIBS = -latomic LDLIBS = -latomic
else ifeq ($(shell expr match ${CXXVER} "[7-9]"),1) # gcc >= 7 else ifeq ($(shell expr match ${CXXVER} "[1,7-9]"),1) # gcc >= 7
NEEDED_CXXFLAGS += -std=c++17 NEEDED_CXXFLAGS += -std=c++17
LDLIBS = -latomic LDLIBS = -latomic
else # not supported else # not supported

View File

@ -2,10 +2,19 @@ USE_WIN32_APP=yes
CXX = g++ CXX = g++
WINDRES = windres WINDRES = windres
CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN
NEEDED_CXXFLAGS = -std=c++11
INCFLAGS = -Idaemon -I. INCFLAGS = -Idaemon -I.
LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++
# detect proper flag for c++11 support by compilers
CXXVER := $(shell $(CXX) -dumpversion)
ifeq ($(shell expr match ${CXXVER} "[4]\.[7-9]\|4\.1[0-9]\|[5-6]"),4) # gcc 4.7 - 6
NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "[1,7-9]"),1) # gcc >= 7
NEEDED_CXXFLAGS += -std=c++17
else # not supported
$(error Compiler too old)
endif
# Boost libraries suffix # Boost libraries suffix
BOOST_SUFFIX = -mt BOOST_SUFFIX = -mt
@ -27,6 +36,8 @@ LDLIBS += \
-lws2_32 \ -lws2_32 \
-lgdi32 \ -lgdi32 \
-liphlpapi \ -liphlpapi \
-lole32 \
-luuid \
-lstdc++ \ -lstdc++ \
-lpthread -lpthread

View File

@ -2,6 +2,7 @@
[![Snapcraft release](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd) [![Snapcraft release](https://snapcraft.io/i2pd/badge.svg)](https://snapcraft.io/i2pd)
[![License](https://img.shields.io/github/license/PurpleI2P/i2pd.svg)](https://github.com/PurpleI2P/i2pd/blob/openssl/LICENSE) [![License](https://img.shields.io/github/license/PurpleI2P/i2pd.svg)](https://github.com/PurpleI2P/i2pd/blob/openssl/LICENSE)
[![Packaging status](https://repology.org/badge/tiny-repos/i2pd.svg)](https://repology.org/project/i2pd/versions) [![Packaging status](https://repology.org/badge/tiny-repos/i2pd.svg)](https://repology.org/project/i2pd/versions)
[![Docker Pulls](https://img.shields.io/docker/pulls/purplei2p/i2pd)](https://hub.docker.com/r/purplei2p/i2pd)
i2pd i2pd
==== ====
@ -68,7 +69,7 @@ Build instructions:
* Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc. * Alpine, ArchLinux, openSUSE, Gentoo, Debian, Ubuntu, etc.
* Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd) * Windows - [![Build status](https://ci.appveyor.com/api/projects/status/1908qe4p48ff1x23?svg=true)](https://ci.appveyor.com/project/PurpleI2P/i2pd)
* Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd) * Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
* Docker image - [![Build Status](https://dockerbuildbadges.quelltext.eu/status.svg?organization=meeh&repository=i2pd)](https://hub.docker.com/r/meeh/i2pd/builds/) * Docker image - [![Build Status](https://img.shields.io/docker/cloud/build/purplei2p/i2pd)](https://hub.docker.com/r/purplei2p/i2pd/builds/)
* Snap - [![Snap Status](https://build.snapcraft.io/badge/PurpleI2P/i2pd-snap.svg)](https://build.snapcraft.io/user/PurpleI2P/i2pd-snap) * Snap - [![Snap Status](https://build.snapcraft.io/badge/PurpleI2P/i2pd-snap.svg)](https://build.snapcraft.io/user/PurpleI2P/i2pd-snap)
* FreeBSD * FreeBSD
* Android * Android

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <thread> #include <thread>
#include <clocale> #include <clocale>
#include "Config.h" #include "Config.h"
@ -8,6 +16,7 @@
#ifdef _WIN32 #ifdef _WIN32
#include "Win32/Win32Service.h" #include "Win32/Win32Service.h"
#ifdef WIN32_APP #ifdef WIN32_APP
#include <windows.h>
#include "Win32/Win32App.h" #include "Win32/Win32App.h"
#endif #endif
@ -23,6 +32,11 @@ namespace util
setlocale(LC_ALL, "Russian"); setlocale(LC_ALL, "Russian");
setlocale(LC_TIME, "C"); setlocale(LC_TIME, "C");
i2p::log::SetThrowFunction ([](const std::string& s)
{
MessageBox(0, TEXT(s.c_str ()), TEXT("i2pd"), MB_ICONERROR | MB_TASKMODAL | MB_OK );
});
if (!Daemon_Singleton::init(argc, argv)) if (!Daemon_Singleton::init(argc, argv))
return false; return false;

View File

@ -1,3 +1,12 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <stdio.h>
#include <string.h> #include <string.h>
#include <windows.h> #include <windows.h>
#include <shellapi.h> #include <shellapi.h>
@ -11,7 +20,7 @@
#include "resource.h" #include "resource.h"
#include "Daemon.h" #include "Daemon.h"
#include "Win32App.h" #include "Win32App.h"
#include <stdio.h> #include "Win32NetState.h"
#define ID_ABOUT 2000 #define ID_ABOUT 2000
#define ID_EXIT 2001 #define ID_EXIT 2001
@ -338,11 +347,6 @@ namespace win32
PostMessage (hWnd, WM_CLOSE, 0, 0); // exit PostMessage (hWnd, WM_CLOSE, 0, 0); // exit
return 0; return 0;
} }
case FRAME_UPDATE_TIMER:
{
InvalidateRect(hWnd, NULL, TRUE);
return 0;
}
case IDT_GRACEFUL_TUNNELCHECK_TIMER: case IDT_GRACEFUL_TUNNELCHECK_TIMER:
{ {
if (i2p::tunnel::tunnels.CountTransitTunnels() == 0) if (i2p::tunnel::tunnels.CountTransitTunnels() == 0)
@ -351,6 +355,11 @@ namespace win32
SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr);
return 0; return 0;
} }
case FRAME_UPDATE_TIMER:
{
InvalidateRect(hWnd, NULL, TRUE);
return 0;
}
} }
break; break;
} }
@ -411,6 +420,7 @@ namespace win32
MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST); MessageBox(NULL, "Failed to create main window", TEXT("Warning!"), MB_ICONERROR | MB_OK | MB_TOPMOST);
return false; return false;
} }
SubscribeToEvents();
return true; return true;
} }
@ -430,6 +440,7 @@ namespace win32
HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd")); HWND hWnd = FindWindow (I2PD_WIN32_CLASSNAME, TEXT("i2pd"));
if (hWnd) if (hWnd)
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0); PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_EXIT, 0), 0);
// UnSubscribeFromEvents(); // TODO: understand why unsubscribing crashes app
UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL)); UnregisterClass (I2PD_WIN32_CLASSNAME, GetModuleHandle(NULL));
} }
@ -448,6 +459,5 @@ namespace win32
PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_STOP_GRACEFUL_SHUTDOWN, 0), 0); PostMessage (hWnd, WM_COMMAND, MAKEWPARAM(ID_STOP_GRACEFUL_SHUTDOWN, 0), 0);
return hWnd; return hWnd;
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef WIN32APP_H__ #ifndef WIN32APP_H__
#define WIN32APP_H__ #define WIN32APP_H__

86
Win32/Win32NetState.cpp Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#if WINVER != 0x0501 // supported since Vista
#include "Win32NetState.h"
#include <windows.h>
#include "Log.h"
IUnknown *pUnknown = nullptr;
INetworkListManager *pNetworkListManager = nullptr;
IConnectionPointContainer *pCPContainer = nullptr;
IConnectionPoint *pConnectPoint = nullptr;
DWORD Cookie = 0;
void SubscribeToEvents()
{
LogPrint(eLogInfo, "NetState: Trying to subscribe to NetworkListManagerEvents");
CoInitialize(NULL);
HRESULT Result = CoCreateInstance(CLSID_NetworkListManager, NULL, CLSCTX_ALL, IID_IUnknown, (void **)&pUnknown);
if (SUCCEEDED(Result))
{
Result = pUnknown->QueryInterface(IID_INetworkListManager, (void **)&pNetworkListManager);
if (SUCCEEDED(Result))
{
VARIANT_BOOL IsConnect = VARIANT_FALSE;
Result = pNetworkListManager->IsConnectedToInternet(&IsConnect);
if (SUCCEEDED(Result)) {
i2p::transport::transports.SetOnline (true);
LogPrint(eLogInfo, "NetState: current state: ", IsConnect == VARIANT_TRUE ? "connected" : "disconnected");
}
Result = pNetworkListManager->QueryInterface(IID_IConnectionPointContainer, (void **)&pCPContainer);
if (SUCCEEDED(Result))
{
Result = pCPContainer->FindConnectionPoint(IID_INetworkListManagerEvents, &pConnectPoint);
if(SUCCEEDED(Result))
{
CNetworkListManagerEvent *NetEvent = new CNetworkListManagerEvent;
Result = pConnectPoint->Advise((IUnknown *)NetEvent, &Cookie);
if (SUCCEEDED(Result))
LogPrint(eLogInfo, "NetState: Successfully subscribed to NetworkListManagerEvent messages");
else
LogPrint(eLogError, "NetState: Unable to subscribe to NetworkListManagerEvent messages");
} else
LogPrint(eLogError, "NetState: Unable to find interface connection point");
} else
LogPrint(eLogError, "NetState: Unable to query NetworkListManager interface");
} else
LogPrint(eLogError, "NetState: Unable to query global interface");
} else
LogPrint(eLogError, "NetState: Unable to create INetworkListManager interface");
}
void UnSubscribeFromEvents()
{
try
{
if (pConnectPoint) {
pConnectPoint->Unadvise(Cookie);
pConnectPoint->Release();
}
if (pCPContainer)
pCPContainer->Release();
if (pNetworkListManager)
pNetworkListManager->Release();
if (pUnknown)
pUnknown->Release();
CoUninitialize();
}
catch (std::exception& ex)
{
LogPrint (eLogError, "NetState: received exception: ", ex.what ());
}
}
#endif // WINVER

93
Win32/Win32NetState.h Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef WIN_32_NETSTATE_H__
#define WIN_32_NETSTATE_H__
#if WINVER != 0x0501 // supported since Vista
#include <netlistmgr.h>
#include <ocidl.h>
#include "Log.h"
#include "Transports.h"
class CNetworkListManagerEvent : public INetworkListManagerEvents
{
public:
CNetworkListManagerEvent() : m_ref(1) { }
~CNetworkListManagerEvent() { }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
{
HRESULT Result = S_OK;
if (IsEqualIID(riid, IID_IUnknown)) {
*ppvObject = (IUnknown *)this;
} else if (IsEqualIID(riid ,IID_INetworkListManagerEvents)) {
*ppvObject = (INetworkListManagerEvents *)this;
} else {
Result = E_NOINTERFACE;
}
return Result;
}
ULONG STDMETHODCALLTYPE AddRef()
{
return (ULONG)InterlockedIncrement(&m_ref);
}
ULONG STDMETHODCALLTYPE Release()
{
LONG Result = InterlockedDecrement(&m_ref);
if (Result == 0)
delete this;
return (ULONG)Result;
}
virtual HRESULT STDMETHODCALLTYPE ConnectivityChanged(NLM_CONNECTIVITY newConnectivity)
{
if (newConnectivity == NLM_CONNECTIVITY_DISCONNECTED) {
i2p::transport::transports.SetOnline (false);
LogPrint(eLogInfo, "NetState: disconnected from network");
}
if (((int)newConnectivity & (int)NLM_CONNECTIVITY_IPV4_INTERNET) != 0) {
i2p::transport::transports.SetOnline (true);
LogPrint(eLogInfo, "NetState: connected to internet with IPv4 capability");
}
if (((int)newConnectivity & (int)NLM_CONNECTIVITY_IPV6_INTERNET) != 0) {
i2p::transport::transports.SetOnline (true);
LogPrint(eLogInfo, "NetState: connected to internet with IPv6 capability");
}
if (
(((int)newConnectivity & (int)NLM_CONNECTIVITY_IPV4_INTERNET) == 0) &&
(((int)newConnectivity & (int)NLM_CONNECTIVITY_IPV6_INTERNET) == 0)
) {
i2p::transport::transports.SetOnline (false);
LogPrint(eLogInfo, "NetState: connected without internet access");
}
return S_OK;
}
private:
LONG m_ref;
};
void SubscribeToEvents();
void UnSubscribeFromEvents();
#else // WINVER == 0x0501
void SubscribeToEvents() { }
void UnSubscribeFromEvents() { }
#endif // WINVER
#endif

View File

@ -1,10 +1,18 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifdef _WIN32 #ifdef _WIN32
#define _CRT_SECURE_NO_WARNINGS // to use freopen #define _CRT_SECURE_NO_WARNINGS // to use freopen
#endif #endif
#include "Win32Service.h" #include "Win32Service.h"
#include <assert.h> #include <assert.h>
#include <strsafe.h> //#include <strsafe.h>
#include <windows.h> #include <windows.h>
#include "Daemon.h" #include "Daemon.h"

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef WIN_32_SERVICE_H__ #ifndef WIN_32_SERVICE_H__
#define WIN_32_SERVICE_H__ #define WIN_32_SERVICE_H__
@ -26,7 +34,7 @@
class I2PService class I2PService
{ {
public: public:
I2PService(PSTR pszServiceName, I2PService(PSTR pszServiceName,
BOOL fCanStop = TRUE, BOOL fCanStop = TRUE,
@ -39,7 +47,7 @@ public:
static BOOL Run(I2PService &service); static BOOL Run(I2PService &service);
void Stop(); void Stop();
protected: protected:
virtual void OnStart(DWORD dwArgc, PSTR *pszArgv); virtual void OnStart(DWORD dwArgc, PSTR *pszArgv);
virtual void OnStop(); virtual void OnStop();
@ -50,7 +58,7 @@ protected:
DWORD dwWin32ExitCode = NO_ERROR, DWORD dwWin32ExitCode = NO_ERROR,
DWORD dwWaitHint = 0); DWORD dwWaitHint = 0);
private: private:
static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv); static void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv);
static void WINAPI ServiceCtrlHandler(DWORD dwCtrl); static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);
@ -77,7 +85,7 @@ void InstallService(
PCSTR pszDependencies, PCSTR pszDependencies,
PCSTR pszAccount, PCSTR pszAccount,
PCSTR pszPassword PCSTR pszPassword
); );
void UninstallService(PCSTR pszServiceName); void UninstallService(PCSTR pszServiceName);

View File

@ -1,5 +1,5 @@
#define I2Pd_AppName "i2pd" #define I2Pd_AppName "i2pd"
#define I2Pd_ver "2.30.0" #define I2Pd_ver "2.32.0"
#define I2Pd_Publisher "PurpleI2P" #define I2Pd_Publisher "PurpleI2P"
[Setup] [Setup]

2
android/.gitignore vendored
View File

@ -4,6 +4,7 @@ bin
libs libs
log* log*
obj obj
.cxx
.gradle .gradle
.idea .idea
.externalNativeBuild .externalNativeBuild
@ -14,3 +15,4 @@ android.iml
build build
*.iml *.iml
*.local *.local
*.jks

View File

@ -19,6 +19,7 @@
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
> >
<receiver android:name=".NetworkStateChangeReceiver"> <receiver android:name=".NetworkStateChangeReceiver">
<intent-filter> <intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
@ -30,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" />

View File

@ -42,6 +42,8 @@ inbound.quantity = 5
outbound.length = 1 outbound.length = 1
outbound.quantity = 5 outbound.quantity = 5
signaturetype=7 signaturetype=7
i2cp.leaseSetType=3
i2cp.leaseSetEncType=0,4
keys = proxy-keys.dat keys = proxy-keys.dat
# addresshelper = true # addresshelper = true
# outproxy = http://false.i2p # outproxy = http://false.i2p

View File

@ -30,8 +30,8 @@ android {
applicationId "org.purplei2p.i2pd" applicationId "org.purplei2p.i2pd"
targetSdkVersion 29 targetSdkVersion 29
minSdkVersion 14 minSdkVersion 14
versionCode 2300 versionCode 2320
versionName "2.30.0" versionName "2.32.0"
setProperty("archivesBaseName", archivesBaseName + "-" + versionName) setProperty("archivesBaseName", archivesBaseName + "-" + versionName)
ndk { ndk {
abiFilters 'armeabi-v7a' abiFilters 'armeabi-v7a'

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
#include <thread> #include <thread>

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef DAEMON_ANDROID_H #ifndef DAEMON_ANDROID_H
#define DAEMON_ANDROID_H #define DAEMON_ANDROID_H

View File

@ -1,8 +1,18 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <jni.h> #include <jni.h>
#include "org_purplei2p_i2pd_I2PD_JNI.h" #include "org_purplei2p_i2pd_I2PD_JNI.h"
#include "DaemonAndroid.h" #include "DaemonAndroid.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "ClientContext.h"
#include "Transports.h" #include "Transports.h"
#include "Tunnel.h"
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith
(JNIEnv *env, jclass clazz) { (JNIEnv *env, jclass clazz) {
@ -61,6 +71,11 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels
i2p::context.SetAcceptsTunnels (true); i2p::context.SetAcceptsTunnels (true);
} }
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_reloadTunnelsConfigs
(JNIEnv *env, jclass clazz) {
i2p::client::context.ReloadConfig();
}
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
(JNIEnv *env, jclass clazz, jboolean isConnected) { (JNIEnv *env, jclass clazz, jboolean isConnected) {
bool isConnectedBool = (bool) isConnected; bool isConnectedBool = (bool) isConnected;
@ -92,3 +107,8 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setDataDir
// Set DataDir // Set DataDir
i2p::android::SetDataDir(dataDir); i2p::android::SetDataDir(dataDir);
} }
JNIEXPORT jint JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_GetTransitTunnelsCount
(JNIEnv *env, jclass clazz) {
return i2p::tunnel::tunnels.CountTransitTunnels();
}

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
/* DO NOT EDIT THIS FILE - it is machine generated */ /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> #include <jni.h>
/* Header for class org_purplei2p_i2pd_I2PD_JNI */ /* Header for class org_purplei2p_i2pd_I2PD_JNI */
@ -27,12 +35,18 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels
(JNIEnv *, jclass); (JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_reloadTunnelsConfigs
(JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
(JNIEnv * env, jclass clazz, jboolean isConnected); (JNIEnv * env, jclass clazz, jboolean isConnected);
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setDataDir JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setDataDir
(JNIEnv *env, jclass clazz, jstring jdataDir); (JNIEnv *env, jclass clazz, jstring jdataDir);
JNIEXPORT jint JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_GetTransitTunnelsCount
(JNIEnv *, jclass);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -15,13 +15,12 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/horizontal_page_margin" android:layout_marginBottom="@dimen/horizontal_page_margin"
android:visibility="gone" android:visibility="gone" />
/>
<Button <Button
android:id="@+id/button_request_write_ext_storage_perms" android:id="@+id/button_request_write_ext_storage_perms"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Retry requesting the SD card write permissions" android:text="@string/retryPermRequest"
android:visibility="gone"/> android:visibility="gone" />
</LinearLayout> </LinearLayout>

View File

@ -15,13 +15,11 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/horizontal_page_margin" android:layout_marginBottom="@dimen/horizontal_page_margin"
android:text="SD card write access is required to write the keys and other files to the I2PD folder on SD card." android:text="@string/permRequired" />
/>
<Button <Button
android:id="@+id/button_ok" android:id="@+id/button_ok"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="OK" android:text="@string/ok" />
/>
</LinearLayout> </LinearLayout>

View File

@ -5,9 +5,8 @@
android:layout_height="fill_parent" android:layout_height="fill_parent"
tools:context=".I2PDActivity"> tools:context=".I2PDActivity">
<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>

View File

@ -3,23 +3,29 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:context=".I2PDActivity"> tools:context=".I2PDActivity">
<group android:id="@+id/group_i2pd_control" >
<group android:id="@+id/group_various">
<item <item
android:id="@+id/action_stop" android:id="@+id/action_battery_otimizations"
android:orderInCategory="99" android:title="@string/menu_item_battery_optimizations_str" />
android:title="@string/action_stop" /> </group>
<group android:id="@+id/group_i2pd_control">
<item
android:id="@+id/action_start_webview"
android:orderInCategory="96"
android:title="@string/action_start_webview" />
<item
android:id="@+id/action_reload_tunnels_config"
android:orderInCategory="97"
android:title="@string/action_reload_tunnels_config" />
<item <item
android:id="@+id/action_graceful_stop" android:id="@+id/action_graceful_stop"
android:orderInCategory="98" android:orderInCategory="98"
android:title="@string/action_graceful_stop" /> android:title="@string/action_graceful_stop" />
<item <item
android:id="@+id/action_start_webview" android:id="@+id/action_stop"
android:orderInCategory="97" android:orderInCategory="99"
android:title="@string/action_start_webview" /> android:title="@string/action_stop" />
</group>
<group android:id="@+id/group_various" >
<item
android:id="@+id/action_battery_otimizations"
android:title="@string/menu_item_battery_optimizations_str" />
</group> </group>
</menu> </menu>

View File

@ -1,28 +1,40 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="app_name">i2pd</string> <string name="app_name">i2pd</string>
<string name="action_stop">Остановить</string> <string name="action_stop">Остановить</string>
<string name="action_graceful_stop">Корректная остановка</string> <string name="action_graceful_stop">Корректная остановка</string>
<string name="action_cancel_graceful_stop">Отменить корректную остановку</string> <string name="action_cancel_graceful_stop">Отменить корректную остановку</string>
<string name="action_reload_tunnels_config">Перезагрузить туннели</string>
<string name="action_start_webview">Открыть Веб Консоль</string>
<string name="graceful_stop_is_already_in_progress">Корректная остановка уже запущена</string> <string name="graceful_stop_is_already_in_progress">Корректная остановка уже запущена</string>
<string name="graceful_stop_is_in_progress">Корректная остановка запущена</string> <string name="graceful_stop_is_in_progress">Корректная остановка запущена</string>
<string name="gracefulShutdownInProgress">Корректная остановка запущена</string>
<string name="already_stopped">Уже остановлено</string> <string name="already_stopped">Уже остановлено</string>
<string name="uninitialized">Приложение инициализируется</string> <string name="uninitialized">Приложение инициализируется</string>
<string name="starting">Приложение запускается</string> <string name="starting">Приложение запускается</string>
<string name="jniLibraryLoaded">Загружены JNI библиотеки</string> <string name="jniLibraryLoaded">Загружены JNI библиотеки</string>
<string name="startedOkay">Приложение запущено</string> <string name="startedOkay">Приложение запущено</string>
<string name="startFailed">Запуск не удался</string> <string name="startFailed">Запуск не удался</string>
<string name="gracefulShutdownInProgress">Корректная остановка запущена</string>
<string name="stopped">Приложение было остановлено</string> <string name="stopped">Приложение было остановлено</string>
<string name="remaining">осталось</string> <string name="remaining">осталось</string>
<string name="title_activity_i2_pdperms_asker_prompt">Запрос</string> <string name="title_activity_i2_pdperms_asker_prompt">Запрос</string>
<string name="permDenied">Права для записи на SD карту отклонены, вам необходимо предоставить их для продолжения</string> <string name="permDenied">Права для записи на SD карту отклонены, вам необходимо предоставить их для продолжения</string>
<string name="permRequired">Права на запись на SD карту необходимы для записи ключей и других файлов в папку I2PD на внутренней памяти.</string>
<string name="retryPermRequest">Повторить запрос прав на запись на SD карту</string>
<string name="menu_item_battery_optimizations_str">Оптимизации аккумулятора</string> <string name="menu_item_battery_optimizations_str">Оптимизации аккумулятора</string>
<string name="battery_optimizations_enabled">Оптимизации аккумулятора включены</string> <string name="battery_optimizations_enabled">Оптимизации аккумулятора включены</string>
<string name="device_does_not_support_disabling_battery_optimizations">Ваша версия Андроид не поддерживает отключение оптимизаций аккумулятора</string>
<string name="battery_optimizations_enabled_explained">Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\nРекомендуется отключить эти оптимизации.</string> <string name="battery_optimizations_enabled_explained">Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\nРекомендуется отключить эти оптимизации.</string>
<string name="battery_optimizations_enabled_dialog" >Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\n\nВам сейчас будет предложено разрешить отключение этих оптимизаций.</string> <string name="battery_optimizations_enabled_dialog">Ваша операционная система осуществляет оптимизации расхода аккумулятора, которые могут приводить к выгрузке I2PD из памяти и прекращению его работы с целью сэкономить заряд аккумулятора.\n\nВам сейчас будет предложено разрешить отключение этих оптимизаций.</string>
<string name="continue_str">Продолжить</string> <string name="continue_str">Продолжить</string>
<string name="device_does_not_support_disabling_battery_optimizations">Ваша версия Андроид не поддерживает отключение оптимизаций аккумулятора</string>
<string name="os_version_does_not_support_battery_optimizations_show_os_dialog_api">Ваша версия Андроид не поддерживает показ диалога об оптимизациях аккумулятора для приложений.</string> <string name="os_version_does_not_support_battery_optimizations_show_os_dialog_api">Ваша версия Андроид не поддерживает показ диалога об оптимизациях аккумулятора для приложений.</string>
<string name="shutdown_canceled">Плановая остановка отменена</string> <string name="shutdown_canceled">Плановая остановка отменена</string>
<string name="tunnels_reloading">Перезагрузка конфигурации туннелей...</string>
</resources> </resources>

View File

@ -1,29 +1,41 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_name">i2pd</string> <string name="app_name">i2pd</string>
<string name="action_stop">Stop</string> <string name="action_stop">Stop</string>
<string name="action_graceful_stop">Graceful Stop</string> <string name="action_graceful_stop">Graceful Stop</string>
<string name="action_cancel_graceful_stop">Cancel Graceful Stop</string> <string name="action_cancel_graceful_stop">Cancel Graceful Stop</string>
<string name="action_reload_tunnels_config">Reload tunnels</string>
<string name="action_start_webview">Open Web Console</string>
<string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string> <string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string>
<string name="graceful_stop_is_in_progress">Graceful stop is in progress</string> <string name="graceful_stop_is_in_progress">Graceful stop is in progress</string>
<string name="gracefulShutdownInProgress">Graceful shutdown in progress</string>
<string name="already_stopped">Already stopped</string> <string name="already_stopped">Already stopped</string>
<string name="uninitialized">Application initializing</string> <string name="uninitialized">Application initializing</string>
<string name="starting">Application starting</string> <string name="starting">Application starting</string>
<string name="jniLibraryLoaded">Loaded JNI libraries</string> <string name="jniLibraryLoaded">Loaded JNI libraries</string>
<string name="startedOkay">Application Started</string> <string name="startedOkay">Application Started</string>
<string name="startFailed">Start failed</string> <string name="startFailed">Start failed</string>
<string name="gracefulShutdownInProgress">Graceful shutdown in progress</string>
<string name="stopped">Application stopped</string> <string name="stopped">Application stopped</string>
<string name="remaining">remaining</string> <string name="remaining">remaining</string>
<string name="ok">OK</string>
<string name="title_activity_i2_pdperms_asker_prompt">Prompt</string> <string name="title_activity_i2_pdperms_asker_prompt">Prompt</string>
<string name="permDenied">SD card write permission denied, you need to allow this to continue</string> <string name="permDenied">SD card write permission denied, you need to allow this to continue</string>
<string name="permRequired">SD card write access is required to write the keys and other files to the I2PD folder on SD card.</string>
<string name="retryPermRequest">Retry requesting the SD card write permissions</string>
<string name="menu_item_battery_optimizations_str">Battery Optimizations</string>
<string name="battery_optimizations_enabled">Battery optimizations enabled</string> <string name="battery_optimizations_enabled">Battery optimizations enabled</string>
<string name="battery_optimizations_enabled_explained">Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\nIt is recommended to allow disabling those battery optimizations.</string> <string name="battery_optimizations_enabled_explained">Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\nIt is recommended to allow disabling those battery optimizations.</string>
<string name="battery_optimizations_enabled_dialog" >Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\n\nYou will now be asked to allow to disable those.</string> <string name="battery_optimizations_enabled_dialog">Your Android is doing some heavy battery optimizations on I2PD that might lead to daemon closing with no other reason.\n\nYou will now be asked to allow to disable those.</string>
<string name="continue_str">Continue</string> <string name="continue_str">Continue</string>
<string name="device_does_not_support_disabling_battery_optimizations">Your Android version does not support opting out of battery optimizations</string> <string name="device_does_not_support_disabling_battery_optimizations">Your Android version does not support opting out of battery optimizations</string>
<string name="menu_item_battery_optimizations_str">Battery Optimizations</string>
<string name="os_version_does_not_support_battery_optimizations_show_os_dialog_api">Your Android OS version does not support showing the dialog for battery optimizations for applications.</string> <string name="os_version_does_not_support_battery_optimizations_show_os_dialog_api">Your Android OS version does not support showing the dialog for battery optimizations for applications.</string>
<string name="shutdown_canceled">Planned shutdown canceled</string> <string name="shutdown_canceled">Planned shutdown canceled</string>
<string name="action_start_webview">Start webview</string>
<string name="tunnels_reloading">Reloading tunnels config...</string>
</resources> </resources>

View File

@ -10,36 +10,65 @@ import org.purplei2p.i2pd.R;
public class DaemonSingleton { public class DaemonSingleton {
private static final String TAG = "i2pd"; private static final String TAG = "i2pd";
private static final DaemonSingleton instance = new DaemonSingleton(); private static final DaemonSingleton instance = new DaemonSingleton();
public interface StateUpdateListener { void daemonStateUpdate(); }
public interface StateUpdateListener {
void daemonStateUpdate();
}
private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>(); private final Set<StateUpdateListener> stateUpdateListeners = new HashSet<>();
public static DaemonSingleton getInstance() { return instance; } public static DaemonSingleton getInstance() {
return instance;
}
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } public synchronized void addStateChangeListener(StateUpdateListener listener) {
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } stateUpdateListeners.add(listener);
}
public synchronized void removeStateChangeListener(StateUpdateListener listener) {
stateUpdateListeners.remove(listener);
}
private synchronized void setState(State newState) { private synchronized void setState(State newState) {
if(newState==null)throw new NullPointerException(); if (newState == null)
throw new NullPointerException();
State oldState = state; State oldState = state;
if(oldState==null)throw new NullPointerException();
if(oldState.equals(newState))return; if (oldState == null)
state=newState; throw new NullPointerException();
if (oldState.equals(newState))
return;
state = newState;
fireStateUpdate1(); fireStateUpdate1();
} }
public synchronized void stopAcceptingTunnels() { public synchronized void stopAcceptingTunnels() {
if(isStartedOkay()){ if (isStartedOkay()) {
setState(State.gracefulShutdownInProgress); setState(State.gracefulShutdownInProgress);
I2PD_JNI.stopAcceptingTunnels(); I2PD_JNI.stopAcceptingTunnels();
} }
} }
public synchronized void startAcceptingTunnels() { public synchronized void startAcceptingTunnels() {
if(isStartedOkay()){ if (isStartedOkay()) {
setState(State.startedOkay); setState(State.startedOkay);
I2PD_JNI.startAcceptingTunnels(); I2PD_JNI.startAcceptingTunnels();
} }
} }
public synchronized void reloadTunnelsConfigs() {
if (isStartedOkay()) {
I2PD_JNI.reloadTunnelsConfigs();
}
}
public synchronized int GetTransitTunnelsCount() {
return I2PD_JNI.GetTransitTunnelsCount();
}
private volatile boolean startedOkay; private volatile boolean startedOkay;
public enum State { public enum State {
@ -64,11 +93,13 @@ public class DaemonSingleton {
private volatile State state = State.uninitialized; private volatile State state = State.uninitialized;
public State getState() { return state; } public State getState() {
return state;
}
{ {
setState(State.starting); setState(State.starting);
new Thread(new Runnable(){ new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
@ -76,7 +107,7 @@ public class DaemonSingleton {
I2PD_JNI.loadLibraries(); I2PD_JNI.loadLibraries();
setState(State.jniLibraryLoaded); setState(State.jniLibraryLoaded);
} catch (Throwable tr) { } catch (Throwable tr) {
lastThrowable=tr; lastThrowable = tr;
setState(State.startFailed); setState(State.startFailed);
return; return;
} }
@ -84,25 +115,27 @@ public class DaemonSingleton {
synchronized (DaemonSingleton.this) { synchronized (DaemonSingleton.this) {
I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd"); I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd");
daemonStartResult = I2PD_JNI.startDaemon(); daemonStartResult = I2PD_JNI.startDaemon();
if("ok".equals(daemonStartResult)){ if ("ok".equals(daemonStartResult)) {
setState(State.startedOkay); setState(State.startedOkay);
setStartedOkay(true); setStartedOkay(true);
}else setState(State.startFailed); } else
setState(State.startFailed);
} }
} catch (Throwable tr) { } catch (Throwable tr) {
lastThrowable=tr; lastThrowable = tr;
setState(State.startFailed); setState(State.startFailed);
} }
} }
}, "i2pdDaemonStart").start(); }, "i2pdDaemonStart").start();
} }
private Throwable lastThrowable; private Throwable lastThrowable;
private String daemonStartResult="N/A"; private String daemonStartResult = "N/A";
private void fireStateUpdate1() { private void fireStateUpdate1() {
Log.i(TAG, "daemon state change: "+state); Log.i(TAG, "daemon state change: " + state);
for(StateUpdateListener listener : stateUpdateListeners) { for (StateUpdateListener listener : stateUpdateListeners) {
try { try {
listener.daemonStateUpdate(); listener.daemonStateUpdate();
} catch (Throwable tr) { } catch (Throwable tr) {
@ -134,8 +167,13 @@ public class DaemonSingleton {
} }
public synchronized void stopDaemon() { public synchronized void stopDaemon() {
if(isStartedOkay()){ if (isStartedOkay()) {
try {I2PD_JNI.stopDaemon();}catch(Throwable tr){Log.e(TAG, "", tr);} try {
I2PD_JNI.stopDaemon();
} catch(Throwable tr) {
Log.e(TAG, "", tr);
}
setStartedOkay(false); setStartedOkay(false);
setState(State.stopped); setState(State.stopped);
} }

View File

@ -68,17 +68,16 @@ public class I2PDActivity extends Activity {
private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton.StateUpdateListener() {
new DaemonSingleton.StateUpdateListener() {
@Override @Override
public void daemonStateUpdate() public void daemonStateUpdate() {
{
processAssets(); processAssets();
runOnUiThread(() -> { runOnUiThread(() -> {
try { try {
if(textView==null) return; if (textView == null)
return;
Throwable tr = daemon.getLastThrowable(); Throwable tr = daemon.getLastThrowable();
if(tr!=null) { if (tr!=null) {
textView.setText(throwableToString(tr)); textView.setText(throwableToString(tr));
return; return;
} }
@ -93,17 +92,17 @@ public class I2PDActivity extends Activity {
} }
}; };
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;
private static String formatGraceTimeRemaining() { private static String formatGraceTimeRemaining() {
long remainingSeconds; long remainingSeconds;
synchronized (graceStartedMillis_LOCK){ synchronized (graceStartedMillis_LOCK) {
remainingSeconds=Math.round(Math.max(0,graceStartedMillis+GRACEFUL_DELAY_MILLIS-System.currentTimeMillis())/1000.0D); remainingSeconds = Math.round(Math.max(0, graceStartedMillis + GRACEFUL_DELAY_MILLIS - System.currentTimeMillis()) / 1000.0D);
} }
long remainingMinutes=(long)Math.floor(remainingSeconds/60.0D); long remainingMinutes = (long)Math.floor(remainingSeconds / 60.0D);
long remSec=remainingSeconds-remainingMinutes*60; long remSec = remainingSeconds - remainingMinutes * 60;
return remainingMinutes+":"+(remSec/10)+remSec%10; return remainingMinutes + ":" + (remSec / 10) + remSec % 10;
} }
@Override @Override
@ -117,10 +116,8 @@ public class I2PDActivity extends Activity {
daemonStateUpdatedListener.daemonStateUpdate(); daemonStateUpdatedListener.daemonStateUpdate();
// request permissions // request permissions
if (Build.VERSION.SDK_INT >= 23) if (Build.VERSION.SDK_INT >= 23) {
{ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this, ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE); MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
@ -131,7 +128,7 @@ public class I2PDActivity extends Activity {
doBindService(); doBindService();
final Timer gracefulQuitTimer = getGracefulQuitTimer(); final Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null){ if (gracefulQuitTimer != null) {
long gracefulStopAtMillis; long gracefulStopAtMillis;
synchronized (graceStartedMillis_LOCK) { synchronized (graceStartedMillis_LOCK) {
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
@ -148,9 +145,9 @@ public class I2PDActivity extends Activity {
textView = null; textView = null;
daemon.removeStateChangeListener(daemonStateUpdatedListener); daemon.removeStateChangeListener(daemonStateUpdatedListener);
//cancelGracefulStop0(); //cancelGracefulStop0();
try{ try {
doUnbindService(); doUnbindService();
}catch(Throwable tr){ } catch(Throwable tr) {
Log.e(TAG, "", tr); Log.e(TAG, "", tr);
} }
} }
@ -171,7 +168,7 @@ public class I2PDActivity extends Activity {
private void cancelGracefulStop0() { private void cancelGracefulStop0() {
Timer gracefulQuitTimer = getGracefulQuitTimer(); Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null) { if (gracefulQuitTimer != null) {
gracefulQuitTimer.cancel(); gracefulQuitTimer.cancel();
setGracefulQuitTimer(null); setGracefulQuitTimer(null);
} }
@ -216,7 +213,8 @@ public class I2PDActivity extends Activity {
private void doBindService() { private void doBindService() {
synchronized (I2PDActivity.class) { synchronized (I2PDActivity.class) {
if (mIsBound) return; if (mIsBound)
return;
// Establish a connection with the service. We use an explicit // Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that // class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be // we know will be running in our own process (and thus won't be
@ -256,10 +254,11 @@ public class I2PDActivity extends Activity {
// as you specify a parent activity in AndroidManifest.xml. // as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); int id = item.getItemId();
switch(id){ switch(id) {
case R.id.action_stop: case R.id.action_stop:
i2pdStop(); i2pdStop();
return true; return true;
case R.id.action_graceful_stop: case R.id.action_graceful_stop:
synchronized (graceStartedMillis_LOCK) { synchronized (graceStartedMillis_LOCK) {
if (getGracefulQuitTimer() != null) if (getGracefulQuitTimer() != null)
@ -268,9 +267,15 @@ public class I2PDActivity extends Activity {
i2pdGracefulStop(); i2pdGracefulStop();
} }
return true; return true;
case R.id.action_battery_otimizations: case R.id.action_battery_otimizations:
onActionBatteryOptimizations(); onActionBatteryOptimizations();
return true; return true;
case R.id.action_reload_tunnels_config:
onReloadTunnelsConfig();
return true;
case R.id.action_start_webview: case R.id.action_start_webview:
setContentView(R.layout.webview); setContentView(R.layout.webview);
this.webView = (WebView) findViewById(R.id.webview1); this.webView = (WebView) findViewById(R.id.webview1);
@ -291,12 +296,18 @@ public class I2PDActivity extends Activity {
try { try {
startActivity(new Intent(ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)); startActivity(new Intent(ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS));
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
Log.e(TAG,"BATT_OPTIM_DIALOG_ActvtNotFound", e); Log.e(TAG, "BATT_OPTIM_DIALOG_ActvtNotFound", e);
Toast.makeText(this, R.string.os_version_does_not_support_battery_optimizations_show_os_dialog_api, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.os_version_does_not_support_battery_optimizations_show_os_dialog_api, Toast.LENGTH_SHORT).show();
} }
} }
} }
private void onReloadTunnelsConfig() {
Log.d(TAG, "reloading tunnels");
daemon.reloadTunnelsConfigs();
Toast.makeText(this, R.string.tunnels_reloading, Toast.LENGTH_SHORT).show();
}
private void i2pdStop() { private void i2pdStop() {
cancelGracefulStop0(); cancelGracefulStop0();
new Thread(() -> { new Thread(() -> {
@ -307,84 +318,83 @@ public class I2PDActivity extends Activity {
Log.e(TAG, "", tr); Log.e(TAG, "", tr);
} }
quit(); //TODO make menu items for starting i2pd. On my Android, I need to reboot the OS to restart i2pd. quit(); //TODO make menu items for starting i2pd. On my Android, I need to reboot the OS to restart i2pd.
},"stop").start(); }, "stop").start();
} }
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() == DaemonSingleton.State.stopped) {
Toast.makeText(this, R.string.already_stopped, Toast.makeText(this, R.string.already_stopped, Toast.LENGTH_SHORT).show();
Toast.LENGTH_SHORT).show();
return; return;
} }
if(getGracefulQuitTimer()!=null){ if (getGracefulQuitTimer() != null) {
Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, Toast.makeText(this, R.string.graceful_stop_is_already_in_progress, Toast.LENGTH_SHORT).show();
Toast.LENGTH_SHORT).show();
return; return;
} }
Toast.makeText(this, R.string.graceful_stop_is_in_progress, Toast.makeText(this, R.string.graceful_stop_is_in_progress, Toast.LENGTH_SHORT).show();
Toast.LENGTH_SHORT).show();
new Thread(() -> { new Thread(() -> {
try { try {
Log.d(TAG, "grac stopping"); Log.d(TAG, "graceful stopping");
if(daemon.isStartedOkay()) { if (daemon.isStartedOkay()) {
daemon.stopAcceptingTunnels(); daemon.stopAcceptingTunnels();
long gracefulStopAtMillis; long gracefulStopAtMillis;
synchronized (graceStartedMillis_LOCK) { synchronized (graceStartedMillis_LOCK) {
graceStartedMillis = System.currentTimeMillis(); graceStartedMillis = System.currentTimeMillis();
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS; gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS;
} }
rescheduleGraceStop(null,gracefulStopAtMillis); rescheduleGraceStop(null, gracefulStopAtMillis);
} else { } else
i2pdStop(); i2pdStop();
}
} catch(Throwable tr) { } catch(Throwable tr) {
Log.e(TAG,"",tr); Log.e(TAG, "", tr);
} }
},"gracInit").start(); }, "gracInit").start();
} }
private void cancelGracefulStop() private void cancelGracefulStop()
{ {
cancelGracefulStop0(); cancelGracefulStop0();
new Thread(() -> { new Thread(() -> {
try try {
{ Log.d(TAG, "canceling graceful stop");
Log.d(TAG, "canceling grac stop"); if (daemon.isStartedOkay()) {
if(daemon.isStartedOkay()) {
daemon.startAcceptingTunnels(); daemon.startAcceptingTunnels();
runOnUiThread(() -> Toast.makeText(this, R.string.shutdown_canceled, Toast.LENGTH_SHORT).show()); runOnUiThread(() -> Toast.makeText(this, R.string.shutdown_canceled, Toast.LENGTH_SHORT).show());
} } else
else
i2pdStop(); i2pdStop();
} catch(Throwable tr) {
Log.e(TAG, "", tr);
} }
catch(Throwable tr) }, "gracCancel").start();
{
Log.e(TAG,"",tr);
}
},"gracCancel").start();
} }
private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) {
if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); if (gracefulQuitTimerOld != null)
gracefulQuitTimerOld.cancel();
if(daemon.GetTransitTunnelsCount() <= 0) { // no tunnels left
Log.d(TAG, "no transit tunnels left, stopping");
i2pdStop();
}
final Timer gracefulQuitTimer = new Timer(true); final Timer gracefulQuitTimer = new Timer(true);
setGracefulQuitTimer(gracefulQuitTimer); setGracefulQuitTimer(gracefulQuitTimer);
gracefulQuitTimer.schedule(new TimerTask(){ gracefulQuitTimer.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
i2pdStop(); i2pdStop();
} }
}, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); }, Math.max(0, gracefulStopAtMillis - System.currentTimeMillis()));
final TimerTask tickerTask = new TimerTask() { final TimerTask tickerTask = new TimerTask() {
@Override @Override
public void run() { public void run() {
daemonStateUpdatedListener.daemonStateUpdate(); daemonStateUpdatedListener.daemonStateUpdate();
} }
}; };
gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); gracefulQuitTimer.scheduleAtFixedRate(tickerTask, 0/*start delay*/, 1000/*millis period*/);
} }
private static Timer getGracefulQuitTimer() { private static Timer getGracefulQuitTimer() {
@ -454,9 +464,9 @@ public class I2PDActivity extends Activity {
*/ */
private void copyFileAsset(String path) { private void copyFileAsset(String path) {
File file = new File(i2pdpath, path); File file = new File(i2pdpath, path);
if(!file.exists()) { if (!file.exists()) {
try { try {
try (InputStream in = getAssets().open(path) ) { try (InputStream in = getAssets().open(path)) {
try (OutputStream out = new FileOutputStream(file)) { try (OutputStream out = new FileOutputStream(file)) {
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
int read = in.read(buffer); int read = in.read(buffer);
@ -475,18 +485,20 @@ public class I2PDActivity extends Activity {
private void deleteRecursive(File fileOrDirectory) { private void deleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) { if (fileOrDirectory.isDirectory()) {
File[] files = fileOrDirectory.listFiles(); File[] files = fileOrDirectory.listFiles();
if(files!=null) { if (files != null) {
for (File child : files) { for (File child : files) {
deleteRecursive(child); deleteRecursive(child);
} }
} }
} }
boolean deleteResult = fileOrDirectory.delete(); boolean deleteResult = fileOrDirectory.delete();
if(!deleteResult)Log.e(TAG, "fileOrDirectory.delete() returned "+deleteResult+", absolute path='"+fileOrDirectory.getAbsolutePath()+"'"); if (!deleteResult)
Log.e(TAG, "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory.getAbsolutePath() + "'");
} }
private void processAssets() { private void processAssets() {
if (!assetsCopied) try { if (!assetsCopied) {
try {
assetsCopied = true; // prevent from running on every state update assetsCopied = true; // prevent from running on every state update
File holderFile = new File(i2pdpath, "assets.ready"); File holderFile = new File(i2pdpath, "assets.ready");
@ -507,14 +519,14 @@ public class I2PDActivity extends Activity {
text.append(line); text.append(line);
} }
}finally { }finally {
try{ try {
br.close(); br.close();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "", e); Log.e(TAG, "", e);
} }
} }
} finally { } finally {
try{ try {
fileReader.close(); fileReader.close();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "", e); Log.e(TAG, "", e);
@ -526,9 +538,11 @@ public class I2PDActivity extends Activity {
} }
// if version differs from current app version or null, try to delete certificates folder // if version differs from current app version or null, try to delete certificates folder
if (!text.toString().contains(versionName)) try { if (!text.toString().contains(versionName))
try {
boolean deleteResult = holderFile.delete(); boolean deleteResult = holderFile.delete();
if(!deleteResult)Log.e(TAG, "holderFile.delete() returned "+deleteResult+", absolute path='"+holderFile.getAbsolutePath()+"'"); if (!deleteResult)
Log.e(TAG, "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile.getAbsolutePath() + "'");
File certPath = new File(i2pdpath, "certificates"); File certPath = new File(i2pdpath, "certificates");
deleteRecursive(certPath); deleteRecursive(certPath);
} }
@ -549,9 +563,9 @@ public class I2PDActivity extends Activity {
try { try {
writer.append(versionName); writer.append(versionName);
} finally { } finally {
try{ try {
writer.close(); writer.close();
}catch (IOException e){ } catch (IOException e) {
Log.e(TAG,"on writer close", e); Log.e(TAG,"on writer close", e);
} }
} }
@ -561,11 +575,12 @@ public class I2PDActivity extends Activity {
Log.e(TAG,"on assets copying", 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);
Log.i(TAG,"BATT_OPTIM_questionEnabled=="+questionEnabled); Log.i(TAG, "BATT_OPTIM_questionEnabled==" + questionEnabled);
if (!isKnownIgnoringBatteryOptimizations() if (!isKnownIgnoringBatteryOptimizations()
&& android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M
&& questionEnabled) { && questionEnabled) {
@ -576,7 +591,7 @@ public class I2PDActivity extends Activity {
try { try {
startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse(PACKAGE_URI_SCHEME + getPackageName()))); startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse(PACKAGE_URI_SCHEME + getPackageName())));
} catch (ActivityNotFoundException e) { } catch (ActivityNotFoundException e) {
Log.e(TAG,"BATT_OPTIM_ActvtNotFound", e); Log.e(TAG, "BATT_OPTIM_ActvtNotFound", e);
Toast.makeText(this, R.string.device_does_not_support_disabling_battery_optimizations, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.device_does_not_support_disabling_battery_optimizations, Toast.LENGTH_SHORT).show();
} }
}); });
@ -602,7 +617,7 @@ public class I2PDActivity extends Activity {
Log.i(TAG, "BATT_OPTIM: ignoring==" + ignoring); Log.i(TAG, "BATT_OPTIM: ignoring==" + ignoring);
return ignoring; return ignoring;
} else { } else {
Log.i(TAG, "BATT_OPTIM: old sdk version=="+Build.VERSION.SDK_INT); Log.i(TAG, "BATT_OPTIM: old sdk version==" + Build.VERSION.SDK_INT);
return false; return false;
} }
} }
@ -626,12 +641,12 @@ public class I2PDActivity extends Activity {
//moveTaskToBack(true); //moveTaskToBack(true);
finish(); finish();
} }
}catch (Throwable tr) { } catch (Throwable tr) {
Log.e(TAG, "", tr); Log.e(TAG, "", tr);
} }
try{ try {
daemon.stopDaemon(); daemon.stopDaemon();
}catch (Throwable tr) { } catch (Throwable tr) {
Log.e(TAG, "", tr); Log.e(TAG, "", tr);
} }
System.exit(0); System.exit(0);

View File

@ -16,10 +16,14 @@ public class I2PD_JNI {
public static native void startAcceptingTunnels(); public static native void startAcceptingTunnels();
public static native void reloadTunnelsConfigs();
public static native void onNetworkStateChanged(boolean isConnected); public static native void onNetworkStateChanged(boolean isConnected);
public static native void setDataDir(String jdataDir); public static native void setDataDir(String jdataDir);
public static native int GetTransitTunnelsCount();
public static void loadLibraries() { public static void loadLibraries() {
//System.loadLibrary("c++_shared"); //System.loadLibrary("c++_shared");
System.loadLibrary("i2pd"); System.loadLibrary("i2pd");

View File

@ -1,4 +1,4 @@
version: 2.30.0.{build} version: 2.32.0.{build}
pull_requests: pull_requests:
do_not_increment_build_number: true do_not_increment_build_number: true
branches: branches:
@ -14,34 +14,25 @@ environment:
CHERE_INVOKING: enabled_from_arguments CHERE_INVOKING: enabled_from_arguments
matrix: matrix:
- MSYSTEM: MINGW64 - MSYSTEM: MINGW64
MSYS_PACKAGES: mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc
MSYS_BITNESS: 64
- MSYSTEM: MINGW32 - MSYSTEM: MINGW32
MSYS_PACKAGES: mingw-w64-i686-boost mingw-w64-i686-miniupnpc
MSYS_BITNESS: 32
install: install:
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Rns gcc-fortran gcc mingw-w64-{i686,x86_64}-gcc-ada mingw-w64-{i686,x86_64}-gcc-objc"
# TODO: revert that change when appveyor's images will be updated
- c:\msys64\usr\bin\bash -l "build/appveyor-msys2-upgrade.bash"
# update runtime
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu"
# update packages and install required
- c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" - c:\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu ${MSYS_PACKAGES}"
- if "%MSYSTEM%" == "MINGW64" (
c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-x86_64-boost mingw-w64-x86_64-miniupnpc"
) else (
c:\msys64\usr\bin\bash -lc "pacman --noconfirm -S mingw-w64-i686-boost mingw-w64-i686-miniupnpc"
)
- if "%MSYSTEM%" == "MINGW64" (
set "bitness=64"
) else (
set "bitness=32"
)
build_script: build_script:
- cmd: >- - echo MSYSTEM = %MSYSTEM%, bitness = %MSYS_BITNESS%
cd \projects\i2pd - c:\msys64\usr\bin\bash -lc "make USE_UPNP=yes -j3"
- 7z a -tzip -mx9 -mmt i2pd-mingw-win%MSYS_BITNESS%.zip i2pd.exe
echo MSYSTEM = %MSYSTEM%, bitness = %bitness%
- c:\msys64\usr\bin\bash -lc "make USE_UPNP=yes -j2"
- 7z a -tzip -mx9 -mmt i2pd-mingw-win%bitness%.zip i2pd.exe
test: off test: off

View File

@ -1,11 +1,16 @@
cmake_minimum_required ( VERSION 2.8.12 ) cmake_minimum_required(VERSION 2.8.12)
# this addresses CMP0059 with CMake > 3.3 for PCH flags # this addresses CMP0059 with CMake > 3.3 for PCH flags
cmake_policy( VERSION 2.8.12 ) cmake_policy(VERSION 2.8.12)
project ( "i2pd" ) project("i2pd")
# for debugging # for debugging
#set(CMAKE_VERBOSE_MAKEFILE on) #set(CMAKE_VERBOSE_MAKEFILE on)
# Win32 build with cmake is not supported
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.")
endif()
# configurale options # configurale options
option(WITH_AESNI "Use AES-NI instructions set" OFF) option(WITH_AESNI "Use AES-NI instructions set" OFF)
option(WITH_AVX "Use AVX instructions" OFF) option(WITH_AVX "Use AVX instructions" OFF)
@ -15,14 +20,13 @@ option(WITH_BINARY "Build binary" ON)
option(WITH_STATIC "Static build" OFF) option(WITH_STATIC "Static build" OFF)
option(WITH_UPNP "Include support for UPnP client" OFF) option(WITH_UPNP "Include support for UPnP client" OFF)
option(WITH_PCH "Use precompiled header" OFF) option(WITH_PCH "Use precompiled header" OFF)
option(WITH_GUI "Include GUI (currently MS Windows only)" ON)
option(WITH_MESHNET "Build for cjdns test network" OFF) option(WITH_MESHNET "Build for cjdns test network" OFF)
option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF) option(WITH_ADDRSANITIZER "Build with address sanitizer unix only" OFF)
option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF) option(WITH_THREADSANITIZER "Build with thread sanitizer unix only" OFF)
# paths # paths
set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules" ) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake_modules")
set ( CMAKE_SOURCE_DIR ".." ) set(CMAKE_SOURCE_DIR "..")
# architecture # architecture
include(TargetArch) include(TargetArch)
@ -30,67 +34,65 @@ target_architecture(ARCHITECTURE)
set(LIBI2PD_SRC_DIR ../libi2pd) set(LIBI2PD_SRC_DIR ../libi2pd)
set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client) set(LIBI2PD_CLIENT_SRC_DIR ../libi2pd_client)
set(DAEMON_SRC_DIR ../daemon)
include_directories(${LIBI2PD_SRC_DIR}) include_directories(${LIBI2PD_SRC_DIR})
include_directories(${LIBI2PD_CLIENT_SRC_DIR}) include_directories(${LIBI2PD_CLIENT_SRC_DIR})
include_directories(${DAEMON_SRC_DIR})
set (LIBI2PD_SRC set(LIBI2PD_SRC
"${LIBI2PD_SRC_DIR}/api.cpp"
"${LIBI2PD_SRC_DIR}/Base.cpp"
"${LIBI2PD_SRC_DIR}/Blinding.cpp"
"${LIBI2PD_SRC_DIR}/BloomFilter.cpp" "${LIBI2PD_SRC_DIR}/BloomFilter.cpp"
"${LIBI2PD_SRC_DIR}/ChaCha20.cpp"
"${LIBI2PD_SRC_DIR}/Config.cpp" "${LIBI2PD_SRC_DIR}/Config.cpp"
"${LIBI2PD_SRC_DIR}/CPU.cpp" "${LIBI2PD_SRC_DIR}/CPU.cpp"
"${LIBI2PD_SRC_DIR}/Crypto.cpp" "${LIBI2PD_SRC_DIR}/Crypto.cpp"
"${LIBI2PD_SRC_DIR}/CryptoKey.cpp" "${LIBI2PD_SRC_DIR}/CryptoKey.cpp"
"${LIBI2PD_SRC_DIR}/Datagram.cpp"
"${LIBI2PD_SRC_DIR}/Destination.cpp"
"${LIBI2PD_SRC_DIR}/ECIESX25519AEADRatchetSession.cpp"
"${LIBI2PD_SRC_DIR}/Ed25519.cpp"
"${LIBI2PD_SRC_DIR}/Elligator.cpp"
"${LIBI2PD_SRC_DIR}/Family.cpp"
"${LIBI2PD_SRC_DIR}/FS.cpp"
"${LIBI2PD_SRC_DIR}/Garlic.cpp" "${LIBI2PD_SRC_DIR}/Garlic.cpp"
"${LIBI2PD_SRC_DIR}/Gost.cpp"
"${LIBI2PD_SRC_DIR}/Gzip.cpp" "${LIBI2PD_SRC_DIR}/Gzip.cpp"
"${LIBI2PD_SRC_DIR}/HTTP.cpp" "${LIBI2PD_SRC_DIR}/HTTP.cpp"
"${LIBI2PD_SRC_DIR}/I2NPProtocol.cpp" "${LIBI2PD_SRC_DIR}/I2NPProtocol.cpp"
"${LIBI2PD_SRC_DIR}/Identity.cpp" "${LIBI2PD_SRC_DIR}/Identity.cpp"
"${LIBI2PD_SRC_DIR}/LeaseSet.cpp" "${LIBI2PD_SRC_DIR}/LeaseSet.cpp"
"${LIBI2PD_SRC_DIR}/FS.cpp"
"${LIBI2PD_SRC_DIR}/Log.cpp" "${LIBI2PD_SRC_DIR}/Log.cpp"
"${LIBI2PD_SRC_DIR}/NTCPSession.cpp"
"${LIBI2PD_SRC_DIR}/NetDbRequests.cpp"
"${LIBI2PD_SRC_DIR}/NetDb.cpp" "${LIBI2PD_SRC_DIR}/NetDb.cpp"
"${LIBI2PD_SRC_DIR}/NetDbRequests.cpp"
"${LIBI2PD_SRC_DIR}/NTCP2.cpp"
"${LIBI2PD_SRC_DIR}/NTCPSession.cpp"
"${LIBI2PD_SRC_DIR}/Poly1305.cpp"
"${LIBI2PD_SRC_DIR}/Profiling.cpp" "${LIBI2PD_SRC_DIR}/Profiling.cpp"
"${LIBI2PD_SRC_DIR}/Reseed.cpp" "${LIBI2PD_SRC_DIR}/Reseed.cpp"
"${LIBI2PD_SRC_DIR}/RouterContext.cpp" "${LIBI2PD_SRC_DIR}/RouterContext.cpp"
"${LIBI2PD_SRC_DIR}/RouterInfo.cpp" "${LIBI2PD_SRC_DIR}/RouterInfo.cpp"
"${LIBI2PD_SRC_DIR}/Signature.cpp"
"${LIBI2PD_SRC_DIR}/SSU.cpp" "${LIBI2PD_SRC_DIR}/SSU.cpp"
"${LIBI2PD_SRC_DIR}/SSUData.cpp" "${LIBI2PD_SRC_DIR}/SSUData.cpp"
"${LIBI2PD_SRC_DIR}/SSUSession.cpp" "${LIBI2PD_SRC_DIR}/SSUSession.cpp"
"${LIBI2PD_SRC_DIR}/Streaming.cpp" "${LIBI2PD_SRC_DIR}/Streaming.cpp"
"${LIBI2PD_SRC_DIR}/Destination.cpp"
"${LIBI2PD_SRC_DIR}/TransitTunnel.cpp"
"${LIBI2PD_SRC_DIR}/Tunnel.cpp"
"${LIBI2PD_SRC_DIR}/TunnelGateway.cpp"
"${LIBI2PD_SRC_DIR}/Transports.cpp"
"${LIBI2PD_SRC_DIR}/TunnelEndpoint.cpp"
"${LIBI2PD_SRC_DIR}/TunnelPool.cpp"
"${LIBI2PD_SRC_DIR}/Base.cpp"
"${LIBI2PD_SRC_DIR}/util.cpp"
"${LIBI2PD_SRC_DIR}/Datagram.cpp"
"${LIBI2PD_SRC_DIR}/Family.cpp"
"${LIBI2PD_SRC_DIR}/Signature.cpp"
"${LIBI2PD_SRC_DIR}/Timestamp.cpp" "${LIBI2PD_SRC_DIR}/Timestamp.cpp"
"${LIBI2PD_SRC_DIR}/api.cpp" "${LIBI2PD_SRC_DIR}/TransitTunnel.cpp"
"${LIBI2PD_SRC_DIR}/Gost.cpp" "${LIBI2PD_SRC_DIR}/Transports.cpp"
"${LIBI2PD_SRC_DIR}/ChaCha20.cpp" "${LIBI2PD_SRC_DIR}/Tunnel.cpp"
"${LIBI2PD_SRC_DIR}/Poly1305.cpp" "${LIBI2PD_SRC_DIR}/TunnelEndpoint.cpp"
"${LIBI2PD_SRC_DIR}/Ed25519.cpp" "${LIBI2PD_SRC_DIR}/TunnelGateway.cpp"
"${LIBI2PD_SRC_DIR}/NTCP2.cpp" "${LIBI2PD_SRC_DIR}/TunnelPool.cpp"
"${LIBI2PD_SRC_DIR}/Blinding.cpp" "${LIBI2PD_SRC_DIR}/util.cpp"
"${LIBI2PD_SRC_DIR}/Elligator.cpp"
"${LIBI2PD_SRC_DIR}/ECIESX25519AEADRatchetSession.cpp"
) )
if (WIN32 OR MSYS)
list (APPEND LIBI2PD_SRC "${CMAKE_SOURCE_DIR}/I2PEndian.cpp")
endif ()
add_library(libi2pd ${LIBI2PD_SRC}) add_library(libi2pd ${LIBI2PD_SRC})
set_target_properties(libi2pd PROPERTIES PREFIX "") set_target_properties(libi2pd PROPERTIES PREFIX "")
if (WITH_LIBRARY) if(WITH_LIBRARY)
install(TARGETS libi2pd install(TARGETS libi2pd
EXPORT libi2pd EXPORT libi2pd
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
@ -101,7 +103,7 @@ if (WITH_LIBRARY)
# install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR}) # install(EXPORT libi2pd DESTINATION ${CMAKE_INSTALL_LIBDIR})
endif() endif()
set (CLIENT_SRC set(CLIENT_SRC
"${LIBI2PD_CLIENT_SRC_DIR}/AddressBook.cpp" "${LIBI2PD_CLIENT_SRC_DIR}/AddressBook.cpp"
"${LIBI2PD_CLIENT_SRC_DIR}/BOB.cpp" "${LIBI2PD_CLIENT_SRC_DIR}/BOB.cpp"
"${LIBI2PD_CLIENT_SRC_DIR}/ClientContext.cpp" "${LIBI2PD_CLIENT_SRC_DIR}/ClientContext.cpp"
@ -117,7 +119,7 @@ set (CLIENT_SRC
add_library(libi2pdclient ${CLIENT_SRC}) add_library(libi2pdclient ${CLIENT_SRC})
set_target_properties(libi2pdclient PROPERTIES PREFIX "") set_target_properties(libi2pdclient PROPERTIES PREFIX "")
if (WITH_LIBRARY) if(WITH_LIBRARY)
install(TARGETS libi2pdclient install(TARGETS libi2pdclient
EXPORT libi2pdclient EXPORT libi2pdclient
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib
@ -125,9 +127,7 @@ if (WITH_LIBRARY)
COMPONENT Libraries) COMPONENT Libraries)
endif() endif()
set(DAEMON_SRC_DIR ../daemon) set(DAEMON_SRC
set (DAEMON_SRC
"${DAEMON_SRC_DIR}/Daemon.cpp" "${DAEMON_SRC_DIR}/Daemon.cpp"
"${DAEMON_SRC_DIR}/HTTPServer.cpp" "${DAEMON_SRC_DIR}/HTTPServer.cpp"
"${DAEMON_SRC_DIR}/I2PControl.cpp" "${DAEMON_SRC_DIR}/I2PControl.cpp"
@ -135,37 +135,20 @@ set (DAEMON_SRC
"${DAEMON_SRC_DIR}/UPnP.cpp" "${DAEMON_SRC_DIR}/UPnP.cpp"
) )
if (WITH_MESHNET) if(WITH_MESHNET)
add_definitions(-DMESHNET) add_definitions(-DMESHNET)
endif () endif()
if (WITH_UPNP) if(WITH_UPNP)
add_definitions(-DUSE_UPNP) add_definitions(-DUSE_UPNP)
if (NOT MSVC AND NOT MSYS) endif()
set(DL_LIB ${CMAKE_DL_LIBS})
endif ()
endif ()
# compiler flags customization (by vendor) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter")
if (MSVC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic")
add_definitions( -DWIN32_LEAN_AND_MEAN -DNOMINMAX ) # TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
# TODO Check & report to Boost dev, there should be no need for these two # Multiple definitions of __stack_chk_fail(libssp & libc)
add_definitions( -DBOOST_THREAD_NO_LIB -DBOOST_CHRONO_NO_LIB ) set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s -ffunction-sections -fdata-sections")
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL" ) set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections") # -flto is added from above
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /INCREMENTAL:NO /LTCG" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} /GL" )
set( CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /INCREMENTAL:NO /LTCG" )
else()
if (MSYS OR MINGW)
add_definitions( -DWIN32_LEAN_AND_MEAN )
endif ()
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Winvalid-pch -Wno-unused-parameter" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -pedantic" )
# TODO: The following is incompatible with static build and enabled hardening for OpenWRT.
# Multiple definitions of __stack_chk_fail (libssp & libc)
set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto -s -ffunction-sections -fdata-sections" )
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-Wl,--gc-sections" ) # -flto is added from above
endif ()
# check for c++17 & c++11 support # check for c++17 & c++11 support
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
@ -179,72 +162,53 @@ else()
message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?") message(SEND_ERROR "C++17 nor C++11 standard not seems to be supported by compiler. Too old version?")
endif() endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pipe")
if (WITH_HARDENING) if(WITH_HARDENING)
add_definitions( "-D_FORTIFY_SOURCE=2" ) add_definitions("-D_FORTIFY_SOURCE=2")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat -Wformat-security -Werror=format-security" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat -Wformat-security -Werror=format-security")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector --param ssp-buffer-size=4" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector --param ssp-buffer-size=4")
endif () endif()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# more tweaks # more tweaks
if (LINUX) if(LINUX)
set (CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libstdc++" ) # required for <atomic> set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libstdc++") # required for <atomic>
list(APPEND CMAKE_REQUIRED_LIBRARIES "stdc++") # required to link with -stdlib=libstdc++ list(APPEND CMAKE_REQUIRED_LIBRARIES "stdc++") # required to link with -stdlib=libstdc++
endif() endif()
if (NOT (MSVC OR MSYS OR APPLE)) if(NOT APPLE)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable -Wno-overloaded-virtual -Wno-c99-extensions" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-const-variable -Wno-overloaded-virtual -Wno-c99-extensions")
endif() endif()
endif () endif()
if (WITH_HARDENING AND MSVC) # compiler flags customization(by system)
# Most security options like dynamic base, buffer & stack checks are ON by default if(UNIX)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /guard:cf" ) list(APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp")
endif () if(NOT(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR APPLE))
# compiler flags customization (by system)
if (UNIX)
list (APPEND DAEMON_SRC "${DAEMON_SRC_DIR}/UnixDaemon.cpp")
if (NOT (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR APPLE))
# "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8 # "'sleep_for' is not a member of 'std::this_thread'" in gcc 4.7/4.8
add_definitions( "-D_GLIBCXX_USE_NANOSLEEP=1" ) add_definitions("-D_GLIBCXX_USE_NANOSLEEP=1")
endif ()
elseif (WIN32 OR MSYS)
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp")
if (WITH_GUI)
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32App.cpp")
set_source_files_properties("${CMAKE_SOURCE_DIR}/Win32/DaemonWin32.cpp"
PROPERTIES COMPILE_DEFINITIONS WIN32_APP)
endif ()
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Win32Service.cpp")
list (APPEND DAEMON_SRC "${CMAKE_SOURCE_DIR}/Win32/Resource.rc")
endif ()
if (WITH_AESNI)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes" )
endif()
if (WITH_AVX)
set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx" )
endif()
if (WITH_ADDRSANITIZER)
if (NOT MSVC)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer" )
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address" )
else ()
message( SEND_ERROR "MSVC does not support address sanitizer option")
endif() endif()
endif() endif()
if (WITH_THREADSANITIZER) if(WITH_AESNI)
if (WITH_ADDRSANITIZER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
message( FATAL_ERROR "thread sanitizer option cannot be combined with address sanitizer") add_definitions(-DAESNI)
elseif (NOT MSVC) endif()
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread" )
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread" ) if(WITH_AVX)
else () set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx")
message( SEND_ERROR "MSVC does not support address sanitizer option") endif()
if(WITH_ADDRSANITIZER)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
endif()
if(WITH_THREADSANITIZER)
if(WITH_ADDRSANITIZER)
message(FATAL_ERROR "thread sanitizer option cannot be combined with address sanitizer")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
endif() endif()
endif() endif()
@ -253,63 +217,38 @@ endif()
# TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826 # TODO: once CMake 3.1+ becomes mainstream, see e.g. http://stackoverflow.com/a/29871891/673826
# use imported Threads::Threads instead # use imported Threads::Threads instead
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
if (IOS) if(IOS)
set(CMAKE_THREAD_LIBS_INIT "-lpthread") set(CMAKE_THREAD_LIBS_INIT "-lpthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1) set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0) set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1) set(CMAKE_USE_PTHREADS_INIT 1)
else() else()
find_package ( Threads REQUIRED ) find_package(Threads REQUIRED)
endif() endif()
if(THREADS_HAVE_PTHREAD_ARG) # compile time flag if(THREADS_HAVE_PTHREAD_ARG) # compile time flag
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif() endif()
if (WITH_STATIC) if(WITH_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_STATIC_RUNTIME ON) set(Boost_USE_STATIC_RUNTIME ON)
if (WIN32 AND NOT MSYS AND NOT MINGW)
# http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace
foreach(flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if(${flag_var} MATCHES "/MD")
string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
endif(${flag_var} MATCHES "/MD")
endforeach(flag_var)
else ()
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
endif ()
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
if (${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*") if(${CMAKE_CXX_COMPILER} MATCHES ".*-openwrt-.*")
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
# set( CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive" ) # set(CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,--whole-archive -lpthread -Wl,--no-whole-archive")
set( CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,-u,pthread_create,-u,pthread_once,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_join,-u,pthread_equal,-u,pthread_detach,-u,pthread_cond_wait,-u,pthread_cond_signal,-u,pthread_cond_destroy,-u,pthread_cond_broadcast,-u,pthread_cancel" ) set(CMAKE_THREAD_LIBS_INIT "gcc_eh -Wl,-u,pthread_create,-u,pthread_once,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_join,-u,pthread_equal,-u,pthread_detach,-u,pthread_cond_wait,-u,pthread_cond_signal,-u,pthread_cond_destroy,-u,pthread_cond_broadcast,-u,pthread_cancel")
endif () endif()
else() else()
if (NOT WIN32 AND NOT MSYS)
# TODO: Consider separate compilation for LIBI2PD_SRC for library. # TODO: Consider separate compilation for LIBI2PD_SRC for library.
# No need in -fPIC overhead for binary if not interested in library # No need in -fPIC overhead for binary if not interested in library
# HINT: revert c266cff CMakeLists.txt: compilation speed up # HINT: revert c266cff CMakeLists.txt: compilation speed up
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
endif ()
add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK) add_definitions(-DBOOST_SYSTEM_DYN_LINK -DBOOST_FILESYSTEM_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_DATE_TIME_DYN_LINK -DBOOST_REGEX_DYN_LINK)
endif () endif()
if (WITH_PCH) if(WITH_PCH)
include_directories(BEFORE ${CMAKE_BINARY_DIR}) include_directories(BEFORE ${CMAKE_BINARY_DIR})
add_library(stdafx STATIC "${LIBI2PD_SRC_DIR}/stdafx.cpp") add_library(stdafx STATIC "${LIBI2PD_SRC_DIR}/stdafx.cpp")
if(MSVC)
target_compile_options(stdafx PRIVATE /Ycstdafx.h /Zm155)
add_custom_command(TARGET stdafx POST_BUILD
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb libi2pd.dir\\$<CONFIG>\\
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pdclient.dir\\$<CONFIG>\\
COMMAND xcopy /y stdafx.dir\\$<CONFIG>\\*.pdb i2pd.dir\\$<CONFIG>\\
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
)
target_compile_options(libi2pd PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
target_compile_options(libi2pdclient PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
string(TOUPPER ${CMAKE_BUILD_TYPE} BTU) string(TOUPPER ${CMAKE_BUILD_TYPE} BTU)
get_directory_property(DEFS DEFINITIONS) get_directory_property(DEFS DEFINITIONS)
string(REPLACE " " ";" FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTU}} ${DEFS}") string(REPLACE " " ";" FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BTU}} ${DEFS}")
@ -318,76 +257,47 @@ if (WITH_PCH)
) )
target_compile_options(libi2pd PRIVATE -include libi2pd/stdafx.h) target_compile_options(libi2pd PRIVATE -include libi2pd/stdafx.h)
target_compile_options(libi2pdclient PRIVATE -include libi2pd/stdafx.h) target_compile_options(libi2pdclient PRIVATE -include libi2pd/stdafx.h)
endif()
target_link_libraries(libi2pd stdafx) target_link_libraries(libi2pd stdafx)
endif() endif()
target_link_libraries(libi2pdclient libi2pd) target_link_libraries(libi2pdclient libi2pd)
find_package ( Boost COMPONENTS system filesystem program_options date_time REQUIRED ) find_package(Boost COMPONENTS system filesystem program_options date_time REQUIRED)
if(NOT DEFINED Boost_INCLUDE_DIRS) if(NOT DEFINED Boost_INCLUDE_DIRS)
message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!") message(SEND_ERROR "Boost is not found, or your boost version was below 1.46. Please download Boost!")
endif() endif()
find_package ( OpenSSL REQUIRED ) find_package(OpenSSL REQUIRED)
if(NOT DEFINED OPENSSL_INCLUDE_DIR) if(NOT DEFINED OPENSSL_INCLUDE_DIR)
message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!") message(SEND_ERROR "Could not find OpenSSL. Please download and install it first!")
endif() endif()
if (WITH_UPNP) if(WITH_UPNP)
find_package ( MiniUPnPc REQUIRED ) find_package(MiniUPnPc REQUIRED)
include_directories( SYSTEM ${MINIUPNPC_INCLUDE_DIR} ) if(NOT MINIUPNPC_FOUND)
message(SEND_ERROR "Could not find MiniUPnPc. Please download and install it first!")
else()
include_directories(SYSTEM ${MINIUPNPC_INCLUDE_DIR})
endif()
endif() endif()
find_package ( ZLIB ) find_package(ZLIB)
if (NOT ZLIB_FOUND ) if(ZLIB_FOUND)
# We are probably on Windows
find_program( PATCH patch C:/Program Files/Git/usr/bin C:/msys64/usr/bin C:/msys32/usr/bin C:/Strawberry/c/bin )
include( ExternalProject )
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
set( ZLIB_EXTRA -DAMD64=ON )
else()
set( ZLIB_EXTRA -DASM686=ON "-DCMAKE_ASM_MASM_FLAGS=/W0 /safeseh" )
endif()
ExternalProject_Add(zlib-project
URL https://zlib.net/zlib-1.2.11.tar.gz
URL_HASH SHA256=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/zlib
PATCH_COMMAND "${PATCH}" -p0 < ${CMAKE_CURRENT_SOURCE_DIR}/cmake-zlib-static.patch
&& "${PATCH}" -p0 < ${CMAKE_CURRENT_SOURCE_DIR}/cmake-zlib-amd64.patch
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DWITH_STATIC=${WITH_STATIC} ${ZLIB_EXTRA}
)
if (WITH_PCH)
add_dependencies( stdafx zlib-project )
else ()
add_dependencies( libi2pd zlib-project )
endif ()
# ExternalProject_Get_Property(zlib-project install_dir)
set ( ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/zlib/include" CACHE FILEPATH "zlib include dir" FORCE)
if (NOT WITH_STATIC)
set ( ZLIB_LIBRARY debug zlibd optimized zlib CACHE STRING "zlib libraries" FORCE)
endif ()
link_directories(${CMAKE_CURRENT_BINARY_DIR}/zlib/lib)
else()
link_directories(${ZLIB_ROOT}/lib) link_directories(${ZLIB_ROOT}/lib)
endif () endif()
if (WITH_STATIC AND (MSVC OR MSYS))
set ( ZLIB_LIBRARY debug zlibstaticd optimized zlibstatic CACHE STRING "zlib libraries" FORCE)
endif ()
# load includes # load includes
include_directories( SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR} ) include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
# warn if for meshnet # warn if for meshnet
if (WITH_MESHNET) if(WITH_MESHNET)
message(STATUS "Building for testnet") message(STATUS "Building for testnet")
message(WARNING "This build will NOT work on mainline i2p") message(WARNING "This build will NOT work on mainline i2p")
endif() endif()
include(CheckAtomic) if(NOT MSYS)
include(CheckAtomic)
endif()
# show summary # show summary
message(STATUS "---------------------------------------") message(STATUS "---------------------------------------")
@ -414,32 +324,24 @@ message(STATUS "---------------------------------------")
#Handle paths nicely #Handle paths nicely
include(GNUInstallDirs) include(GNUInstallDirs)
if (WITH_BINARY) if(WITH_BINARY)
add_executable ( "${PROJECT_NAME}" ${DAEMON_SRC} ) add_executable("${PROJECT_NAME}" ${DAEMON_SRC})
if (WIN32 AND WITH_GUI)
set_target_properties("${PROJECT_NAME}" PROPERTIES WIN32_EXECUTABLE TRUE ) if(WITH_STATIC)
endif() set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static")
if(NOT MSVC)
if (WITH_STATIC)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-static" )
endif ()
endif() endif()
if (WITH_PCH) if(WITH_PCH)
if (MSVC)
target_compile_options("${PROJECT_NAME}" PRIVATE /FIstdafx.h /Yustdafx.h /Zm155 "/Fp${CMAKE_BINARY_DIR}/stdafx.dir/$<CONFIG>/stdafx.pch")
else()
target_compile_options("${PROJECT_NAME}" PRIVATE -include libi2pd/stdafx.h) target_compile_options("${PROJECT_NAME}" PRIVATE -include libi2pd/stdafx.h)
endif() endif()
if(WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now")
endif() endif()
if (WITH_HARDENING AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT MSYS AND NOT MINGW) if(WITH_UPNP)
set_target_properties("${PROJECT_NAME}" PROPERTIES LINK_FLAGS "-z relro -z now" ) set(UPNP_LIB ${MINIUPNPC_LIBRARY})
endif () endif()
if (WITH_UPNP)
target_link_libraries("${PROJECT_NAME}" "${MINIUPNPC_LIBRARY}")
endif ()
# FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04 # FindBoost pulls pthread for thread which is broken for static linking at least on Ubuntu 15.04
list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES) list(GET Boost_LIBRARIES -1 LAST_Boost_LIBRARIES)
@ -447,128 +349,15 @@ if (WITH_BINARY)
list(REMOVE_AT Boost_LIBRARIES -1) list(REMOVE_AT Boost_LIBRARIES -1)
endif() endif()
if (MSYS OR MINGW)
set (MINGW_EXTRA -lws2_32 -lmswsock -liphlpapi ) if(WITH_STATIC)
endif ()
if (WITH_STATIC)
set(DL_LIB ${CMAKE_DL_LIBS}) set(DL_LIB ${CMAKE_DL_LIBS})
endif() endif()
target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY}) target_link_libraries(libi2pd ${Boost_LIBRARIES} ${ZLIB_LIBRARY})
target_link_libraries( "${PROJECT_NAME}" libi2pd libi2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES}) target_link_libraries("${PROJECT_NAME}" libi2pd libi2pdclient ${DL_LIB} ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} ${UPNP_LIB} ${ZLIB_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${MINGW_EXTRA} ${DL_LIB} ${CMAKE_REQUIRED_LIBRARIES})
install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime) install(TARGETS "${PROJECT_NAME}" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT Runtime)
set (APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}") set(APPS "\${CMAKE_INSTALL_PREFIX}/bin/${PROJECT_NAME}${CMAKE_EXECUTABLE_SUFFIX}")
set (DIRS "${Boost_LIBRARY_DIR};${OPENSSL_INCLUDE_DIR}/../bin;${ZLIB_INCLUDE_DIR}/../bin;/mingw32/bin") set(DIRS "${Boost_LIBRARY_DIR};${OPENSSL_INCLUDE_DIR}/../bin;${ZLIB_INCLUDE_DIR}/../bin;/mingw32/bin")
if (MSVC)
install(FILES $<TARGET_PDB_FILE:${PROJECT_NAME}> DESTINATION ${CMAKE_INSTALL_BINDIR} CONFIGURATIONS DEBUG RELWITHDEBINFO COMPONENT Symbols)
# TODO Somehow this picks lots of unrelevant stuff with MSYS. OS X testing needed.
INSTALL(CODE "
include(BundleUtilities)
fixup_bundle(\"${APPS}\" \"\" \"${DIRS}\")
" COMPONENT Runtime)
endif ()
endif ()
install(FILES ../LICENSE
DESTINATION .
COMPONENT Runtime
)
# Take a copy on Appveyor
install(FILES "C:/projects/openssl-$ENV{OPENSSL}/LICENSE"
DESTINATION .
COMPONENT Runtime
RENAME LICENSE_OPENSSL
OPTIONAL # for local builds only!
)
file(GLOB_RECURSE I2PD_SOURCES "../libi2pd/*.cpp" "../libi2pd_client/*.cpp" "../daemon/*.cpp" "../build" "../Win32" "../Makefile*")
install(FILES ${I2PD_SOURCES} DESTINATION src/ COMPONENT Source)
# install(DIRECTORY ../ DESTINATION src/
# # OPTIONAL
# COMPONENT Source FILES_MATCHING
# PATTERN .git EXCLUDE
# PATTERN "*.cpp"
# )
file(GLOB I2PD_HEADERS "../libi2pd/*.h" "../libi2pd_client/*.h" "../daemon/*.h")
install(FILES ${I2PD_HEADERS} DESTINATION src/ COMPONENT Headers)
# install(DIRECTORY ../ DESTINATION src/
# # OPTIONAL
# COMPONENT Headers FILES_MATCHING
# PATTERN .git EXCLUDE
# PATTERN "*.h"
# )
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Purple I2P, a C++ I2P daemon")
set(CPACK_PACKAGE_VENDOR "Purple I2P")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/../LICENSE")
file(READ ../libi2pd/version.h version_h)
string(REGEX REPLACE ".*I2PD_VERSION_MAJOR ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MAJOR "${version_h}")
string(REGEX REPLACE ".*I2PD_VERSION_MINOR ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MINOR "${version_h}")
string(REGEX REPLACE ".*I2PD_VERSION_MICRO ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_MICRO "${version_h}")
string(REGEX REPLACE ".*I2PD_VERSION_PATCH ([0-9]+).*" "\\1" CPACK_PACKAGE_VERSION_PATCH "${version_h}")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Purple I2P")# ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
include(CPackComponent)
cpack_add_component(Runtime
DESCRIPTION "Main files"
REQUIRED INSTALL_TYPES minimal)
cpack_add_component(Symbols
DISPLAY_NAME "Debug symbols"
DESCRIPTION "Debug symbols for use with WinDbg or Visual Studio"
INSTALL_TYPES recommended full
)
cpack_add_component(Libraries
DESCRIPTION "Binary libraries for development"
INSTALL_TYPES full dev3rd
)
cpack_add_component(Source
DISPLAY_NAME "Source code"
DESCRIPTION "I2pd source code"
INSTALL_TYPES full
)
cpack_add_component(Headers
DISPLAY_NAME "Header files"
DESCRIPTION "I2pd header files for development"
INSTALL_TYPES full dev3rd
)
install(FILES ${MINIUPNPC_INCLUDE_DIR}/miniupnpc/miniupnpc.dll
DESTINATION bin
COMPONENT MiniUPnPc
OPTIONAL
)
install(FILES ${MINIUPNPC_INCLUDE_DIR}/miniupnpc/LICENSE
DESTINATION .
COMPONENT MiniUPnPc
RENAME LICENSE_MINIUPNPC
OPTIONAL
)
cpack_add_component(MiniUPnPc
INSTALL_TYPES full recommended
# DOWNLOADED
# ARCHIVE_FILE miniupnpc-win32.zip
)
cpack_add_install_type(recommended DISPLAY_NAME Recommended)
cpack_add_install_type(dev3rd DISPLAY_NAME "Third party development")
cpack_add_install_type(full DISPLAY_NAME Full)
cpack_add_install_type(minimal DISPLAY_NAME Minimal)
if((WIN32 OR MSYS) AND NOT UNIX)
# There is a bug in NSI that does not handle full unix paths properly. Make
# sure there is at least one set of four (4) backlasshes.
set(CPACK_NSIS_DEFINES "RequestExecutionLevel user")
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/../Win32\\\\mask.bmp")
set(CPACK_NSIS_INSTALLED_ICON_NAME "bin/i2pd.exe")
SET(CPACK_NSIS_DISPLAY_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
set(CPACK_NSIS_HELP_LINK "https:\\\\\\\\github.com\\\\PurpleI2P\\\\i2pd\\\\issues")
set(CPACK_NSIS_URL_INFO_ABOUT "https:\\\\\\\\github.com\\\\PurpleI2P\\\\i2pd")
set(CPACK_NSIS_CREATE_ICONS_EXTRA "CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Install i2pd as windows service.lnk' '$INSTDIR\\\\bin\\\\i2pd.exe' '--service=install'
CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Remove i2pd windows service.lnk' '$INSTDIR\\\\bin\\\\i2pd.exe' '--service=remove'")
set(CPACK_NSIS_DELETE_ICONS_EXTRA "Delete '$SMPROGRAMS\\\\$START_MENU\\\\Install i2pd as windows service.lnk'
Delete '$SMPROGRAMS\\\\$START_MENU\\\\Remove i2pd windows service.lnk'")
else()
set(CPACK_STRIP_FILES "bin/i2pd")
set(CPACK_SOURCE_STRIP_FILES "")
endif() endif()
set(CPACK_PACKAGE_EXECUTABLES "i2pd" "C++ I2P daemon")
set(CPACK_SOURCE_GENERATOR "TGZ")
include(CPack)

View File

@ -0,0 +1,10 @@
set -e -x
base_url='http://repo.msys2.org/msys/x86_64/'
packages="libzstd-1.4.4-2-x86_64.pkg.tar.xz pacman-5.2.1-6-x86_64.pkg.tar.xz zstd-1.4.4-2-x86_64.pkg.tar.xz"
for p in $packages
do
curl "${base_url}$p" -o "$p"
done
pacman -U --noconfirm $packages
rm -f $packages

View File

@ -1,10 +0,0 @@
--- CMakeLists.txt.orig 2015-12-07 14:19:36.447689600 -0600
+++ CMakeLists.txt 2015-12-07 14:18:23.004419900 -0600
@@ -165,6 +165,7 @@
ENABLE_LANGUAGE(ASM_MASM)
set(ZLIB_ASMS
contrib/masmx64/gvmat64.asm
+ contrib/masmx64/inffas8664.c
contrib/masmx64/inffasx64.asm
)
endif()

View File

@ -1,28 +0,0 @@
--- CMakeLists.txt.orig 2013-04-28 17:57:10.000000000 -0500
+++ CMakeLists.txt 2015-12-03 12:53:52.371087900 -0600
@@ -7,6 +7,7 @@
option(ASM686 "Enable building i686 assembly implementation")
option(AMD64 "Enable building amd64 assembly implementation")
+option(WITH_STATIC "Static runtime on Windows" OFF)
set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
@@ -66,6 +67,17 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
endif()
+if(WITH_STATIC AND (MSVC OR MSYS))
+ # http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace
+ foreach(flag_var
+ CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+ CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO)
+ if(${flag_var} MATCHES "/MD")
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ endif(${flag_var} MATCHES "/MD")
+ endforeach(flag_var)
+endif()
+
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
# If we're doing an out of source build and the user has a zconf.h
# in their source tree...

View File

@ -19,6 +19,7 @@
/etc/nsswitch.conf r, /etc/nsswitch.conf r,
/etc/resolv.conf r, /etc/resolv.conf r,
/run/resolvconf/resolv.conf r, /run/resolvconf/resolv.conf r,
/run/systemd/resolve/resolv.conf r,
/run/systemd/resolve/stub-resolv.conf r, /run/systemd/resolve/stub-resolv.conf r,
# path specific (feel free to modify if you have another paths) # path specific (feel free to modify if you have another paths)

View File

@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF3TCCA8WgAwIBAgIRAKye34BRrKyQN6kMVPHddykwDQYJKoZIhvcNAQELBQAw
dzELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJYWDEeMBwGA1UE
ChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAxIDAeBgNVBAMM
F2hhbmtoaWxsMTk1ODBAZ21haWwuY29tMB4XDTIwMDUwNzA1MDkxMFoXDTMwMDUw
NzA1MDkxMFowdzELMAkGA1UEBhMCWFgxCzAJBgNVBAcTAlhYMQswCQYDVQQJEwJY
WDEeMBwGA1UEChMVSTJQIEFub255bW91cyBOZXR3b3JrMQwwCgYDVQQLEwNJMlAx
IDAeBgNVBAMMF2hhbmtoaWxsMTk1ODBAZ21haWwuY29tMIICIjANBgkqhkiG9w0B
AQEFAAOCAg8AMIICCgKCAgEA5Vt7c0SeUdVkcXXEYe3M9LmCTUyiCv/PHF2Puys6
8luLH8lO0U/pQ4j703kFKK7s4rV65jVpGNncjHWbfSCNevvs6VcbAFoo7oJX7Yjt
5+Z4oU1g7JG86feTwU6pzfFjAs0RO2lNq2L8AyLYKWOnPsVrmuGYl2c6N5WDzTxA
Et66IudfGsppTv7oZkgX6VNUMioV8tCjBTLaPCkSfyYKBX7r6ByHY86PflhFgYES
zIB92Ma75YFtCB0ktCM+o6d7wmnt10Iy4I6craZ+z7szCDRF73jhf3Vk7vGzb2cN
aCfr2riwlRJBaKrLJP5m0dGf5RdhviMgxc6JAgkN7Ius5lkxO/p3OSy5co0DrMJ7
lvwdZ2hu0dnO75unTt6ImR4RQ90Sqj7MUdorKR/8FcYEo+twBV8cV3s9kjuO5jxV
g976Q+GD3zDoixiege3W5UT4ff/Anm4mJpE5PKbNuO+KUjk6WA4B1PeudkEcxkO4
tQYy0aBzfjeyENee9otd4TgN1epY4wlHIORCa3HUFmFZd9VZMQcxwv7c47wl2kc9
Cv1L6Nae78wRzRu2CHD8zWhq+tv5q7Md2eRd3mFPI09ljsOgG2TQv6300WvHvI5M
enNdjYjLqOTRCzUJ2Jst4BZsvDxjWYkHsSZc1UORzm2LQmh2bJvbhC3m81qANGw6
ZhcCAwEAAaNkMGIwDgYDVR0PAQH/BAQDAgKEMB0GA1UdJQQWMBQGCCsGAQUFBwMC
BggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCAGA1UdDgQZBBdoYW5raGlsbDE5
NTgwQGdtYWlsLmNvbTANBgkqhkiG9w0BAQsFAAOCAgEAVtMF7lrgkDLTNXlavI7h
HJqFxFHjmxPk3iu2Qrgwk302Gowqg5NjVVamT20cXeuJaUa6maTTHzDyyCai3+3e
roaosGxZQRpRf5/RBz2yhdEPLZBV9IqxGgIxvCWNqNIYB1SNk00rwC4q5heW1me0
EsOK4Mw5IbS2jUjbi9E5th781QDj91elwltghxwtDvpE2vzAJwmxwwBhjySGsKfq
w8SBZOxN+Ih5/IIpDnYGNoN1LSkJnBVGSkjY6OpstuJRIPYWl5zX5tJtYdaxiD+8
qNbFHBIZ5WrktMopJ3QJJxHdERyK6BFYYSzX/a1gO7woOFCkx8qMCsVzfcE/z1pp
JxJvshT32hnrKZ6MbZMd9JpTFclQ62RV5tNs3FPP3sbDsFtKBUtj87SW7XsimHbZ
OrWlPacSnQDbOoV5TfDDCqWi4PW2EqzDsDcg+Lc8EnBRIquWcAox2+4zmcQI29wO
C1TUpMT5o/wGyL/i9pf6GuTbH0D+aYukULropgSrK57EALbuvqnN3vh5l2QlX/rM
+7lCKsGCNLiJFXb0m6l/B9CC1947XVEbpMEAC/80Shwxl/UB+mKFpJxcNLFtPXzv
FYv2ixarBPbJx/FclOO8G91QC4ZhAKbsVZn5HPMSgtZe+xWM1r0/UJVChsMTafpd
CCOJyu3XtyzFf+tAeixOnuQ=
-----END CERTIFICATE-----

View File

@ -1,2 +1,2 @@
d /var/run/i2pd 0755 i2pd i2pd - - d /run/i2pd 0755 i2pd i2pd - -
d /var/log/i2pd 0755 i2pd i2pd - - d /var/log/i2pd 0755 i2pd i2pd - -

View File

@ -36,9 +36,9 @@ RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool zlib
&& cd /usr/local/bin \ && cd /usr/local/bin \
&& strip i2pd \ && strip i2pd \
&& rm -fr /tmp/build && apk --no-cache --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \ && rm -fr /tmp/build && apk --no-cache --purge del build-dependendencies build-base fortify-headers boost-dev zlib-dev openssl-dev \
boost-python3 python3 gdbm boost-unit_test_framework linux-headers boost-prg_exec_monitor \ boost-python3 python3 gdbm boost-unit_test_framework boost-python2 linux-headers boost-prg_exec_monitor \
boost-serialization boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre \ boost-serialization boost-wave boost-wserialization boost-math boost-graph boost-regex git pcre2 \
libtool g++ gcc pkgconfig libtool g++ gcc
# 2. Adding required libraries to run i2pd to ensure it will run. # 2. Adding required libraries to run i2pd to ensure it will run.
RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl musl-utils libstdc++ RUN apk --no-cache add boost-filesystem boost-system boost-program_options boost-date_time boost-thread boost-iostreams openssl musl-utils libstdc++

View File

@ -13,10 +13,10 @@
## Tunnels config files path ## Tunnels config files path
## Use that path to store separated tunnels in different config files. ## Use that path to store separated tunnels in different config files.
## Default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d ## Default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d
# tunnelsdir = /var/lib/i2pd/tunnels.conf.d # tunnelsdir = /var/lib/i2pd/tunnels.d
## Where to write pidfile (don't write by default) ## Where to write pidfile (default: i2pd.pid, not used in Windows)
# pidfile = /var/run/i2pd.pid # pidfile = /run/i2pd.pid
## Logging configuration section ## Logging configuration section
## By default logs go to stdout with level 'info' and higher ## By default logs go to stdout with level 'info' and higher
@ -27,10 +27,10 @@
## * syslog - use syslog, see man 3 syslog ## * syslog - use syslog, see man 3 syslog
# log = file # log = file
## Path to logfile (default - autodetect) ## Path to logfile (default - autodetect)
# logfile = /var/log/i2pd.log # logfile = /var/log/i2pd/i2pd.log
## Log messages above this level (debug, *info, warn, error, none) ## Log messages above this level (debug, info, *warn, error, none)
## If you set it to none, logging will be disabled ## If you set it to none, logging will be disabled
# loglevel = info # loglevel = warn
## Write full CLF-formatted date and time to log (default: write only time) ## Write full CLF-formatted date and time to log (default: write only time)
# logclftime = true # logclftime = true

9
contrib/i2pd.logrotate Normal file
View File

@ -0,0 +1,9 @@
"/var/log/i2pd/*.log" {
copytruncate
daily
rotate 5
compress
delaycompress
missingok
notifempty
}

View File

@ -11,9 +11,9 @@ RuntimeDirectoryMode=0700
LogsDirectory=i2pd LogsDirectory=i2pd
LogsDirectoryMode=0700 LogsDirectoryMode=0700
Type=forking Type=forking
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID ExecReload=/bin/sh -c "kill -HUP $MAINPID"
PIDFile=/var/run/i2pd/i2pd.pid PIDFile=/run/i2pd/i2pd.pid
### Uncomment, if auto restart needed ### Uncomment, if auto restart needed
#Restart=on-failure #Restart=on-failure
@ -27,7 +27,6 @@ KillSignal=SIGQUIT
LimitNOFILE=4096 LimitNOFILE=4096
# To enable write of coredump uncomment this # To enable write of coredump uncomment this
#LimitCORE=infinity #LimitCORE=infinity
PrivateDevices=yes
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -1,7 +1,7 @@
%define git_hash %(git rev-parse HEAD | cut -c -7) %define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git Name: i2pd-git
Version: 2.30.0 Version: 2.32.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
@ -24,6 +24,7 @@ BuildRequires: openssl-devel
BuildRequires: miniupnpc-devel BuildRequires: miniupnpc-devel
BuildRequires: systemd-units BuildRequires: systemd-units
Requires: logrotate
Requires: systemd Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
@ -73,16 +74,17 @@ pushd build
chrpath -d i2pd chrpath -d i2pd
%{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd %{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf %{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt
%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
%{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.d/README %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d/README
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1
%{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd %{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd %{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
%{__install} -d -m 755 %{buildroot}%{_datadir}/%{name} %{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/%{name}/certificates %{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/i2pd
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
@ -108,16 +110,30 @@ getent passwd i2pd >/dev/null || \
%files %files
%doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d %doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
%{_sbindir}/i2pd %{_sbindir}/i2pd
%config(noreplace) %{_sysconfdir}/i2pd/* %config(noreplace) %{_sysconfdir}/i2pd/*.conf
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
%config %{_sysconfdir}/i2pd/subscriptions.txt
%doc %{_sysconfdir}/i2pd/tunnels.conf.d/README
%{_sysconfdir}/logrotate.d/i2pd
%{_unitdir}/i2pd.service %{_unitdir}/i2pd.service
%{_mandir}/man1/i2pd.1* %{_mandir}/man1/i2pd.1*
%dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd %dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd %dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd
%{_datadir}/%{name}/certificates %{_datadir}/i2pd/certificates
%{_sharedstatedir}/i2pd/certificates %{_sharedstatedir}/i2pd/certificates
%changelog %changelog
* Mon May 25 2020 r4sas <r4sas@i2pmail.org> - 2.32.0
- update to 2.32.0
- updated systemd service file (#1394)
* Thu May 7 2020 Anatolii Vorona <vorona.tolik@gmail.com> - 2.31.0-3
- added RPM logrotate config
* Fri Apr 10 2020 orignal <i2porignal@yandex.ru> - 2.31.0
- update to 2.31.0
* Tue Feb 25 2020 orignal <i2porignal@yandex.ru> - 2.30.0 * Tue Feb 25 2020 orignal <i2porignal@yandex.ru> - 2.30.0
- update to 2.30.0 - update to 2.30.0

View File

@ -1 +0,0 @@
../i2pd.service

View File

@ -1,6 +1,6 @@
Name: i2pd Name: i2pd
Version: 2.30.0 Version: 2.32.0
Release: 1%{?dist} Release: 2%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git Conflicts: i2pd-git
@ -22,6 +22,7 @@ BuildRequires: openssl-devel
BuildRequires: miniupnpc-devel BuildRequires: miniupnpc-devel
BuildRequires: systemd-units BuildRequires: systemd-units
Requires: logrotate
Requires: systemd Requires: systemd
Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd Requires(pre): %{_sbindir}/useradd %{_sbindir}/groupadd
@ -70,18 +71,19 @@ pushd build
%endif %endif
chrpath -d i2pd chrpath -d i2pd
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd %{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf %{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf %{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
install -d -m 755 %{buildroot}%{_datadir}/i2pd %{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
install -d -m 755 %{buildroot}%{_datadir}/i2pd/tunnels.conf.d %{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/i2pd
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
%{__install} -D -m 644 %{_builddir}/%{name}-%{version}/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates %{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d %{__cp} -r %{_builddir}/%{name}-%{version}/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
ln -s %{_datadir}/i2pd/tunnels.conf.d %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
%pre %pre
@ -104,18 +106,32 @@ getent passwd i2pd >/dev/null || \
%files %files
%doc LICENSE README.md %doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
%{_sbindir}/i2pd %{_sbindir}/i2pd
%{_datadir}/i2pd/certificates %config(noreplace) %{_sysconfdir}/i2pd/*.conf
%config(noreplace) %{_sysconfdir}/i2pd/* %config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*.conf
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/* %config %{_sysconfdir}/i2pd/subscriptions.txt
/%{_unitdir}/i2pd.service %doc %{_sysconfdir}/i2pd/tunnels.conf.d/README
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd %{_sysconfdir}/logrotate.d/i2pd
%{_unitdir}/i2pd.service
%{_mandir}/man1/i2pd.1*
%dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd %dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd
%{_datadir}/i2pd/certificates
%{_sharedstatedir}/i2pd/certificates %{_sharedstatedir}/i2pd/certificates
%changelog %changelog
* Mon May 25 2020 r4sas <r4sas@i2pmail.org> - 2.32.0
- update to 2.32.0
- updated systemd service file (#1394)
* Thu May 7 2020 Anatolii Vorona <vorona.tolik@gmail.com> - 2.31.0-3
- added RPM logrotate config
* Fri Apr 10 2020 orignal <i2porignal@yandex.ru> - 2.31.0
- update to 2.31.0
* Tue Feb 25 2020 orignal <i2porignal@yandex.ru> - 2.30.0 * Tue Feb 25 2020 orignal <i2porignal@yandex.ru> - 2.30.0
- update to 2.30.0 - update to 2.30.0

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <thread> #include <thread>
#include <memory> #include <memory>
@ -71,20 +79,15 @@ namespace i2p
i2p::fs::Init(); i2p::fs::Init();
datadir = i2p::fs::GetDataDir(); datadir = i2p::fs::GetDataDir();
// TODO: drop old name detection in v2.8.0
if (config == "") if (config == "")
{ {
config = i2p::fs::DataDirPath("i2p.conf");
if (i2p::fs::Exists (config)) {
LogPrint(eLogWarning, "Daemon: please rename i2p.conf to i2pd.conf here: ", config);
} else {
config = i2p::fs::DataDirPath("i2pd.conf"); config = i2p::fs::DataDirPath("i2pd.conf");
if (!i2p::fs::Exists (config)) { if (!i2p::fs::Exists (config)) {
// use i2pd.conf only if exists // use i2pd.conf only if exists
config = ""; /* reset */ config = ""; /* reset */
} }
} }
}
i2p::config::ParseConfig(config); i2p::config::ParseConfig(config);
i2p::config::Finalize(); i2p::config::Finalize();
@ -177,10 +180,13 @@ namespace i2p
SetMaxNumTransitTunnels (transitTunnels); SetMaxNumTransitTunnels (transitTunnels);
bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill); bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
if (isFloodfill) { if (isFloodfill)
{
LogPrint(eLogInfo, "Daemon: router will be floodfill"); LogPrint(eLogInfo, "Daemon: router will be floodfill");
i2p::context.SetFloodfill (true); i2p::context.SetFloodfill (true);
} else { }
else
{
i2p::context.SetFloodfill (false); i2p::context.SetFloodfill (false);
} }
@ -248,7 +254,8 @@ namespace i2p
i2p::transport::transports.RestrictRoutesToFamilies(fams); i2p::transport::transports.RestrictRoutesToFamilies(fams);
restricted = fams.size() > 0; restricted = fams.size() > 0;
} }
if (routers.length() > 0) { if (routers.length() > 0)
{
std::set<i2p::data::IdentHash> idents; std::set<i2p::data::IdentHash> idents;
size_t pos = 0, comma; size_t pos = 0, comma;
do do
@ -265,7 +272,7 @@ namespace i2p
restricted = idents.size() > 0; restricted = idents.size() > 0;
} }
if(!restricted) if(!restricted)
LogPrint(eLogError, "Daemon: no trusted routers of families specififed"); LogPrint(eLogError, "Daemon: no trusted routers of families specified");
} }
bool hidden; i2p::config::GetOption("trust.hidden", hidden); bool hidden; i2p::config::GetOption("trust.hidden", hidden);
@ -284,7 +291,8 @@ namespace i2p
i2p::data::netdb.Start(); i2p::data::netdb.Start();
bool upnp; i2p::config::GetOption("upnp.enabled", upnp); bool upnp; i2p::config::GetOption("upnp.enabled", upnp);
if (upnp) { if (upnp)
{
d.UPnP = std::unique_ptr<i2p::transport::UPnP>(new i2p::transport::UPnP); d.UPnP = std::unique_ptr<i2p::transport::UPnP>(new i2p::transport::UPnP);
d.UPnP->Start (); d.UPnP->Start ();
} }
@ -315,14 +323,22 @@ namespace i2p
} }
bool http; i2p::config::GetOption("http.enabled", http); bool http; i2p::config::GetOption("http.enabled", http);
if (http) { if (http)
{
std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); uint16_t httpPort; i2p::config::GetOption("http.port", httpPort);
LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort); LogPrint(eLogInfo, "Daemon: starting webconsole at ", httpAddr, ":", httpPort);
try
{
d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort)); d.httpServer = std::unique_ptr<i2p::http::HTTPServer>(new i2p::http::HTTPServer(httpAddr, httpPort));
d.httpServer->Start(); d.httpServer->Start();
} }
catch (std::exception& ex)
{
LogPrint (eLogError, "Daemon: failed to start webconsole: ", ex.what ());
ThrowFatal ("Unable to start webconsole at ", httpAddr, ":", httpPort, ": ", ex.what ());
}
}
LogPrint(eLogInfo, "Daemon: starting Tunnels"); LogPrint(eLogInfo, "Daemon: starting Tunnels");
i2p::tunnel::tunnels.Start(); i2p::tunnel::tunnels.Start();
@ -336,9 +352,17 @@ namespace i2p
std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr); std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort); uint16_t i2pcpPort; i2p::config::GetOption("i2pcontrol.port", i2pcpPort);
LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort); LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
try
{
d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort)); d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
d.m_I2PControlService->Start (); d.m_I2PControlService->Start ();
} }
catch (std::exception& ex)
{
LogPrint (eLogError, "Daemon: failed to start I2PControl: ", ex.what ());
ThrowFatal ("Unable to start I2PControl service at ", i2pcpAddr, ":", i2pcpPort, ": ", ex.what ());
}
}
return true; return true;
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef DAEMON_H__ #ifndef DAEMON_H__
#define DAEMON_H__ #define DAEMON_H__
@ -13,6 +21,7 @@ namespace util
class Daemon_Singleton class Daemon_Singleton
{ {
public: public:
virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream); virtual bool init(int argc, char* argv[], std::shared_ptr<std::ostream> logstream);
virtual bool init(int argc, char* argv[]); virtual bool init(int argc, char* argv[]);
virtual bool start(); virtual bool start();
@ -23,6 +32,7 @@ namespace util
bool running; bool running;
protected: protected:
Daemon_Singleton(); Daemon_Singleton();
virtual ~Daemon_Singleton(); virtual ~Daemon_Singleton();
@ -39,6 +49,7 @@ namespace util
class DaemonQT: public i2p::util::Daemon_Singleton class DaemonQT: public i2p::util::Daemon_Singleton
{ {
public: public:
static DaemonQT& Instance() static DaemonQT& Instance()
{ {
static DaemonQT instance; static DaemonQT instance;
@ -51,6 +62,7 @@ namespace util
class DaemonWin32 : public Daemon_Singleton class DaemonWin32 : public Daemon_Singleton
{ {
public: public:
static DaemonWin32& Instance() static DaemonWin32& Instance()
{ {
static DaemonWin32 instance; static DaemonWin32 instance;
@ -72,6 +84,7 @@ namespace util
class DaemonAndroid: public i2p::util::Daemon_Singleton class DaemonAndroid: public i2p::util::Daemon_Singleton
{ {
public: public:
static DaemonAndroid& Instance() static DaemonAndroid& Instance()
{ {
static DaemonAndroid instance; static DaemonAndroid instance;
@ -83,6 +96,7 @@ namespace util
class DaemonLinux : public Daemon_Singleton class DaemonLinux : public Daemon_Singleton
{ {
public: public:
static DaemonLinux& Instance() static DaemonLinux& Instance()
{ {
static DaemonLinux instance; static DaemonLinux instance;
@ -94,10 +108,12 @@ namespace util
void run (); void run ();
private: private:
std::string pidfile; std::string pidfile;
int pidFH; int pidFH;
public: public:
int gracefulShutdownInterval; // in seconds int gracefulShutdownInterval; // in seconds
}; };
#endif #endif

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <thread> #include <thread>
@ -22,6 +30,7 @@
#include "HTTPServer.h" #include "HTTPServer.h"
#include "Daemon.h" #include "Daemon.h"
#include "util.h" #include "util.h"
#include "ECIESX25519AEADRatchetSession.h"
#ifdef WIN32_APP #ifdef WIN32_APP
#include "Win32/Win32App.h" #include "Win32/Win32App.h"
#endif #endif
@ -54,7 +63,7 @@ namespace http {
" body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n" " body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; }\r\n"
" a, .slide label { text-decoration: none; color: #894C84; }\r\n" " a, .slide label { text-decoration: none; color: #894C84; }\r\n"
" a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n" " a:hover, .slide label:hover { color: #FAFAFA; background: #894C84; }\r\n"
" a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial; width: 1.5em;}\r\n" " a.button { -webkit-appearance: button; -moz-appearance: button; appearance: button; text-decoration: none; color: initial; padding: 0 5px; }\r\n"
" .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n" " .header { font-size: 2.5em; text-align: center; margin: 1.5em 0; color: #894C84; }\r\n"
" .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n" " .wrapper { margin: 0 auto; padding: 1em; max-width: 60em; }\r\n"
" .left { float: left; position: absolute; }\r\n" " .left { float: left; position: absolute; }\r\n"
@ -93,6 +102,7 @@ namespace http {
const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config"; const char HTTP_COMMAND_RELOAD_CONFIG[] = "reload_config";
const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel"; const char HTTP_COMMAND_LOGLEVEL[] = "set_loglevel";
const char HTTP_COMMAND_KILLSTREAM[] = "closestream"; const char HTTP_COMMAND_KILLSTREAM[] = "closestream";
const char HTTP_COMMAND_LIMITTRANSIT[] = "limittransit";
const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
const char HTTP_PARAM_ADDRESS[] = "address"; const char HTTP_PARAM_ADDRESS[] = "address";
@ -397,18 +407,36 @@ namespace http {
} }
} }
s << "<br>\r\n"; s << "<br>\r\n";
s << "<b>Tags</b><br>Incoming: <i>" << dest->GetNumIncomingTags () << "</i><br>";
s << "<b>Tags</b><br>\r\nIncoming: <i>" << dest->GetNumIncomingTags () << "</i><br>\r\n";
if (!dest->GetSessions ().empty ()) { if (!dest->GetSessions ().empty ()) {
std::stringstream tmp_s; uint32_t out_tags = 0; std::stringstream tmp_s; uint32_t out_tags = 0;
for (const auto& it: dest->GetSessions ()) { for (const auto& it: dest->GetSessions ()) {
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n"; tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.first) << "</td><td>" << it.second->GetNumOutgoingTags () << "</td></tr>\r\n";
out_tags = out_tags + it.second->GetNumOutgoingTags (); out_tags += it.second->GetNumOutgoingTags ();
} }
s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type='checkbox' id='slide-tags'/>\r\n" s << "<div class='slide'><label for='slide-tags'>Outgoing: <i>" << out_tags << "</i></label>\r\n<input type='checkbox' id='slide-tags'/>\r\n"
<< "<div class='content'>\r\n<table><tbody><thead><th>Destination</th><th>Amount</th></thead>\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n"; << "<div class='content'>\r\n<table><tbody><thead><th>Destination</th><th>Amount</th></thead>\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
} else } else
s << "Outgoing: <i>0</i><br>\r\n"; s << "Outgoing: <i>0</i><br>\r\n";
s << "<br>\r\n"; s << "<br>\r\n";
auto numECIESx25519Tags = dest->GetNumIncomingECIESx25519Tags ();
if (numECIESx25519Tags > 0) {
s << "<b>ECIESx25519</b><br>\r\nIncoming Tags: <i>" << numECIESx25519Tags << "</i><br>\r\n";
if (!dest->GetECIESx25519Sessions ().empty ())
{
std::stringstream tmp_s; uint32_t ecies_sessions = 0;
for (const auto& it: dest->GetECIESx25519Sessions ()) {
tmp_s << "<tr><td>" << i2p::client::context.GetAddressBook ().ToAddress(it.second->GetDestination ()) << "</td><td>" << it.second->GetState () << "</td></tr>\r\n";
ecies_sessions++;
}
s << "<div class='slide'><label for='slide-ecies-sessions'>Tags sessions: <i>" << ecies_sessions << "</i></label>\r\n<input type='checkbox' id='slide-ecies-sessions'/>\r\n"
<< "<div class='content'>\r\n<table><tbody><thead><th>Destination</th><th>Status</th></thead>\r\n" << tmp_s.str () << "</tbody></table>\r\n</div>\r\n</div>\r\n";
} else
s << "Tags sessions: <i>0</i><br>\r\n";
s << "<br>\r\n";
}
} }
void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token) void ShowLocalDestination (std::stringstream& s, const std::string& b32, uint32_t token)
@ -580,14 +608,25 @@ namespace http {
else else
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#endif #endif
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n<br>\r\n";
s << "<br>\r\n<b>Logging level</b><br>\r\n"; s << "<small><b>Note:</b> any action done here are not persistent and not changes your config files.</small>\r\n<br>\r\n";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\">[none]</a> ";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> "; s << "<b>Logging level</b><br>\r\n";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\">[warn]</a> "; s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\"> none </a> \r\n";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\">[info]</a> "; s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\"> error </a> \r\n";
s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\">[debug]</a><br>\r\n"; s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\"> warn </a> \r\n";
s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\"> info </a> \r\n";
s << " <a class=\"button\" href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\"> debug </a><br>\r\n<br>\r\n";
uint16_t maxTunnels = GetMaxNumTransitTunnels ();
s << "<b>Transit tunnels limit</b><br>\r\n";
s << "<form method=\"get\" action=\"" << webroot << "\">\r\n";
s << " <input type=\"hidden\" name=\"cmd\" value=\"" << HTTP_COMMAND_LIMITTRANSIT << "\">\r\n";
s << " <input type=\"hidden\" name=\"token\" value=\"" << token << "\">\r\n";
s << " <input type=\"number\" min=\"0\" max=\"65535\" name=\"limit\" value=\"" << maxTunnels << "\">\r\n";
s << " <button type=\"submit\">Change</button>\r\n";
s << "</form>\r\n<br>\r\n";
} }
void ShowTransitTunnels (std::stringstream& s) void ShowTransitTunnels (std::stringstream& s)
@ -1125,6 +1164,19 @@ namespace http {
res.add_header("Refresh", redirect.c_str()); res.add_header("Refresh", redirect.c_str());
return; return;
} }
else if (cmd == HTTP_COMMAND_LIMITTRANSIT)
{
uint32_t limit = std::stoul(params["limit"], nullptr);
if (limit > 0 && limit <= 65535)
SetMaxNumTransitTunnels (limit);
else {
s << "<b>ERROR</b>:&nbsp;Transit tunnels count must not exceed 65535<br><br>\r\n";
s << "<a href=\"" << webroot << "?page=commands\">Back to commands list</a><br>\r\n";
s << "<p>You will be redirected back in 5 seconds</b>";
res.add_header("Refresh", redirect.c_str());
return;
}
}
else else
{ {
res.code = 400; res.code = 400;
@ -1182,8 +1234,9 @@ namespace http {
i2p::config::SetOption("http.pass", pass); i2p::config::SetOption("http.pass", pass);
LogPrint(eLogInfo, "HTTPServer: password set to ", pass); LogPrint(eLogInfo, "HTTPServer: password set to ", pass);
} }
m_IsRunning = true; m_IsRunning = true;
m_Thread = std::unique_ptr<std::thread>(new std::thread (std::bind (&HTTPServer::Run, this))); m_Thread.reset (new std::thread (std::bind (&HTTPServer::Run, this)));
m_Acceptor.listen (); m_Acceptor.listen ();
Accept (); Accept ();
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef HTTP_SERVER_H__ #ifndef HTTP_SERVER_H__
#define HTTP_SERVER_H__ #define HTTP_SERVER_H__

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <stdio.h> #include <stdio.h>
#include <sstream> #include <sstream>
#include <openssl/x509.h> #include <openssl/x509.h>
@ -80,8 +88,7 @@ namespace client
m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S; m_RouterInfoHandlers["i2p.router.net.bw.outbound.1s"] = &I2PControlService::OutboundBandwidth1S;
m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler; m_RouterInfoHandlers["i2p.router.net.status"] = &I2PControlService::NetStatusHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler; m_RouterInfoHandlers["i2p.router.net.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = m_RouterInfoHandlers["i2p.router.net.tunnels.successrate"] = &I2PControlService::TunnelsSuccessRateHandler;
&I2PControlService::TunnelsSuccessRateHandler;
m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes; m_RouterInfoHandlers["i2p.router.net.total.received.bytes"] = &I2PControlService::NetTotalReceivedBytes;
m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes; m_RouterInfoHandlers["i2p.router.net.total.sent.bytes"] = &I2PControlService::NetTotalSentBytes;

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef I2P_CONTROL_H__ #ifndef I2P_CONTROL_H__
#define I2P_CONTROL_H__ #define I2P_CONTROL_H__
@ -27,6 +35,7 @@ namespace client
class I2PControlService class I2PControlService
{ {
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket; typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
public: public:
I2PControlService (const std::string& address, int port); I2PControlService (const std::string& address, int port);

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifdef USE_UPNP #ifdef USE_UPNP
#include <string> #include <string>
#include <thread> #include <thread>
@ -110,7 +118,7 @@ namespace transport
} }
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr)); err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
m_upnpUrlsInitialized=err!=0; m_upnpUrlsInitialized = err != 0;
if (err == UPNP_IGD_VALID_CONNECTED) if (err == UPNP_IGD_VALID_CONNECTED)
{ {
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress); err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef __UPNP_H__ #ifndef __UPNP_H__
#define __UPNP_H__ #define __UPNP_H__
@ -60,7 +68,7 @@ namespace transport
std::mutex m_StartedMutex; std::mutex m_StartedMutex;
boost::asio::io_service m_Service; boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer; boost::asio::deadline_timer m_Timer;
bool m_upnpUrlsInitialized=false; bool m_upnpUrlsInitialized = false;
struct UPNPUrls m_upnpUrls; struct UPNPUrls m_upnpUrls;
struct IGDdatas m_upnpData; struct IGDdatas m_upnpData;

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include "Daemon.h" #include "Daemon.h"
#ifndef _WIN32 #ifndef _WIN32
@ -175,7 +183,6 @@ namespace i2p
bool DaemonLinux::stop() bool DaemonLinux::stop()
{ {
i2p::fs::Remove(pidfile); i2p::fs::Remove(pidfile);
return Daemon_Singleton::stop(); return Daemon_Singleton::stop();
} }
@ -197,5 +204,4 @@ namespace i2p
} }
} }
} }
#endif #endif

View File

@ -1,8 +1,15 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <stdlib.h> #include <stdlib.h>
#include "Daemon.h" #include "Daemon.h"
#if defined(QT_GUI_LIB) #if defined(QT_GUI_LIB)
namespace i2p namespace i2p
{ {
namespace qt namespace qt
@ -10,11 +17,11 @@ namespace qt
int RunQT (int argc, char* argv[]); int RunQT (int argc, char* argv[]);
} }
} }
int main( int argc, char* argv[] ) int main( int argc, char* argv[] )
{ {
return i2p::qt::RunQT (argc, argv); return i2p::qt::RunQT (argc, argv);
} }
#else #else
int main( int argc, char* argv[] ) int main( int argc, char* argv[] )
{ {

15
debian/changelog vendored
View File

@ -1,3 +1,18 @@
i2pd (2.32.0-1) unstable; urgency=high
* updated to version 2.32.0/0.9.46
* updated systemd service file (see #1394)
* updated apparmor profile (see 9318388007cff0495b4b360d0480f4fc1219a9dc)
* updated logrotate config and moved it to contrib
-- r4sas <r4sas@i2pmail.org> Mon, 25 May 2020 12:45:00 +0000
i2pd (2.31.0-1) unstable; urgency=medium
* updated to version 2.31.0
-- orignal <orignal@i2pmail.org> Fri, 10 Apr 2020 16:00:00 +0000
i2pd (2.30.0-1) unstable; urgency=medium i2pd (2.30.0-1) unstable; urgency=medium
* updated to version 2.30.0/0.9.45 * updated to version 2.30.0/0.9.45

6
debian/copyright vendored
View File

@ -3,7 +3,7 @@ Upstream-Name: i2pd
Source: https://github.com/PurpleI2P Source: https://github.com/PurpleI2P
Files: * Files: *
Copyright: 2013-2017 PurpleI2P Copyright: 2013-2020 PurpleI2P
License: BSD-3-clause License: BSD-3-clause
Files: qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl Files: qt/i2pd_qt/android/src/org/kde/necessitas/ministro/IMinistro.aidl
@ -16,8 +16,8 @@ License: BSD-2-Clause
Files: debian/* Files: debian/*
Copyright: 2013-2015 Kill Your TV <killyourtv@i2pmail.org> Copyright: 2013-2015 Kill Your TV <killyourtv@i2pmail.org>
2014-2016 hagen <hagen@i2pmail.org> 2014-2016 hagen <hagen@i2pmail.org>
2016-2017 R4SAS <r4sas@i2pmail.org> 2016-2020 R4SAS <r4sas@i2pmail.org>
2017-2018 Yangfl <mmyangfl@gmail.com> 2017-2020 Yangfl <mmyangfl@gmail.com>
License: GPL-2+ License: GPL-2+
License: BSD-3-clause License: BSD-3-clause

View File

@ -1,9 +0,0 @@
/var/log/i2pd/i2pd.log {
rotate 6
daily
missingok
notifempty
compress
delaycompress
copytruncate
}

1
debian/i2pd.logrotate vendored Symbolic link
View File

@ -0,0 +1 @@
../contrib/i2pd.logrotate

View File

@ -1,17 +1,15 @@
diff --git a/Makefile b/Makefile Index: i2pd/Makefile
index bdadfe0..2f71eec 100644 ===================================================================
--- a/Makefile --- i2pd.orig/Makefile
+++ b/Makefile +++ i2pd/Makefile
@@ -9,10 +9,10 @@ DEPS := obj/make.dep @@ -13,8 +13,8 @@ DAEMON_SRC_DIR := daemon
include filelist.mk include filelist.mk
-USE_AESNI := yes -USE_AESNI := yes
+USE_AESNI := no
-USE_AVX := yes -USE_AVX := yes
+USE_AESNI := no
+USE_AVX := no +USE_AVX := no
USE_STATIC := no USE_STATIC := no
USE_MESHNET := no USE_MESHNET := no
USE_UPNP := no USE_UPNP := no
DEBUG := yes

View File

@ -4,10 +4,12 @@ Author: r4sas <r4sas@i2pmail.org>
Bug: https://github.com/PurpleI2P/i2pd/issues/1210 Bug: https://github.com/PurpleI2P/i2pd/issues/1210
Reviewed-By: r4sas <r4sas@i2pmail.org> Reviewed-By: r4sas <r4sas@i2pmail.org>
Last-Update: 2018-08-25 Last-Update: 2020-05-25
--- a/contrib/i2pd.service Index: i2pd/contrib/i2pd.service
+++ b/contrib/i2pd.service ===================================================================
--- i2pd.orig/contrib/i2pd.service
+++ i2pd/contrib/i2pd.service
@@ -6,10 +6,10 @@ After=network.target @@ -6,10 +6,10 @@ After=network.target
[Service] [Service]
User=i2pd User=i2pd
@ -21,5 +23,5 @@ Last-Update: 2018-08-25
+#LogsDirectory=i2pd +#LogsDirectory=i2pd
+#LogsDirectoryMode=0700 +#LogsDirectoryMode=0700
Type=forking Type=forking
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID ExecReload=/bin/sh -c "kill -HUP $MAINPID"

2
debian/postrm vendored
View File

@ -6,7 +6,7 @@ if [ "$1" = "purge" ]; then
rm -rf /etc/i2pd rm -rf /etc/i2pd
rm -rf /var/lib/i2pd rm -rf /var/lib/i2pd
rm -rf /var/log/i2pd rm -rf /var/log/i2pd
rm -rf /var/run/i2pd rm -rf /run/i2pd
fi fi
#DEBHELPER# #DEBHELPER#

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -7,7 +15,8 @@ namespace i2p
{ {
namespace data namespace data
{ {
static const char T32[32] = { static const char T32[32] =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
@ -29,7 +38,8 @@ namespace data
* Direct Substitution Table * Direct Substitution Table
*/ */
static const char T64[64] = { static const char T64[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@ -67,14 +77,12 @@ namespace data
* *
*/ */
size_t /* Number of bytes in the encoded buffer */ size_t ByteStreamToBase64 ( /* Number of bytes in the encoded buffer */
ByteStreamToBase64 (
const uint8_t * InBuffer, /* Input buffer, binary data */ const uint8_t * InBuffer, /* Input buffer, binary data */
size_t InCount, /* Number of bytes in the input buffer */ size_t InCount, /* Number of bytes in the input buffer */
char * OutBuffer, /* output buffer */ char * OutBuffer, /* output buffer */
size_t len /* length of output buffer */ size_t len /* length of output buffer */
) )
{ {
unsigned char * ps; unsigned char * ps;
unsigned char * pd; unsigned char * pd;
@ -86,33 +94,37 @@ namespace data
size_t outCount; size_t outCount;
ps = (unsigned char *)InBuffer; ps = (unsigned char *)InBuffer;
n = InCount/3; n = InCount / 3;
m = InCount%3; m = InCount % 3;
if (!m) if (!m)
outCount = 4*n; outCount = 4 * n;
else else
outCount = 4*(n+1); outCount = 4 * (n + 1);
if (outCount > len) return 0; if (outCount > len) return 0;
pd = (unsigned char *)OutBuffer; pd = (unsigned char *)OutBuffer;
for ( i = 0; i<n; i++ ){ for ( i = 0; i < n; i++ )
{
acc_1 = *ps++; acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x30; acc_2 = (acc_1 << 4) & 0x30;
acc_1 >>= 2; /* base64 digit #1 */ acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1]; *pd++ = T64[acc_1];
acc_1 = *ps++; acc_1 = *ps++;
acc_2 |= acc_1 >> 4; /* base64 digit #2 */ acc_2 |= acc_1 >> 4; /* base64 digit #2 */
*pd++ = T64[acc_2]; *pd++ = T64[acc_2];
acc_1 &= 0x0f; acc_1 &= 0x0f;
acc_1 <<=2; acc_1 <<= 2;
acc_2 = *ps++; acc_2 = *ps++;
acc_1 |= acc_2>>6; /* base64 digit #3 */ acc_1 |= acc_2 >> 6; /* base64 digit #3 */
*pd++ = T64[acc_1]; *pd++ = T64[acc_1];
acc_2 &= 0x3f; /* base64 digit #4 */ acc_2 &= 0x3f; /* base64 digit #4 */
*pd++ = T64[acc_2]; *pd++ = T64[acc_2];
} }
if ( m == 1 ){ if ( m == 1 )
{
acc_1 = *ps++; acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */ acc_2 = (acc_1 << 4) & 0x3f; /* base64 digit #2 */
acc_1 >>= 2; /* base64 digit #1 */ acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1]; *pd++ = T64[acc_1];
*pd++ = T64[acc_2]; *pd++ = T64[acc_2];
@ -120,16 +132,17 @@ namespace data
*pd++ = P64; *pd++ = P64;
} }
else if ( m == 2 ){ else if ( m == 2 )
{
acc_1 = *ps++; acc_1 = *ps++;
acc_2 = (acc_1<<4)&0x3f; acc_2 = (acc_1 << 4) & 0x3f;
acc_1 >>= 2; /* base64 digit #1 */ acc_1 >>= 2; /* base64 digit #1 */
*pd++ = T64[acc_1]; *pd++ = T64[acc_1];
acc_1 = *ps++; acc_1 = *ps++;
acc_2 |= acc_1 >> 4; /* base64 digit #2 */ acc_2 |= acc_1 >> 4; /* base64 digit #2 */
*pd++ = T64[acc_2]; *pd++ = T64[acc_2];
acc_1 &= 0x0f; acc_1 &= 0x0f;
acc_1 <<=2; /* base64 digit #3 */ acc_1 <<= 2; /* base64 digit #3 */
*pd++ = T64[acc_1]; *pd++ = T64[acc_1];
*pd++ = P64; *pd++ = P64;
} }
@ -147,8 +160,7 @@ namespace data
* *
*/ */
size_t /* Number of output bytes */ size_t Base64ToByteStream ( /* Number of output bytes */
Base64ToByteStream (
const char * InBuffer, /* BASE64 encoded buffer */ const char * InBuffer, /* BASE64 encoded buffer */
size_t InCount, /* Number of input bytes */ size_t InCount, /* Number of input bytes */
uint8_t * OutBuffer, /* output buffer length */ uint8_t * OutBuffer, /* output buffer length */
@ -164,36 +176,46 @@ namespace data
int m; int m;
size_t outCount; size_t outCount;
if (isFirstTime) iT64Build(); if (isFirstTime)
n = InCount/4; iT64Build();
m = InCount%4;
n = InCount / 4;
m = InCount % 4;
if (InCount && !m) if (InCount && !m)
outCount = 3*n; outCount = 3 * n;
else { else
{
outCount = 0; outCount = 0;
return 0; return 0;
} }
ps = (unsigned char *)(InBuffer + InCount - 1); ps = (unsigned char *)(InBuffer + InCount - 1);
while ( *ps-- == P64 ) outCount--; while ( *ps-- == P64 )
outCount--;
ps = (unsigned char *)InBuffer; ps = (unsigned char *)InBuffer;
if (outCount > len) return -1; if (outCount > len)
return -1;
pd = OutBuffer; pd = OutBuffer;
auto endOfOutBuffer = OutBuffer + outCount; auto endOfOutBuffer = OutBuffer + outCount;
for ( i = 0; i < n; i++ ){ for ( i = 0; i < n; i++ )
{
acc_1 = iT64[*ps++]; acc_1 = iT64[*ps++];
acc_2 = iT64[*ps++]; acc_2 = iT64[*ps++];
acc_1 <<= 2; acc_1 <<= 2;
acc_1 |= acc_2>>4; acc_1 |= acc_2 >> 4;
*pd++ = acc_1; *pd++ = acc_1;
if (pd >= endOfOutBuffer) break; if (pd >= endOfOutBuffer)
break;
acc_2 <<= 4; acc_2 <<= 4;
acc_1 = iT64[*ps++]; acc_1 = iT64[*ps++];
acc_2 |= acc_1 >> 2; acc_2 |= acc_1 >> 2;
*pd++ = acc_2; *pd++ = acc_2;
if (pd >= endOfOutBuffer) break; if (pd >= endOfOutBuffer)
break;
acc_2 = iT64[*ps++]; acc_2 = iT64[*ps++];
acc_2 |= acc_1 << 6; acc_2 |= acc_1 << 6;
@ -206,20 +228,25 @@ namespace data
size_t Base64EncodingBufferSize (const size_t input_size) size_t Base64EncodingBufferSize (const size_t input_size)
{ {
auto d = div (input_size, 3); auto d = div (input_size, 3);
if (d.rem) d.quot++; if (d.rem)
return 4*d.quot; d.quot++;
return 4 * d.quot;
} }
std::string ToBase64Standard (const std::string& in) std::string ToBase64Standard (const std::string& in)
{ {
auto len = Base64EncodingBufferSize (in.length ()); auto len = Base64EncodingBufferSize (in.length ());
char * str = new char[len+1]; char * str = new char[len + 1];
auto l = ByteStreamToBase64 ((const uint8_t *)in.c_str (), in.length (), str, len); auto l = ByteStreamToBase64 ((const uint8_t *)in.c_str (), in.length (), str, len);
str[l] = 0; str[l] = 0;
// replace '-' by '+' and '~' by '/' // replace '-' by '+' and '~' by '/'
for (size_t i = 0; i < l; i++) for (size_t i = 0; i < l; i++)
if (str[i] == '-') str[i] = '+'; if (str[i] == '-')
else if (str[i] == '~') str[i] = '/'; str[i] = '+';
else if (str[i] == '~')
str[i] = '/';
std::string s(str); std::string s(str);
delete[] str; delete[] str;
return s; return s;
@ -238,8 +265,8 @@ namespace data
{ {
int i; int i;
isFirstTime = 0; isFirstTime = 0;
for ( i=0; i<256; i++ ) iT64[i] = -1; for ( i = 0; i < 256; i++ ) iT64[i] = -1;
for ( i=0; i<64; i++ ) iT64[(int)T64[i]] = i; for ( i = 0; i < 64; i++ ) iT64[(int)T64[i]] = i;
iT64[(int)P64] = 0; iT64[(int)P64] = 0;
} }
@ -302,4 +329,3 @@ namespace data
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef BASE_H__ #ifndef BASE_H__
#define BASE_H__ #define BASE_H__

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <zlib.h> // for crc32 #include <zlib.h> // for crc32
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
@ -314,4 +322,3 @@ namespace data
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef BLINDING_H__ #ifndef BLINDING_H__
#define BLINDING_H__ #define BLINDING_H__

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include "BloomFilter.h" #include "BloomFilter.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#include <array> #include <array>

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef BLOOM_FILTER_H_ #ifndef BLOOM_FILTER_H_
#define BLOOM_FILTER_H_ #define BLOOM_FILTER_H_
#include <memory> #include <memory>

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include "CPU.h" #include "CPU.h"
#if defined(__x86_64__) || defined(__i386__) #if defined(__x86_64__) || defined(__i386__)
#include <cpuid.h> #include <cpuid.h>

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef LIBI2PD_CPU_H #ifndef LIBI2PD_CPU_H
#define LIBI2PD_CPU_H #define LIBI2PD_CPU_H

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2018, 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
* *
@ -78,7 +78,6 @@ void block (Chacha20State &input, int rounds)
} }
x += input; x += input;
input.block << x; input.block << x;
} }
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter) void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter)
@ -130,9 +129,9 @@ void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz)
} }
} }
} }
} // namespace chacha } // namespace chacha
} // namespace crypto
} // namespace i2p
}
}
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2018, 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
* *
@ -64,9 +64,9 @@ namespace chacha
void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter); void Chacha20Init (Chacha20State& state, const uint8_t * nonce, const uint8_t * key, uint32_t counter);
void Chacha20SetCounter (Chacha20State& state, uint32_t counter); void Chacha20SetCounter (Chacha20State& state, uint32_t counter);
void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); // encrypt buf in place void Chacha20Encrypt (Chacha20State& state, uint8_t * buf, size_t sz); // encrypt buf in place
} } // namespace chacha
} } // namespace crypto
} } // namespace i2p
#endif
#endif #endif
#endif

View File

@ -1,5 +1,5 @@
/* /*
* 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
* *
@ -39,7 +39,7 @@ namespace config {
("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)") ("pidfile", value<std::string>()->default_value(""), "Path to pidfile (default: ~/i2pd/i2pd.pid or /var/lib/i2pd/i2pd.pid)")
("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)") ("log", value<std::string>()->default_value(""), "Logs destination: stdout, file, syslog (stdout if not set)")
("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)") ("logfile", value<std::string>()->default_value(""), "Path to logfile (stdout if not set, autodetect if daemon)")
("loglevel", value<std::string>()->default_value("info"), "Set the minimal level of log messages (debug, info, warn, error, none)") ("loglevel", value<std::string>()->default_value("warn"), "Set the minimal level of log messages (debug, info, warn, error, none)")
("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)") ("logclftime", bool_switch()->default_value(false), "Write full CLF-formatted date and time to log (default: disabled, write only time)")
("family", value<std::string>()->default_value(""), "Specify a family, router belongs to") ("family", value<std::string>()->default_value(""), "Specify a family, router belongs to")
("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)") ("datadir", value<std::string>()->default_value(""), "Path to storage of i2pd data (RI, keys, peer profiles, ...)")
@ -97,7 +97,8 @@ namespace config {
("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address") ("httpproxy.address", value<std::string>()->default_value("127.0.0.1"), "HTTP Proxy listen address")
("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port") ("httpproxy.port", value<uint16_t>()->default_value(4444), "HTTP Proxy listen port")
("httpproxy.keys", value<std::string>()->default_value(""), "File to persist HTTP Proxy keys") ("httpproxy.keys", value<std::string>()->default_value(""), "File to persist HTTP Proxy keys")
("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") ("httpproxy.signaturetype", value<i2p::data::SigningKeyType>()->
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length") ("httpproxy.inbound.length", value<std::string>()->default_value("3"), "HTTP proxy inbound tunnel length")
("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length") ("httpproxy.outbound.length", value<std::string>()->default_value("3"), "HTTP proxy outbound tunnel length")
("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity") ("httpproxy.inbound.quantity", value<std::string>()->default_value("5"), "HTTP proxy inbound tunnels quantity")
@ -106,6 +107,8 @@ namespace config {
("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels") ("httpproxy.latency.max", value<std::string>()->default_value("0"), "HTTP proxy max latency for tunnels")
("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url") ("httpproxy.outproxy", value<std::string>()->default_value(""), "HTTP proxy upstream out proxy url")
("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper") ("httpproxy.addresshelper", value<bool>()->default_value(true), "Enable or disable addresshelper")
("httpproxy.i2cp.leaseSetType", value<std::string>()->default_value("1"), "Local destination's LeaseSet type")
("httpproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0"), "Local destination's LeaseSet encryption type")
; ;
options_description socksproxy("SOCKS Proxy options"); options_description socksproxy("SOCKS Proxy options");
@ -114,7 +117,8 @@ namespace config {
("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address") ("socksproxy.address", value<std::string>()->default_value("127.0.0.1"), "SOCKS Proxy listen address")
("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port") ("socksproxy.port", value<uint16_t>()->default_value(4447), "SOCKS Proxy listen port")
("socksproxy.keys", value<std::string>()->default_value(""), "File to persist SOCKS Proxy keys") ("socksproxy.keys", value<std::string>()->default_value(""), "File to persist SOCKS Proxy keys")
("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()->default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default") ("socksproxy.signaturetype", value<i2p::data::SigningKeyType>()->
default_value(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519), "Signature type for new keys. 7 (EdDSA) by default")
("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length") ("socksproxy.inbound.length", value<std::string>()->default_value("3"), "SOCKS proxy inbound tunnel length")
("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length") ("socksproxy.outbound.length", value<std::string>()->default_value("3"), "SOCKS proxy outbound tunnel length")
("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity") ("socksproxy.inbound.quantity", value<std::string>()->default_value("5"), "SOCKS proxy inbound tunnels quantity")
@ -124,6 +128,8 @@ namespace config {
("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy") ("socksproxy.outproxy.enabled", value<bool>()->default_value(false), "Enable or disable SOCKS outproxy")
("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy") ("socksproxy.outproxy", value<std::string>()->default_value("127.0.0.1"), "Upstream outproxy address for SOCKS Proxy")
("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy") ("socksproxy.outproxyport", value<uint16_t>()->default_value(9050), "Upstream outproxy port for SOCKS Proxy")
("socksproxy.i2cp.leaseSetType", value<std::string>()->default_value("1"), "Local destination's LeaseSet type")
("socksproxy.i2cp.leaseSetEncType", value<std::string>()->default_value("0"), "Local destination's LeaseSet encryption type")
; ;
options_description sam("SAM bridge options"); options_description sam("SAM bridge options");
@ -190,15 +196,12 @@ namespace config {
("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://i2p.mooo.com/netDb/," "https://i2p.mooo.com/netDb/,"
"https://netdb.i2p2.no/,"
"https://reseed.i2p2.no/," "https://reseed.i2p2.no/,"
"https://reseed2.i2p2.no/,"
// "https://us.reseed.i2p2.no:444/," // mamoth's shit
// "https://uk.reseed.i2p2.no:444/," // mamoth's shit
"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://i2p.novg.net/" "https://i2p.novg.net/"
), "Reseed URLs, separated by comma") ), "Reseed URLs, separated by comma")
; ;
@ -218,6 +221,14 @@ namespace config {
("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?") ("trust.hidden", value<bool>()->default_value(false), "Should we hide our router from other routers?")
; ;
// Save deprecated websocket options for compatibility
options_description websocket("Websocket Options");
websocket.add_options()
("websockets.enabled", value<bool>()->default_value(false), "Deprecated option")
("websockets.address", value<std::string>()->default_value(""), "Deprecated option")
("websockets.port", value<uint16_t>()->default_value(0), "Deprecated option")
;
options_description exploratory("Exploratory Options"); options_description exploratory("Exploratory Options");
exploratory.add_options() exploratory.add_options()
("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length") ("exploratory.inbound.length", value<int>()->default_value(2), "Exploratory inbound tunnel length")
@ -268,6 +279,7 @@ namespace config {
.add(reseed) .add(reseed)
.add(addressbook) .add(addressbook)
.add(trust) .add(trust)
.add(websocket) // deprecated
.add(exploratory) .add(exploratory)
.add(ntcp2) .add(ntcp2)
.add(nettime) .add(nettime)

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
@ -63,7 +71,8 @@ namespace config {
*/ */
void Finalize(); void Finalize();
/* @brief Accessor to parameters by name /**
* @brief Accessor to parameters by name
* @param name Name of the requested parameter * @param name Name of the requested parameter
* @param value Variable where to store option * @param value Variable where to store option
* @return this function returns false if parameter not found * @return this function returns false if parameter not found
@ -71,7 +80,8 @@ namespace config {
* Example: uint16_t port; GetOption("sam.port", port); * Example: uint16_t port; GetOption("sam.port", port);
*/ */
template<typename T> template<typename T>
bool GetOption(const char *name, T& value) { bool GetOption(const char *name, T& value)
{
if (!m_Options.count(name)) if (!m_Options.count(name))
return false; return false;
value = m_Options[name].as<T>(); value = m_Options[name].as<T>();
@ -96,7 +106,8 @@ namespace config {
* Example: uint16_t port = 2827; SetOption("bob.port", port); * Example: uint16_t port = 2827; SetOption("bob.port", port);
*/ */
template<typename T> template<typename T>
bool SetOption(const char *name, const T& value) { bool SetOption(const char *name, const T& value)
{
if (!m_Options.count(name)) if (!m_Options.count(name))
return false; return false;
m_Options.at(name).value() = value; m_Options.at(name).value() = value;

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <vector> #include <vector>
@ -884,7 +892,6 @@ namespace crypto
} }
} }
void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out) void CBCEncryption::Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out)
{ {
#ifdef __AES__ #ifdef __AES__
@ -1364,4 +1371,3 @@ namespace crypto
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef CRYPTO_H__ #ifndef CRYPTO_H__
#define CRYPTO_H__ #define CRYPTO_H__

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <string.h> #include <string.h>
#include "Log.h" #include "Log.h"
#include "Gost.h" #include "Gost.h"
@ -178,4 +186,3 @@ namespace crypto
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef CRYPTO_KEY_H__ #ifndef CRYPTO_KEY_H__
#define CRYPTO_KEY_H__ #define CRYPTO_KEY_H__
@ -153,4 +161,3 @@ namespace crypto
} }
#endif #endif

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef CRYPTO_WORKER_H_ #ifndef CRYPTO_WORKER_H_
#define CRYPTO_WORKER_H_ #define CRYPTO_WORKER_H_
@ -77,5 +85,4 @@ namespace worker
} }
} }
#endif #endif

View File

@ -1,5 +1,12 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <string.h> #include <string.h>
#include <vector>
#include "Crypto.h" #include "Crypto.h"
#include "Log.h" #include "Log.h"
#include "TunnelBase.h" #include "TunnelBase.h"
@ -11,9 +18,13 @@ namespace i2p
{ {
namespace datagram namespace datagram
{ {
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner): DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip):
m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr) m_Owner (owner), m_Receiver (nullptr), m_RawReceiver (nullptr), m_Gzip (gzip)
{ {
auto identityLen = m_Owner->GetIdentity ()->GetFullLen ();
m_From.resize (identityLen);
m_Owner->GetIdentity ()->ToBuffer (m_From.data (), identityLen);
m_Signature.resize (m_Owner->GetIdentity ()->GetSignatureLen ());
} }
DatagramDestination::~DatagramDestination () DatagramDestination::~DatagramDestination ()
@ -23,35 +34,25 @@ namespace datagram
void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort) void DatagramDestination::SendDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
{ {
auto owner = m_Owner; if (m_Owner->GetIdentity ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
uint8_t * buf = v.data();
auto localIdentity = m_Owner->GetIdentity ();
auto identityLen = localIdentity->ToBuffer (buf, MAX_DATAGRAM_SIZE);
uint8_t * signature = buf + identityLen;
auto signatureLen = localIdentity->GetSignatureLen ();
uint8_t * buf1 = signature + signatureLen;
size_t headerLen = identityLen + signatureLen;
memcpy (buf1, payload, len);
if (localIdentity->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
{ {
uint8_t hash[32]; uint8_t hash[32];
SHA256(buf1, len, hash); SHA256(payload, len, hash);
owner->Sign (hash, 32, signature); m_Owner->Sign (hash, 32, m_Signature.data ());
} }
else else
owner->Sign (buf1, len, signature); m_Owner->Sign (payload, len, m_Signature.data ());
auto msg = CreateDataMessage (buf, len + headerLen, fromPort, toPort);
auto session = ObtainSession(identity); auto session = ObtainSession(identity);
auto msg = CreateDataMessage ({{m_From.data (), m_From.size ()}, {m_Signature.data (), m_Signature.size ()}, {payload, len}},
fromPort, toPort, false, !session->IsRatchets ()); // datagram
session->SendMsg(msg); session->SendMsg(msg);
} }
void DatagramDestination::SendRawDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort) void DatagramDestination::SendRawDatagramTo(const uint8_t * payload, size_t len, const i2p::data::IdentHash & identity, uint16_t fromPort, uint16_t toPort)
{ {
auto msg = CreateDataMessage (payload, len, fromPort, toPort, true); // raw
auto session = ObtainSession(identity); auto session = ObtainSession(identity);
auto msg = CreateDataMessage ({{payload, len}}, fromPort, toPort, true, !session->IsRatchets ()); // raw
session->SendMsg(msg); session->SendMsg(msg);
} }
@ -121,13 +122,15 @@ namespace datagram
LogPrint (eLogWarning, "Datagram: decompression failed"); LogPrint (eLogWarning, "Datagram: decompression failed");
} }
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (
std::shared_ptr<I2NPMessage> DatagramDestination::CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort, bool isRaw) const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
uint16_t fromPort, uint16_t toPort, bool isRaw, bool checksum)
{ {
auto msg = NewI2NPMessage (); auto msg = NewI2NPMessage ();
uint8_t * buf = msg->GetPayload (); uint8_t * buf = msg->GetPayload ();
buf += 4; // reserve for length buf += 4; // reserve for length
size_t size = m_Deflator.Deflate (payload, len, buf, msg->maxLen - msg->len); size_t size = m_Gzip ? m_Deflator.Deflate (payloads, buf, msg->maxLen - msg->len) :
i2p::data::GzipNoCompression (payloads, buf, msg->maxLen - msg->len);
if (size) if (size)
{ {
htobe32buf (msg->GetPayload (), size); // length htobe32buf (msg->GetPayload (), size); // length
@ -135,7 +138,7 @@ namespace datagram
htobe16buf (buf + 6, toPort); // destination port htobe16buf (buf + 6, toPort); // destination port
buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol buf[9] = isRaw ? i2p::client::PROTOCOL_TYPE_RAW : i2p::client::PROTOCOL_TYPE_DATAGRAM; // raw or datagram protocol
msg->len += size + 4; msg->len += size + 4;
msg->FillI2NPMessageHeader (eI2NPData); msg->FillI2NPMessageHeader (eI2NPData, 0, checksum);
} }
else else
msg = nullptr; msg = nullptr;
@ -247,11 +250,14 @@ namespace datagram
auto path = GetSharedRoutingPath(); auto path = GetSharedRoutingPath();
if(path) if(path)
path->updateTime = i2p::util::GetSecondsSinceEpoch (); path->updateTime = i2p::util::GetSecondsSinceEpoch ();
if (IsRatchets ())
SendMsg (nullptr); // send empty message in case if we have some data to send
} }
std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath () std::shared_ptr<i2p::garlic::GarlicRoutingPath> DatagramSession::GetSharedRoutingPath ()
{ {
if(!m_RoutingSession) { if (!m_RoutingSession || !m_RoutingSession->GetOwner ())
{
if(!m_RemoteLeaseSet) { if(!m_RemoteLeaseSet) {
m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent); m_RemoteLeaseSet = m_LocalDestination->FindLeaseSet(m_RemoteIdent);
} }
@ -352,6 +358,7 @@ namespace datagram
void DatagramSession::HandleSend(std::shared_ptr<I2NPMessage> msg) void DatagramSession::HandleSend(std::shared_ptr<I2NPMessage> msg)
{ {
if (msg || m_SendQueue.empty ())
m_SendQueue.push_back(msg); m_SendQueue.push_back(msg);
// flush queue right away if full // flush queue right away if full
if(m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE) FlushSendQueue(); if(m_SendQueue.size() >= DATAGRAM_SEND_QUEUE_MAX_SIZE) FlushSendQueue();
@ -359,7 +366,6 @@ namespace datagram
void DatagramSession::FlushSendQueue () void DatagramSession::FlushSendQueue ()
{ {
std::vector<i2p::tunnel::TunnelMessageBlock> send; std::vector<i2p::tunnel::TunnelMessageBlock> send;
auto routingPath = GetSharedRoutingPath(); auto routingPath = GetSharedRoutingPath();
// if we don't have a routing path we will drop all queued messages // if we don't have a routing path we will drop all queued messages
@ -368,6 +374,7 @@ namespace datagram
for (const auto & msg : m_SendQueue) for (const auto & msg : m_SendQueue)
{ {
auto m = m_RoutingSession->WrapSingleMessage(msg); auto m = m_RoutingSession->WrapSingleMessage(msg);
if (m)
send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m}); send.push_back(i2p::tunnel::TunnelMessageBlock{i2p::tunnel::eDeliveryTypeTunnel,routingPath->remoteLease->tunnelGateway, routingPath->remoteLease->tunnelID, m});
} }
routingPath->outboundTunnel->SendTunnelDataMsg(send); routingPath->outboundTunnel->SendTunnelDataMsg(send);
@ -385,4 +392,3 @@ namespace datagram
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef DATAGRAM_H__ #ifndef DATAGRAM_H__
#define DATAGRAM_H__ #define DATAGRAM_H__
@ -5,6 +13,7 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <map> #include <map>
#include <vector>
#include "Base.h" #include "Base.h"
#include "Identity.h" #include "Identity.h"
#include "LeaseSet.h" #include "LeaseSet.h"
@ -36,7 +45,9 @@ namespace datagram
class DatagramSession : public std::enable_shared_from_this<DatagramSession> class DatagramSession : public std::enable_shared_from_this<DatagramSession>
{ {
public: public:
DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, const i2p::data::IdentHash & remoteIdent); DatagramSession(std::shared_ptr<i2p::client::ClientDestination> localDestination, const i2p::data::IdentHash & remoteIdent);
void Start (); void Start ();
@ -51,6 +62,8 @@ namespace datagram
/** get the last time in milliseconds for when we used this datagram session */ /** get the last time in milliseconds for when we used this datagram session */
uint64_t LastActivity() const { return m_LastUse; } uint64_t LastActivity() const { return m_LastUse; }
bool IsRatchets () const { return m_RoutingSession && m_RoutingSession->IsRatchets (); }
struct Info struct Info
{ {
std::shared_ptr<const i2p::data::IdentHash> IBGW; std::shared_ptr<const i2p::data::IdentHash> IBGW;
@ -81,6 +94,7 @@ namespace datagram
void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls); void HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls);
private: private:
std::shared_ptr<i2p::client::ClientDestination> m_LocalDestination; std::shared_ptr<i2p::client::ClientDestination> m_LocalDestination;
i2p::data::IdentHash m_RemoteIdent; i2p::data::IdentHash m_RemoteIdent;
std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet; std::shared_ptr<const i2p::data::LeaseSet> m_RemoteLeaseSet;
@ -101,11 +115,9 @@ namespace datagram
typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver; typedef std::function<void (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> Receiver;
typedef std::function<void (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> RawReceiver; typedef std::function<void (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len)> RawReceiver;
public: public:
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner, bool gzip);
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner);
~DatagramDestination (); ~DatagramDestination ();
void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0); void SendDatagramTo (const uint8_t * payload, size_t len, const i2p::data::IdentHash & ident, uint16_t fromPort = 0, uint16_t toPort = 0);
@ -130,7 +142,8 @@ namespace datagram
std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident); std::shared_ptr<DatagramSession> ObtainSession(const i2p::data::IdentHash & ident);
std::shared_ptr<I2NPMessage> CreateDataMessage (const uint8_t * payload, size_t len, uint16_t fromPort, uint16_t toPort, bool isRaw = false); std::shared_ptr<I2NPMessage> CreateDataMessage (const std::vector<std::pair<const uint8_t *, size_t> >& payloads,
uint16_t fromPort, uint16_t toPort, bool isRaw = false, bool checksum = true);
void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len); void HandleDatagram (uint16_t fromPort, uint16_t toPort, uint8_t *const& buf, size_t len);
void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleRawDatagram (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
@ -143,6 +156,7 @@ namespace datagram
std::shared_ptr<i2p::client::ClientDestination> m_Owner; std::shared_ptr<i2p::client::ClientDestination> m_Owner;
Receiver m_Receiver; // default Receiver m_Receiver; // default
RawReceiver m_RawReceiver; // default RawReceiver m_RawReceiver; // default
bool m_Gzip; // gzip compression of data messages
std::mutex m_SessionsMutex; std::mutex m_SessionsMutex;
std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions; std::map<i2p::data::IdentHash, DatagramSession_ptr > m_Sessions;
std::mutex m_ReceiversMutex; std::mutex m_ReceiversMutex;
@ -150,6 +164,7 @@ namespace datagram
i2p::data::GzipInflator m_Inflator; i2p::data::GzipInflator m_Inflator;
i2p::data::GzipDeflator m_Deflator; i2p::data::GzipDeflator m_Deflator;
std::vector<uint8_t> m_From, m_Signature;
}; };
} }
} }

View File

@ -1,6 +1,17 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#include <string> #include <string>
#include <set>
#include <vector>
#include <boost/algorithm/string.hpp>
#include "Crypto.h" #include "Crypto.h"
#include "Log.h" #include "Log.h"
#include "FS.h" #include "FS.h"
@ -157,7 +168,6 @@ namespace client
bool LeaseSetDestination::Reconfigure(std::map<std::string, std::string> params) bool LeaseSetDestination::Reconfigure(std::map<std::string, std::string> params)
{ {
auto itr = params.find("i2cp.dontPublishLeaseSet"); auto itr = params.find("i2cp.dontPublishLeaseSet");
if (itr != params.end()) if (itr != params.end())
{ {
@ -412,7 +422,8 @@ namespace client
auto it2 = m_LeaseSetRequests.find (key); auto it2 = m_LeaseSetRequests.find (key);
if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey) if (it2 != m_LeaseSetRequests.end () && it2->second->requestedBlindedKey)
{ {
auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset, it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? *m_LeaseSetPrivKey : nullptr, GetPreferredCryptoType ()); auto ls2 = std::make_shared<i2p::data::LeaseSet2> (buf + offset, len - offset,
it2->second->requestedBlindedKey, m_LeaseSetPrivKey ? ((const uint8_t *)*m_LeaseSetPrivKey) : nullptr , GetPreferredCryptoType ());
if (ls2->IsValid ()) if (ls2->IsValid ())
{ {
m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key m_RemoteLeaseSets[ls2->GetIdentHash ()] = ls2; // ident is not key
@ -824,8 +835,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_RARCHET)) if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET; return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET;
return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
} }
@ -839,23 +850,53 @@ namespace client
if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) if (keys.IsOfflineSignature () && GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only SetLeaseSetType (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2); // offline keys can be published with LS2 only
m_EncryptionKeyType = GetIdentity ()->GetCryptoKeyType ();
// extract encryption type params for LS2 // extract encryption type params for LS2
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 && params) std::set<i2p::data::CryptoKeyType> encryptionKeyTypes;
if ((GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2 ||
GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2) && params)
{ {
auto it = params->find (I2CP_PARAM_LEASESET_ENCRYPTION_TYPE); auto it = params->find (I2CP_PARAM_LEASESET_ENCRYPTION_TYPE);
if (it != params->end ()) if (it != params->end ())
m_EncryptionKeyType = std::stoi(it->second); {
// comma-separated values
std::vector<std::string> values;
boost::split(values, it->second, boost::is_any_of(","));
for (auto& it1: values)
{
try
{
encryptionKeyTypes.insert (std::stoi(it1));
}
catch (std::exception& ex)
{
LogPrint (eLogInfo, "Destination: Unexpected crypto type ", it1, ". ", ex.what ());
continue;
}
}
}
}
// if no param or valid crypto type use from identity
bool isSingleKey = false;
if (encryptionKeyTypes.empty ())
{
isSingleKey = true;
encryptionKeyTypes.insert (GetIdentity ()->GetCryptoKeyType ());
} }
memset (m_EncryptionPrivateKey, 0, 256); for (auto& it: encryptionKeyTypes)
memset (m_EncryptionPublicKey, 0, 256); {
auto encryptionKey = new EncryptionKey (it);
if (isPublic) if (isPublic)
PersistTemporaryKeys (); PersistTemporaryKeys (encryptionKey, isSingleKey);
else else
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey); encryptionKey->GenerateKeys ();
encryptionKey->CreateDecryptor ();
if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
m_ECIESx25519EncryptionKey.reset (encryptionKey);
else
m_StandardEncryptionKey.reset (encryptionKey);
}
m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_EncryptionKeyType, m_EncryptionPrivateKey);
if (isPublic) if (isPublic)
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
@ -1071,10 +1112,10 @@ namespace client
return dest; return dest;
} }
i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination () i2p::datagram::DatagramDestination * ClientDestination::CreateDatagramDestination (bool gzip)
{ {
if (m_DatagramDestination == nullptr) if (m_DatagramDestination == nullptr)
m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis ()); m_DatagramDestination = new i2p::datagram::DatagramDestination (GetSharedFromThis (), gzip);
return m_DatagramDestination; return m_DatagramDestination;
} }
@ -1092,27 +1133,29 @@ namespace client
return ret; return ret;
} }
void ClientDestination::PersistTemporaryKeys () void ClientDestination::PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey)
{ {
if (!keys) return;
std::string ident = GetIdentHash().ToBase32(); std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("destinations", (ident + ".dat")); std::string path = i2p::fs::DataDirPath("destinations",
isSingleKey ? (ident + ".dat") : (ident + "." + std::to_string (keys->keyType) + ".dat"));
std::ifstream f(path, std::ifstream::binary); std::ifstream f(path, std::ifstream::binary);
if (f) { if (f) {
f.read ((char *)m_EncryptionPublicKey, 256); f.read ((char *)keys->pub, 256);
f.read ((char *)m_EncryptionPrivateKey, 256); f.read ((char *)keys->priv, 256);
return; return;
} }
LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p"); LogPrint (eLogInfo, "Destination: Creating new temporary keys of type for address ", ident, ".b32.i2p");
memset (m_EncryptionPrivateKey, 0, 256); memset (keys->priv, 0, 256);
memset (m_EncryptionPublicKey, 0, 256); memset (keys->pub, 0, 256);
i2p::data::PrivateKeys::GenerateCryptoKeyPair (m_EncryptionKeyType, m_EncryptionPrivateKey, m_EncryptionPublicKey); keys->GenerateKeys ();
// TODO:: persist crypto key type // TODO:: persist crypto key type
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
if (f1) { if (f1) {
f1.write ((char *)m_EncryptionPublicKey, 256); f1.write ((char *)keys->pub, 256);
f1.write ((char *)m_EncryptionPrivateKey, 256); f1.write ((char *)keys->priv, 256);
return; return;
} }
LogPrint(eLogError, "Destinations: Can't save keys to ", path); LogPrint(eLogError, "Destinations: Can't save keys to ", path);
@ -1123,18 +1166,27 @@ namespace client
std::shared_ptr<i2p::data::LocalLeaseSet> leaseSet; std::shared_ptr<i2p::data::LocalLeaseSet> leaseSet;
if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET)
{ {
leaseSet = std::make_shared<i2p::data::LocalLeaseSet> (GetIdentity (), m_EncryptionPublicKey, tunnels); if (m_StandardEncryptionKey)
{
leaseSet = std::make_shared<i2p::data::LocalLeaseSet> (GetIdentity (), m_StandardEncryptionKey->pub, tunnels);
// sign // sign
Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ()); Sign (leaseSet->GetBuffer (), leaseSet->GetBufferLen () - leaseSet->GetSignatureLen (), leaseSet->GetSignature ());
} }
else
LogPrint (eLogError, "Destinations: Wrong encryption key type for LeaseSet type 1");
}
else else
{ {
// standard LS2 (type 3) first // standard LS2 (type 3) first
uint16_t keyLen = m_Decryptor ? m_Decryptor->GetPublicKeyLen () : 256; i2p::data::LocalLeaseSet2::KeySections keySections;
if (m_ECIESx25519EncryptionKey)
keySections.push_back ({m_ECIESx25519EncryptionKey->keyType, 32, m_ECIESx25519EncryptionKey->pub} );
if (m_StandardEncryptionKey)
keySections.push_back ({m_StandardEncryptionKey->keyType, (uint16_t)m_StandardEncryptionKey->decryptor->GetPublicKeyLen (), m_StandardEncryptionKey->pub} );
bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2; bool isPublishedEncrypted = GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_ENCRYPTED_LEASESET2;
auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2, auto ls2 = std::make_shared<i2p::data::LocalLeaseSet2> (i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2,
m_Keys, i2p::data::LocalLeaseSet2::KeySections { {m_EncryptionKeyType, keyLen, m_EncryptionPublicKey} }, m_Keys, keySections, tunnels, IsPublic (), isPublishedEncrypted);
tunnels, IsPublic (), isPublishedEncrypted);
if (isPublishedEncrypted) // encrypt if type 5 if (isPublishedEncrypted) // encrypt if type 5
ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys, GetAuthType (), m_AuthKeys); ls2 = std::make_shared<i2p::data::LocalEncryptedLeaseSet2> (ls2, m_Keys, GetAuthType (), m_AuthKeys);
leaseSet = ls2; leaseSet = ls2;
@ -1149,13 +1201,28 @@ 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 (m_Decryptor) if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
return m_Decryptor->Decrypt (encrypted, data, ctx, true); if (m_ECIESx25519EncryptionKey && m_ECIESx25519EncryptionKey->decryptor)
return m_ECIESx25519EncryptionKey->decryptor->Decrypt (encrypted, data, ctx, true);
if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor)
return m_StandardEncryptionKey->decryptor->Decrypt (encrypted, data, ctx, true);
else else
LogPrint (eLogError, "Destinations: decryptor is not set"); LogPrint (eLogError, "Destinations: decryptor is not set");
return false; return false;
} }
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;
}
const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const
{
if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)
return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub : nullptr;
return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub : nullptr;
}
void ClientDestination::ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params) void ClientDestination::ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params)
{ {
for (auto it: *params) for (auto it: *params)

View File

@ -1,6 +1,15 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef DESTINATION_H__ #ifndef DESTINATION_H__
#define DESTINATION_H__ #define DESTINATION_H__
#include <string.h>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <memory> #include <memory>
@ -93,7 +102,6 @@ namespace client
} }
}; };
public: public:
LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map<std::string, std::string> * params = nullptr); LeaseSetDestination (boost::asio::io_service& service, bool isPublic, const std::map<std::string, std::string> * params = nullptr);
@ -192,6 +200,17 @@ namespace client
class ClientDestination: public LeaseSetDestination class ClientDestination: public LeaseSetDestination
{ {
struct EncryptionKey
{
uint8_t pub[256], priv[256];
i2p::data::CryptoKeyType keyType;
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> decryptor;
EncryptionKey (i2p::data::CryptoKeyType t):keyType(t) { memset (pub, 0, 256); memset (priv, 0, 256); };
void GenerateKeys () { i2p::data::PrivateKeys::GenerateCryptoKeyPair (keyType, priv, pub); };
void CreateDecryptor () { decryptor = i2p::data::PrivateKeys::CreateDecryptor (keyType, priv); };
};
public: public:
ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys, ClientDestination (boost::asio::io_service& service, const i2p::data::PrivateKeys& keys,
@ -224,13 +243,13 @@ namespace client
// datagram // datagram
i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; }; i2p::datagram::DatagramDestination * GetDatagramDestination () const { return m_DatagramDestination; };
i2p::datagram::DatagramDestination * CreateDatagramDestination (); i2p::datagram::DatagramDestination * CreateDatagramDestination (bool gzip = true);
// implements LocalDestination // implements LocalDestination
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const; bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const;
std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); }; std::shared_ptr<const i2p::data::IdentityEx> GetIdentity () const { return m_Keys.GetPublic (); };
bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { return m_EncryptionKeyType == keyType; }; bool SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const;
const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { return m_EncryptionPublicKey; }; const uint8_t * GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const;
protected: protected:
@ -244,15 +263,14 @@ namespace client
std::shared_ptr<ClientDestination> GetSharedFromThis () { std::shared_ptr<ClientDestination> GetSharedFromThis () {
return std::static_pointer_cast<ClientDestination>(shared_from_this ()); return std::static_pointer_cast<ClientDestination>(shared_from_this ());
} }
void PersistTemporaryKeys (); void PersistTemporaryKeys (EncryptionKey * keys, bool isSingleKey);
void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params); void ReadAuthKey (const std::string& group, const std::map<std::string, std::string> * params);
private: private:
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; std::unique_ptr<EncryptionKey> m_StandardEncryptionKey;
i2p::data::CryptoKeyType m_EncryptionKeyType; std::unique_ptr<EncryptionKey> m_ECIESx25519EncryptionKey;
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
int m_StreamingAckDelay; int m_StreamingAckDelay;
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <string.h> #include <string.h>
#include <openssl/sha.h> #include <openssl/sha.h>
#include "Log.h" #include "Log.h"
@ -20,7 +28,7 @@ namespace garlic
// DH_INITIALIZE(rootKey, k) // DH_INITIALIZE(rootKey, k)
uint8_t keydata[64]; uint8_t keydata[64];
i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64) i2p::crypto::HKDF (rootKey, k, 32, "KDFDHRatchetStep", keydata); // keydata = HKDF(rootKey, k, "KDFDHRatchetStep", 64)
// nextRootKey = keydata[0:31] memcpy (m_NextRootKey, keydata, 32); // nextRootKey = keydata[0:31]
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_KeyData.buf); i2p::crypto::HKDF (keydata + 32, nullptr, 0, "TagAndKeyGenKeys", m_KeyData.buf);
// [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64) // [sessTag_ck, symmKey_ck] = HKDF(keydata[32:63], ZEROLEN, "TagAndKeyGenKeys", 64)
memcpy (m_SymmKeyCK, m_KeyData.buf + 32, 32); memcpy (m_SymmKeyCK, m_KeyData.buf + 32, 32);
@ -38,36 +46,55 @@ namespace garlic
{ {
i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64) i2p::crypto::HKDF (m_KeyData.GetSessTagCK (), m_SessTagConstant, 32, "SessionTagKeyGen", m_KeyData.buf); // [sessTag_ck, tag] = HKDF(sessTag_chainkey, SESSTAG_CONSTANT, "SessionTagKeyGen", 64)
m_NextIndex++; m_NextIndex++;
if (m_NextIndex >= 65535) m_NextIndex = 0; // TODO: dirty hack, should create new tagset if (m_NextIndex >= 65535)
{
LogPrint (eLogError, "Garlic: Tagset ", GetTagSetID (), " is empty");
return 0;
}
return m_KeyData.GetTag (); return m_KeyData.GetTag ();
} }
void RatchetTagSet::GetSymmKey (int index, uint8_t * key) void RatchetTagSet::GetSymmKey (int index, uint8_t * key)
{ {
if (m_NextSymmKeyIndex > 0 && index >= m_NextSymmKeyIndex) if (index >= m_NextSymmKeyIndex)
{ {
auto num = index + 1 - m_NextSymmKeyIndex; auto num = index + 1 - m_NextSymmKeyIndex;
if (!m_NextSymmKeyIndex)
{
i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); // keydata_0 = HKDF(symmKey_ck, SYMMKEY_CONSTANT, "SymmetricRatchet", 64)
m_NextSymmKeyIndex = 1;
num--;
}
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{
i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK); i2p::crypto::HKDF (m_CurrentSymmKeyCK, nullptr, 0, "SymmetricRatchet", m_CurrentSymmKeyCK);
if (i < num - 1)
m_ItermediateSymmKeys.emplace (m_NextSymmKeyIndex + i, m_CurrentSymmKeyCK + 32);
}
m_NextSymmKeyIndex += num; m_NextSymmKeyIndex += num;
memcpy (key, m_CurrentSymmKeyCK + 32, 32); memcpy (key, m_CurrentSymmKeyCK + 32, 32);
} }
else else
CalculateSymmKeyCK (index, key);
}
void RatchetTagSet::CalculateSymmKeyCK (int index, uint8_t * key)
{ {
// TODO: store intermediate keys auto it = m_ItermediateSymmKeys.find (index);
uint8_t currentSymmKeyCK[64]; if (it != m_ItermediateSymmKeys.end ())
i2p::crypto::HKDF (m_SymmKeyCK, nullptr, 0, "SymmetricRatchet", currentSymmKeyCK); // keydata_0 = HKDF(symmKey_ck, SYMMKEY_CONSTANT, "SymmetricRatchet", 64) {
for (int i = 0; i < index; i++) memcpy (key, it->second, 32);
i2p::crypto::HKDF (currentSymmKeyCK, nullptr, 0, "SymmetricRatchet", currentSymmKeyCK); // keydata_n = HKDF(symmKey_chainKey_(n-1), SYMMKEY_CONSTANT, "SymmetricRatchet", 64) m_ItermediateSymmKeys.erase (it);
memcpy (key, currentSymmKeyCK + 32, 32); }
else
LogPrint (eLogError, "Garlic: Missing symmetric key for index ", index);
}
} }
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner): void RatchetTagSet::Expire ()
GarlicRoutingSession (owner, true) {
if (!m_ExpirationTimestamp)
m_ExpirationTimestamp = i2p::util::GetSecondsSinceEpoch () + ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT;
}
ECIESX25519AEADRatchetSession::ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet):
GarlicRoutingSession (owner, attachLeaseSet)
{ {
ResetKeys (); ResetKeys ();
} }
@ -78,11 +105,18 @@ namespace garlic
void ECIESX25519AEADRatchetSession::ResetKeys () void ECIESX25519AEADRatchetSession::ResetKeys ()
{ {
// TODO : use precalculated hashes static const uint8_t protocolNameHash[32] =
static const char protocolName[41] = "Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"; // 40 bytes {
SHA256 ((const uint8_t *)protocolName, 40, m_H); 0x4c, 0xaf, 0x11, 0xef, 0x2c, 0x8e, 0x36, 0x56, 0x4c, 0x53, 0xe8, 0x88, 0x85, 0x06, 0x4d, 0xba,
memcpy (m_CK, m_H, 32); 0xac, 0xbe, 0x00, 0x54, 0xad, 0x17, 0x8f, 0x80, 0x79, 0xa6, 0x46, 0x82, 0x7e, 0x6e, 0xe4, 0x0c
SHA256 (m_H, 32, m_H); }; // SHA256("Noise_IKelg2+hs2_25519_ChaChaPoly_SHA256"), 40 bytes
static const uint8_t hh[32] =
{
0x9c, 0xcf, 0x85, 0x2c, 0xc9, 0x3b, 0xb9, 0x50, 0x44, 0x41, 0xe9, 0x50, 0xe0, 0x1d, 0x52, 0x32,
0x2e, 0x0d, 0x47, 0xad, 0xd1, 0xe9, 0xa5, 0x55, 0xf7, 0x55, 0xb5, 0x69, 0xae, 0x18, 0x3b, 0x5c
}; // SHA256 (protocolNameHash)
memcpy (m_CK, protocolNameHash, 32);
memcpy (m_H, hh, 32);
} }
void ECIESX25519AEADRatchetSession::MixHash (const uint8_t * buf, size_t len) void ECIESX25519AEADRatchetSession::MixHash (const uint8_t * buf, size_t len)
@ -111,15 +145,15 @@ namespace garlic
return false; return false;
} }
uint64_t ECIESX25519AEADRatchetSession::CreateNewSessionTag () const std::shared_ptr<RatchetTagSet> ECIESX25519AEADRatchetSession::CreateNewSessionTagset ()
{ {
uint8_t tagsetKey[32]; uint8_t tagsetKey[32];
i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32) i2p::crypto::HKDF (m_CK, nullptr, 0, "SessionReplyTags", tagsetKey, 32); // tagsetKey = HKDF(chainKey, ZEROLEN, "SessionReplyTags", 32)
// Session Tag Ratchet // Session Tag Ratchet
RatchetTagSet tagsetNsr; auto tagsetNsr = std::make_shared<RatchetTagSet>(shared_from_this ());
tagsetNsr.DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey) tagsetNsr->DHInitialize (m_CK, tagsetKey); // tagset_nsr = DH_INITIALIZE(chainKey, tagsetKey)
tagsetNsr.NextSessionTagRatchet (); tagsetNsr->NextSessionTagRatchet ();
return tagsetNsr.GetNextSessionTag (); return tagsetNsr;
} }
bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len) bool ECIESX25519AEADRatchetSession::HandleNewIncomingSession (const uint8_t * buf, size_t len)
@ -127,7 +161,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_RARCHET), 32); // h = SHA256(h || bpk) MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET), 32); // h = SHA256(h || bpk)
if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk))
{ {
@ -138,7 +172,7 @@ 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_RARCHET); // x25519(bsk, aepk) GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, aepk)
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
// decrypt flags/static // decrypt flags/static
@ -152,19 +186,20 @@ namespace garlic
MixHash (buf, 48); // h = SHA256(h || ciphertext) MixHash (buf, 48); // h = SHA256(h || ciphertext)
buf += 48; len -= 48; // 32 data + 16 poly buf += 48; len -= 48; // 32 data + 16 poly
// decrypt payload
std::vector<uint8_t> payload (len - 16);
// KDF2 for payload // KDF2 for payload
bool isStatic = !i2p::data::Tag<32> (fs).IsZero (); bool isStatic = !i2p::data::Tag<32> (fs).IsZero ();
if (isStatic) if (isStatic)
{ {
// 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_RARCHET); // x25519(bsk, apk) GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, apk)
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
} }
else // all zeros flags else // all zeros flags
CreateNonce (1, nonce); CreateNonce (1, nonce);
// decrypt payload
std::vector<uint8_t> payload (len - 16); // we must save original ciphertext
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, m_CK + 32, nonce, payload.data (), len - 16, false)) // decrypt
{ {
LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed");
@ -174,12 +209,12 @@ namespace garlic
m_State = eSessionStateNewSessionReceived; m_State = eSessionStateNewSessionReceived;
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
HandlePayload (payload.data (), len - 16); HandlePayload (payload.data (), len - 16, nullptr, 0);
return true; return true;
} }
void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, int index) void ECIESX25519AEADRatchetSession::HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset, int index)
{ {
size_t offset = 0; size_t offset = 0;
while (offset < len) while (offset < len)
@ -197,8 +232,37 @@ namespace garlic
switch (blk) switch (blk)
{ {
case eECIESx25519BlkGalicClove: case eECIESx25519BlkGalicClove:
if (GetOwner ())
GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size); GetOwner ()->HandleECIESx25519GarlicClove (buf + offset, size);
break; break;
case eECIESx25519BlkNextKey:
LogPrint (eLogDebug, "Garlic: next key");
HandleNextKey (buf + offset, size, receiveTagset);
break;
case eECIESx25519BlkAck:
{
LogPrint (eLogDebug, "Garlic: ack");
int numAcks = size >> 2; // /4
auto offset1 = offset;
for (auto i = 0; i < numAcks; i++)
{
offset1 += 2; // tagsetid
MessageConfirmed (bufbe16toh (buf + offset1)); offset1 += 2; // N
}
break;
}
case eECIESx25519BlkAckRequest:
{
LogPrint (eLogDebug, "Garlic: ack request");
m_AckRequests.push_back ({receiveTagset->GetTagSetID (), index});
break;
}
case eECIESx25519BlkTermination:
LogPrint (eLogDebug, "Garlic: termination");
if (GetOwner ())
GetOwner ()->RemoveECIESx25519Session (m_RemoteStaticKey);
if (receiveTagset) receiveTagset->Expire ();
break;
case eECIESx25519BlkDateTime: case eECIESx25519BlkDateTime:
LogPrint (eLogDebug, "Garlic: datetime"); LogPrint (eLogDebug, "Garlic: datetime");
break; break;
@ -208,12 +272,6 @@ namespace garlic
case eECIESx25519BlkPadding: case eECIESx25519BlkPadding:
LogPrint (eLogDebug, "Garlic: padding"); LogPrint (eLogDebug, "Garlic: padding");
break; break;
case eECIESx25519BlkAckRequest:
{
LogPrint (eLogDebug, "Garlic: ack request");
m_AckRequests.push_back ({0, index}); // TODO: use actual tagsetid
break;
}
default: default:
LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk); LogPrint (eLogWarning, "Garlic: Unknown block type ", (int)blk);
} }
@ -221,6 +279,94 @@ namespace garlic
} }
} }
void ECIESX25519AEADRatchetSession::HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr<RatchetTagSet>& receiveTagset)
{
uint8_t flag = buf[0]; buf++; // flag
if (flag & ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG)
{
if (!m_SendForwardKey || !m_NextSendRatchet) return;
uint16_t keyID = bufbe16toh (buf); buf += 2; // keyID
if (((!m_NextSendRatchet->newKey || !m_NextSendRatchet->keyID) && keyID == m_NextSendRatchet->keyID) ||
(m_NextSendRatchet->newKey && keyID == m_NextSendRatchet->keyID -1))
{
if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG)
memcpy (m_NextSendRatchet->remote, buf, 32);
uint8_t sharedSecret[32], tagsetKey[32];
m_NextSendRatchet->key.Agree (m_NextSendRatchet->remote, sharedSecret);
i2p::crypto::HKDF (sharedSecret, nullptr, 0, "XDHRatchetTagSet", tagsetKey, 32); // tagsetKey = HKDF(sharedSecret, ZEROLEN, "XDHRatchetTagSet", 32)
auto newTagset = std::make_shared<RatchetTagSet> (shared_from_this ());
newTagset->SetTagSetID (1 + m_NextSendRatchet->keyID + keyID);
newTagset->DHInitialize (m_SendTagset->GetNextRootKey (), tagsetKey);
newTagset->NextSessionTagRatchet ();
m_SendTagset = newTagset;
m_SendForwardKey = false;
LogPrint (eLogDebug, "Garlic: next send tagset ", newTagset->GetTagSetID (), " created");
}
else
LogPrint (eLogDebug, "Garlic: Unexpected next key ", keyID);
}
else
{
uint16_t keyID = bufbe16toh (buf); buf += 2; // keyID
bool newKey = flag & ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG;
m_SendReverseKey = true;
if (!m_NextReceiveRatchet)
m_NextReceiveRatchet.reset (new DHRatchet ());
else
{
if (keyID == m_NextReceiveRatchet->keyID && newKey == m_NextReceiveRatchet->newKey)
{
LogPrint (eLogDebug, "Garlic: Duplicate ", newKey ? "new" : "old", " key ", keyID, " received");
return;
}
m_NextReceiveRatchet->keyID = keyID;
}
int tagsetID = 2*keyID;
if (newKey)
{
m_NextReceiveRatchet->key.GenerateKeys ();
m_NextReceiveRatchet->newKey = true;
tagsetID++;
}
else
m_NextReceiveRatchet->newKey = false;
if (flag & ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG)
memcpy (m_NextReceiveRatchet->remote, buf, 32);
uint8_t sharedSecret[32], tagsetKey[32];
m_NextReceiveRatchet->key.Agree (m_NextReceiveRatchet->remote, sharedSecret);
i2p::crypto::HKDF (sharedSecret, nullptr, 0, "XDHRatchetTagSet", tagsetKey, 32); // tagsetKey = HKDF(sharedSecret, ZEROLEN, "XDHRatchetTagSet", 32)
auto newTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
newTagset->SetTagSetID (tagsetID);
newTagset->DHInitialize (receiveTagset->GetNextRootKey (), tagsetKey);
newTagset->NextSessionTagRatchet ();
GenerateMoreReceiveTags (newTagset, ECIESX25519_MAX_NUM_GENERATED_TAGS);
receiveTagset->Expire ();
LogPrint (eLogDebug, "Garlic: next receive tagset ", tagsetID, " created");
}
}
void ECIESX25519AEADRatchetSession::NewNextSendRatchet ()
{
if (m_NextSendRatchet)
{
if (!m_NextSendRatchet->newKey || !m_NextSendRatchet->keyID)
{
m_NextSendRatchet->keyID++;
m_NextSendRatchet->newKey = true;
}
else
m_NextSendRatchet->newKey = false;
}
else
m_NextSendRatchet.reset (new DHRatchet ());
if (m_NextSendRatchet->newKey)
m_NextSendRatchet->key.GenerateKeys ();
m_SendForwardKey = true;
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)
{ {
ResetKeys (); ResetKeys ();
@ -242,7 +388,7 @@ namespace garlic
// encrypt static key section // encrypt 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_RARCHET), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt 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
{ {
LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed "); LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed ");
return false; return false;
@ -250,7 +396,7 @@ namespace garlic
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_RARCHET); // x25519 (ask, bpk) GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bpk)
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
// 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
@ -262,7 +408,7 @@ namespace garlic
m_State = eSessionStateNewSessionSent; m_State = eSessionStateNewSessionSent;
if (GetOwner ()) if (GetOwner ())
GetOwner ()->AddECIESx25519SessionTag (0, CreateNewSessionTag (), shared_from_this ()); GenerateMoreReceiveTags (CreateNewSessionTagset (), ECIESX25519_NSR_NUM_GENERATED_TAGS);
return true; return true;
} }
@ -270,7 +416,8 @@ namespace garlic
bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
// we are Bob // we are Bob
uint64_t tag = CreateNewSessionTag (); m_NSRTagset = CreateNewSessionTagset ();
uint64_t tag = m_NSRTagset->GetNextSessionTag ();
size_t offset = 0; size_t offset = 0;
memcpy (out + offset, &tag, 8); memcpy (out + offset, &tag, 8);
@ -280,6 +427,8 @@ namespace garlic
LogPrint (eLogError, "Garlic: Can't encode elligator"); LogPrint (eLogError, "Garlic: Can't encode elligator");
return false; return false;
} }
memcpy (m_NSREncodedKey, out + offset, 56); // for possible next NSR
memcpy (m_NSRH, m_H, 32);
offset += 32; offset += 32;
// KDF for Reply Key Section // KDF for Reply Key Section
MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag) MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag)
@ -291,24 +440,25 @@ namespace garlic
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (0, nonce); CreateNonce (0, nonce);
// calulate hash for zero length // calculate hash for zero length
if (!i2p::crypto::AEADChaCha20Poly1305 (sharedSecret /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad) if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + offset, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad)
{ {
LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed"); LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed");
return false; return false;
} }
MixHash (out + offset, 16); // h = SHA256(h || ciphertext) MixHash (out + offset, 16); // h = SHA256(h || ciphertext)
offset += 16; offset += 16;
memcpy (m_NSRHeader, out, 56); // for possible next NSR
// KDF for payload // KDF for payload
uint8_t keydata[64]; uint8_t keydata[64];
i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64)
// k_ab = keydata[0:31], k_ba = keydata[32:63] // k_ab = keydata[0:31], k_ba = keydata[32:63]
m_ReceiveTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) auto receiveTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
m_ReceiveTagset.NextSessionTagRatchet (); receiveTagset->DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab)
m_SendTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) receiveTagset->NextSessionTagRatchet ();
m_SendTagset.NextSessionTagRatchet (); m_SendTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ()); m_SendTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
m_SendTagset->NextSessionTagRatchet ();
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_MIN_NUM_GENERATED_TAGS);
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", m_NSRKey, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", m_NSRKey, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
// encrypt payload // encrypt payload
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset, len + 16, true)) // encrypt if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + offset, len + 16, true)) // encrypt
@ -317,6 +467,7 @@ namespace garlic
return false; return false;
} }
m_State = eSessionStateNewSessionReplySent; m_State = eSessionStateNewSessionReplySent;
m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch ();
return true; return true;
} }
@ -324,9 +475,21 @@ namespace garlic
bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
// we are Bob and sent NSR already // we are Bob and sent NSR already
memcpy (out, m_NSRHeader, 56); uint64_t tag = m_NSRTagset->GetNextSessionTag (); // next tag
memcpy (out, &tag, 8);
memcpy (out + 8, m_NSREncodedKey, 32);
// recalculate h with new tag
memcpy (m_H, m_NSRH, 32);
MixHash ((const uint8_t *)&tag, 8); // h = SHA256(h || tag)
MixHash (m_EphemeralKeys.GetPublicKey (), 32); // h = SHA256(h || bepk)
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (0, nonce); CreateNonce (0, nonce);
if (!i2p::crypto::AEADChaCha20Poly1305 (nonce /* can be anything */, 0, m_H, 32, m_CK + 32, nonce, out + 40, 16, true)) // encrypt, ciphertext = ENCRYPT(k, n, ZEROLEN, ad)
{
LogPrint (eLogWarning, "Garlic: Reply key section AEAD encryption failed");
return false;
}
MixHash (out + 40, 16); // h = SHA256(h || ciphertext)
// encrypt payload // encrypt payload
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + 56, len + 16, true)) // encrypt if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_NSRKey, nonce, out + 56, len + 16, true)) // encrypt
{ {
@ -336,7 +499,7 @@ namespace garlic
return true; return true;
} }
bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len) bool ECIESX25519AEADRatchetSession::HandleNewOutgoingSessionReply (uint8_t * buf, size_t len)
{ {
// we are Alice // we are Alice
LogPrint (eLogDebug, "Garlic: reply received"); LogPrint (eLogDebug, "Garlic: reply received");
@ -350,17 +513,22 @@ namespace garlic
} }
buf += 32; len -= 32; buf += 32; len -= 32;
// KDF for Reply Key Section // KDF for Reply Key Section
uint8_t h[32]; memcpy (h, m_H, 32); // save m_H
MixHash (tag, 8); // h = SHA256(h || tag) MixHash (tag, 8); // h = SHA256(h || tag)
MixHash (bepk, 32); // h = SHA256(h || bepk) MixHash (bepk, 32); // h = SHA256(h || bepk)
uint8_t sharedSecret[32]; uint8_t sharedSecret[32];
if (m_State == eSessionStateNewSessionSent)
{
// 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) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32)
GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET); // x25519 (ask, bepk) GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk)
i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64)
}
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (0, nonce); CreateNonce (0, nonce);
// calulate hash for zero length // calculate hash for zero length
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anyting */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only if (!i2p::crypto::AEADChaCha20Poly1305 (buf, 0, m_H, 32, m_CK + 32, nonce, sharedSecret/* can be anything */, 0, false)) // decrypt, DECRYPT(k, n, ZEROLEN, ad) verification only
{ {
LogPrint (eLogWarning, "Garlic: Reply key section AEAD decryption failed"); LogPrint (eLogWarning, "Garlic: Reply key section AEAD decryption failed");
return false; return false;
@ -370,24 +538,37 @@ namespace garlic
// KDF for payload // KDF for payload
uint8_t keydata[64]; uint8_t keydata[64];
i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64) i2p::crypto::HKDF (m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64)
if (m_State == eSessionStateNewSessionSent)
{
// k_ab = keydata[0:31], k_ba = keydata[32:63] // k_ab = keydata[0:31], k_ba = keydata[32:63]
m_SendTagset.DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab) m_SendTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
m_SendTagset.NextSessionTagRatchet (); m_SendTagset->DHInitialize (m_CK, keydata); // tagset_ab = DH_INITIALIZE(chainKey, k_ab)
m_ReceiveTagset.DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba) m_SendTagset->NextSessionTagRatchet ();
m_ReceiveTagset.NextSessionTagRatchet (); auto receiveTagset = std::make_shared<RatchetTagSet>(shared_from_this ());
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ()); receiveTagset->DHInitialize (m_CK, keydata + 32); // tagset_ba = DH_INITIALIZE(chainKey, k_ba)
receiveTagset->NextSessionTagRatchet ();
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_MIN_NUM_GENERATED_TAGS);
}
i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32) i2p::crypto::HKDF (keydata + 32, nullptr, 0, "AttachPayloadKDF", keydata, 32); // k = HKDF(k_ba, ZEROLEN, "AttachPayloadKDF", 32)
// decrypt payload // decrypt payload
std::vector<uint8_t> payload (len - 16); if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, keydata, nonce, buf, len - 16, false)) // decrypt
if (!i2p::crypto::AEADChaCha20Poly1305 (buf, len - 16, m_H, 32, keydata, nonce, payload.data (), len - 16, false)) // decrypt
{ {
LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed");
return false; return false;
} }
if (m_State == eSessionStateNewSessionSent)
{
m_State = eSessionStateEstablished; m_State = eSessionStateEstablished;
m_SessionCreatedTimestamp = i2p::util::GetSecondsSinceEpoch ();
GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ());
HandlePayload (payload.data (), len - 16); }
memcpy (m_H, h, 32); // restore m_H
HandlePayload (buf, len - 16, nullptr, 0);
// we have received reply to NS with LeaseSet in it
SetLeaseSetUpdateStatus (eLeaseSetUpToDate);
SetLeaseSetUpdateMsgID (0);
return true; return true;
} }
@ -395,56 +576,70 @@ namespace garlic
bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) bool ECIESX25519AEADRatchetSession::NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen)
{ {
uint8_t nonce[12]; uint8_t nonce[12];
auto index = m_SendTagset.GetNextIndex (); auto index = m_SendTagset->GetNextIndex ();
CreateNonce (index, nonce); // tag's index CreateNonce (index, nonce); // tag's index
uint64_t tag = m_SendTagset.GetNextSessionTag (); uint64_t tag = m_SendTagset->GetNextSessionTag ();
memcpy (out, &tag, 8); memcpy (out, &tag, 8);
// ad = The session tag, 8 bytes // ad = The session tag, 8 bytes
// ciphertext = ENCRYPT(k, n, payload, ad) // ciphertext = ENCRYPT(k, n, payload, ad)
uint8_t key[32]; uint8_t key[32];
m_SendTagset.GetSymmKey (index, key); m_SendTagset->GetSymmKey (index, key);
if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, key, nonce, out + 8, outLen - 8, true)) // encrypt if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, out, 8, key, nonce, out + 8, outLen - 8, true)) // encrypt
{ {
LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed");
return false; return false;
} }
if (index >= ECIESX25519_TAGSET_MAX_NUM_TAGS && !m_SendForwardKey)
NewNextSendRatchet ();
return true; return true;
} }
bool ECIESX25519AEADRatchetSession::HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index) bool ECIESX25519AEADRatchetSession::HandleExistingSessionMessage (uint8_t * buf, size_t len,
std::shared_ptr<RatchetTagSet> receiveTagset, int index)
{ {
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (index, nonce); // tag's index CreateNonce (index, nonce); // tag's index
len -= 8; // tag len -= 8; // tag
std::vector<uint8_t> payload (len - 16); uint8_t * payload = buf + 8;
uint8_t key[32]; uint8_t key[32];
m_ReceiveTagset.GetSymmKey (index, key); receiveTagset->GetSymmKey (index, key);
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 8, len - 16, buf, 8, key, nonce, payload.data (), len - 16, false)) // decrypt if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 16, buf, 8, key, nonce, payload, len - 16, false)) // decrypt
{ {
LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed"); LogPrint (eLogWarning, "Garlic: Payload section AEAD decryption failed");
return false; return false;
} }
HandlePayload (payload.data (), len - 16, index); HandlePayload (payload, len - 16, receiveTagset, index);
if (m_ReceiveTagset.GetNextIndex () - index <= GetOwner ()->GetNumTags ()*2/3) int moreTags = ECIESX25519_MIN_NUM_GENERATED_TAGS + (index >> 2); // N/4
GenerateMoreReceiveTags (GetOwner ()->GetNumTags ()); if (moreTags > ECIESX25519_MAX_NUM_GENERATED_TAGS) moreTags = ECIESX25519_MAX_NUM_GENERATED_TAGS;
moreTags -= (receiveTagset->GetNextIndex () - index);
if (moreTags > 0 && GetOwner ())
GenerateMoreReceiveTags (receiveTagset, moreTags);
return true; return true;
} }
bool ECIESX25519AEADRatchetSession::HandleNextMessage (const uint8_t * buf, size_t len, int index) bool ECIESX25519AEADRatchetSession::HandleNextMessage (uint8_t * buf, size_t len,
std::shared_ptr<RatchetTagSet> receiveTagset, int index)
{ {
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
switch (m_State) switch (m_State)
{ {
case eSessionStateNewSessionReplySent: case eSessionStateNewSessionReplySent:
m_State = eSessionStateEstablished; m_State = eSessionStateEstablished;
m_NSRTagset = nullptr;
#if (__cplusplus >= 201703L) // C++ 17 or higher #if (__cplusplus >= 201703L) // C++ 17 or higher
[[fallthrough]]; [[fallthrough]];
#endif #endif
case eSessionStateEstablished: case eSessionStateEstablished:
return HandleExistingSessionMessage (buf, len, index); if (HandleExistingSessionMessage (buf, len, receiveTagset, index)) return true;
// check NSR just in case
LogPrint (eLogDebug, "Garlic: check for out of order NSR with index ", index);
if (receiveTagset->GetNextIndex () - index < ECIESX25519_NSR_NUM_GENERATED_TAGS/2)
GenerateMoreReceiveTags (receiveTagset, ECIESX25519_NSR_NUM_GENERATED_TAGS);
return HandleNewOutgoingSessionReply (buf, len);
case eSessionStateNew: case eSessionStateNew:
return HandleNewIncomingSession (buf, len); return HandleNewIncomingSession (buf, len);
case eSessionStateNewSessionSent: case eSessionStateNewSessionSent:
receiveTagset->Expire (); // NSR tagset
return HandleNewOutgoingSessionReply (buf, len); return HandleNewOutgoingSessionReply (buf, len);
default: default:
return false; return false;
@ -454,11 +649,12 @@ namespace garlic
std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) std::shared_ptr<I2NPMessage> ECIESX25519AEADRatchetSession::WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg)
{ {
auto m = NewI2NPMessage (); auto payload = CreatePayload (msg, m_State != eSessionStateEstablished);
size_t len = payload.size ();
if (!len) return nullptr;
auto m = NewI2NPMessage (len + 100); // 96 + 4
m->Align (12); // in order to get buf aligned to 16 (12 + 4) m->Align (12); // in order to get buf aligned to 16 (12 + 4)
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
auto payload = CreatePayload (msg);
size_t len = payload.size ();
switch (m_State) switch (m_State)
{ {
@ -492,43 +688,79 @@ namespace garlic
return m; return m;
} }
std::vector<uint8_t> ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr<const I2NPMessage> msg) 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 ();
size_t payloadLen = 7; // datatime size_t payloadLen = 0;
if (first) payloadLen += 7;// datatime
if (msg && m_Destination) if (msg && m_Destination)
payloadLen += msg->GetPayloadLength () + 13 + 32; payloadLen += msg->GetPayloadLength () + 13 + 32;
auto leaseSet = (GetLeaseSetUpdateStatus () == eLeaseSetUpdated) ? CreateDatabaseStoreMsg (GetOwner ()->GetLeaseSet ()) : nullptr; auto leaseSet = (GetLeaseSetUpdateStatus () == eLeaseSetUpdated ||
std::shared_ptr<I2NPMessage> deliveryStatus; (GetLeaseSetUpdateStatus () == eLeaseSetSubmitted &&
ts > GetLeaseSetSubmissionTime () + LEASET_CONFIRMATION_TIMEOUT)) ?
GetOwner ()->GetLeaseSet () : nullptr;
if (leaseSet) if (leaseSet)
{ {
payloadLen += leaseSet->GetPayloadLength () + 13; payloadLen += leaseSet->GetBufferLen () + DATABASE_STORE_HEADER_SIZE + 13;
deliveryStatus = CreateEncryptedDeliveryStatusMsg (leaseSet->GetMsgID ()); if (!first)
payloadLen += deliveryStatus->GetPayloadLength () + 49; {
if (GetLeaseSetUpdateMsgID ()) GetOwner ()->RemoveDeliveryStatusSession (GetLeaseSetUpdateMsgID ()); // remove previous // ack request
SetLeaseSetUpdateStatus (eLeaseSetSubmitted); SetLeaseSetUpdateStatus (eLeaseSetSubmitted);
SetLeaseSetUpdateMsgID (leaseSet->GetMsgID ()); SetLeaseSetUpdateMsgID (m_SendTagset->GetNextIndex ());
SetLeaseSetSubmissionTime (ts); SetLeaseSetSubmissionTime (ts);
GetOwner ()->DeliveryStatusSent (shared_from_this (), leaseSet->GetMsgID ()); payloadLen += 4;
}
} }
if (m_AckRequests.size () > 0) if (m_AckRequests.size () > 0)
payloadLen += m_AckRequests.size ()*4 + 3; payloadLen += m_AckRequests.size ()*4 + 3;
uint8_t paddingSize; if (m_SendReverseKey)
{
payloadLen += 6;
if (m_NextReceiveRatchet->newKey) payloadLen += 32;
}
if (m_SendForwardKey)
{
payloadLen += 6;
if (m_NextSendRatchet->newKey) payloadLen += 32;
}
uint8_t paddingSize = 0;
if (payloadLen)
{
int delta = (int)ECIESX25519_OPTIMAL_PAYLOAD_SIZE - (int)payloadLen;
if (delta < 0 || delta > 3) // don't create padding if we are close to optimal size
{
RAND_bytes (&paddingSize, 1); RAND_bytes (&paddingSize, 1);
paddingSize &= 0x0F; paddingSize++; // 1 - 16 paddingSize &= 0x0F; // 0 - 15
if (delta > 3)
{
delta -= 3;
if (paddingSize >= delta) paddingSize %= delta;
}
paddingSize++;
payloadLen += paddingSize + 3; payloadLen += paddingSize + 3;
}
}
std::vector<uint8_t> v(payloadLen); std::vector<uint8_t> v(payloadLen);
size_t offset = 0; size_t offset = 0;
// DateTime // DateTime
if (first)
{
v[offset] = eECIESx25519BlkDateTime; offset++; v[offset] = eECIESx25519BlkDateTime; offset++;
htobe16buf (v.data () + offset, 4); offset += 2; htobe16buf (v.data () + offset, 4); offset += 2;
htobe32buf (v.data () + offset, ts/1000); offset += 4; // in seconds htobe32buf (v.data () + offset, ts/1000); offset += 4; // in seconds
}
// LeaseSet // LeaseSet
if (leaseSet) if (leaseSet)
offset += CreateGarlicClove (leaseSet, v.data () + offset, payloadLen - offset); {
// DeliveryStatus offset += CreateLeaseSetClove (leaseSet, ts, v.data () + offset, payloadLen - offset);
if (deliveryStatus) if (!first)
offset += CreateDeliveryStatusClove (deliveryStatus, v.data () + offset, payloadLen - offset); {
// ack request
v[offset] = eECIESx25519BlkAckRequest; offset++;
htobe16buf (v.data () + offset, 1); offset += 2;
v[offset] = 0; offset++; // flags
}
}
// msg // msg
if (msg && m_Destination) if (msg && m_Destination)
offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset, true); offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset, true);
@ -536,7 +768,7 @@ namespace garlic
if (m_AckRequests.size () > 0) if (m_AckRequests.size () > 0)
{ {
v[offset] = eECIESx25519BlkAck; offset++; v[offset] = eECIESx25519BlkAck; offset++;
htobe16buf (v.data () + offset, m_AckRequests.size ()*4); offset += 2; htobe16buf (v.data () + offset, m_AckRequests.size () * 4); offset += 2;
for (auto& it: m_AckRequests) for (auto& it: m_AckRequests)
{ {
htobe16buf (v.data () + offset, it.first); offset += 2; htobe16buf (v.data () + offset, it.first); offset += 2;
@ -544,10 +776,48 @@ namespace garlic
} }
m_AckRequests.clear (); m_AckRequests.clear ();
} }
// next keys
if (m_SendReverseKey)
{
v[offset] = eECIESx25519BlkNextKey; offset++;
htobe16buf (v.data () + offset, m_NextReceiveRatchet->newKey ? 35 : 3); offset += 2;
v[offset] = ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG;
int keyID = m_NextReceiveRatchet->keyID - 1;
if (m_NextReceiveRatchet->newKey)
{
v[offset] |= ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG;
keyID++;
}
offset++; // flag
htobe16buf (v.data () + offset, keyID); offset += 2; // keyid
if (m_NextReceiveRatchet->newKey)
{
memcpy (v.data () + offset, m_NextReceiveRatchet->key.GetPublicKey (), 32);
offset += 32; // public key
}
m_SendReverseKey = false;
}
if (m_SendForwardKey)
{
v[offset] = eECIESx25519BlkNextKey; offset++;
htobe16buf (v.data () + offset, m_NextSendRatchet->newKey ? 35 : 3); offset += 2;
v[offset] = m_NextSendRatchet->newKey ? ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG : ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG;
if (!m_NextSendRatchet->keyID) v[offset] |= ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG; // for first key only
offset++; // flag
htobe16buf (v.data () + offset, m_NextSendRatchet->keyID); offset += 2; // keyid
if (m_NextSendRatchet->newKey)
{
memcpy (v.data () + offset, m_NextSendRatchet->key.GetPublicKey (), 32);
offset += 32; // public key
}
}
// padding // padding
if (paddingSize)
{
v[offset] = eECIESx25519BlkPadding; offset++; v[offset] = eECIESx25519BlkPadding; offset++;
htobe16buf (v.data () + offset, paddingSize); offset += 2; htobe16buf (v.data () + offset, paddingSize); offset += 2;
memset (v.data () + offset, 0, paddingSize); offset += paddingSize; memset (v.data () + offset, 0, paddingSize); offset += paddingSize;
}
return v; return v;
} }
@ -570,52 +840,41 @@ namespace garlic
buf++; // flag and delivery instructions buf++; // flag and delivery instructions
*buf = msg->GetTypeID (); // I2NP msg type *buf = msg->GetTypeID (); // I2NP msg type
htobe32buf (buf + 1, msg->GetMsgID ()); // msgID htobe32buf (buf + 1, msg->GetMsgID ()); // msgID
htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds htobe32buf (buf + 5, msg->GetExpiration () / 1000); // expiration in seconds
memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ()); memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ());
return cloveSize + 3; return cloveSize + 3;
} }
size_t ECIESX25519AEADRatchetSession::CreateDeliveryStatusClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len) size_t ECIESX25519AEADRatchetSession::CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len)
{ {
uint16_t cloveSize = msg->GetPayloadLength () + 9 + 37 /* delivery instruction */; if (!ls || ls->GetStoreType () != i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2)
{
LogPrint (eLogError, "Garlic: Incorrect LeasetSet type to send");
return 0;
}
uint16_t cloveSize = 1 + 9 + DATABASE_STORE_HEADER_SIZE + ls->GetBufferLen (); // to local
if ((int)len < cloveSize + 3) return 0; if ((int)len < cloveSize + 3) return 0;
buf[0] = eECIESx25519BlkGalicClove; // clove type buf[0] = eECIESx25519BlkGalicClove; // clove type
htobe16buf (buf + 1, cloveSize); // size htobe16buf (buf + 1, cloveSize); // size
buf += 3; buf += 3;
if (GetOwner ()) *buf = 0; buf++; // flag and delivery instructions
{ *buf = eI2NPDatabaseStore; buf++; // I2NP msg type
auto inboundTunnel = GetOwner ()->GetTunnelPool ()->GetNextInboundTunnel (); RAND_bytes (buf, 4); buf += 4; // msgID
if (inboundTunnel) htobe32buf (buf, (ts + I2NP_MESSAGE_EXPIRATION_TIMEOUT)/1000); buf += 4; // expiration
{ // payload
// delivery instructions memcpy (buf + DATABASE_STORE_KEY_OFFSET, ls->GetStoreHash (), 32);
*buf = eGarlicDeliveryTypeTunnel << 5; buf++; // delivery instructions flag tunnel buf[DATABASE_STORE_TYPE_OFFSET] = i2p::data::NETDB_STORE_TYPE_STANDARD_LEASESET2;
// hash and tunnelID sequence is reversed for Garlic memset (buf + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0, 4); // replyToken = 0
memcpy (buf, inboundTunnel->GetNextIdentHash (), 32); buf += 32;// To Hash buf += DATABASE_STORE_HEADER_SIZE;
htobe32buf (buf, inboundTunnel->GetNextTunnelID ()); buf += 4;// tunnelID memcpy (buf, ls->GetBuffer (), ls->GetBufferLen ());
}
else
{
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
return 0;
}
*buf = msg->GetTypeID (); // I2NP msg type
htobe32buf (buf + 1, msg->GetMsgID ()); // msgID
htobe32buf (buf + 5, msg->GetExpiration ()/1000); // expiration in seconds
memcpy (buf + 9, msg->GetPayload (), msg->GetPayloadLength ());
}
else
return 0;
return cloveSize + 3; return cloveSize + 3;
} }
void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (int numTags) void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags)
{ {
for (int i = 0; i < numTags; i++) for (int i = 0; i < numTags; i++)
{ GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset);
auto index = m_ReceiveTagset.GetNextIndex ();
uint64_t tag = m_ReceiveTagset.GetNextSessionTag ();
GetOwner ()->AddECIESx25519SessionTag (index, tag, shared_from_this ());
}
} }
bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts) bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts)
@ -642,7 +901,7 @@ namespace garlic
*payload = 0; payload++; // flag and delivery instructions *payload = 0; payload++; // flag and delivery instructions
*payload = msg->GetTypeID (); // I2NP msg type *payload = msg->GetTypeID (); // I2NP msg type
htobe32buf (payload + 1, msg->GetMsgID ()); // msgID htobe32buf (payload + 1, msg->GetMsgID ()); // msgID
htobe32buf (payload + 5, msg->GetExpiration ()/1000); // expiration in seconds htobe32buf (payload + 5, msg->GetExpiration () / 1000); // expiration in seconds
memcpy (payload + 9, msg->GetPayload (), msg->GetPayloadLength ()); memcpy (payload + 9, msg->GetPayload (), msg->GetPayloadLength ());
if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len, buf, 8, key, nonce, buf + offset, len + 16, true)) // encrypt if (!i2p::crypto::AEADChaCha20Poly1305 (buf + offset, len, buf, 8, key, nonce, buf + offset, len + 16, true)) // encrypt
@ -660,5 +919,3 @@ namespace garlic
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef ECIES_X25519_AEAD_RATCHET_SESSION_H__ #ifndef ECIES_X25519_AEAD_RATCHET_SESSION_H__
#define ECIES_X25519_AEAD_RATCHET_SESSION_H__ #define ECIES_X25519_AEAD_RATCHET_SESSION_H__
@ -7,27 +15,49 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <list> #include <list>
#include <unordered_map>
#include "Identity.h" #include "Identity.h"
#include "Crypto.h" #include "Crypto.h"
#include "Garlic.h" #include "Garlic.h"
#include "Tag.h"
namespace i2p namespace i2p
{ {
namespace garlic namespace garlic
{ {
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second since session creation we can restart session after
const int ECIESX25519_EXPIRATION_TIMEOUT = 480; // in seconds
const int ECIESX25519_INACTIVITY_TIMEOUT = 90; // number of second we receive nothing and should restart if we can
const int ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT = 600; // in seconds
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_MIN_NUM_GENERATED_TAGS = 24;
const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 160;
const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12;
const size_t ECIESX25519_OPTIMAL_PAYLOAD_SIZE = 1912; // 1912 = 1956 /* to fit 2 tunnel messages */
// - 16 /* I2NP header */ - 16 /* poly hash */ - 8 /* tag */ - 4 /* garlic length */
class ECIESX25519AEADRatchetSession;
class RatchetTagSet class RatchetTagSet
{ {
public: public:
RatchetTagSet (std::shared_ptr<ECIESX25519AEADRatchetSession> session): m_Session (session) {};
void DHInitialize (const uint8_t * rootKey, const uint8_t * k); void DHInitialize (const uint8_t * rootKey, const uint8_t * k);
void NextSessionTagRatchet (); void NextSessionTagRatchet ();
uint64_t GetNextSessionTag (); uint64_t GetNextSessionTag ();
const uint8_t * GetNextRootKey () const { return m_NextRootKey; };
int GetNextIndex () const { return m_NextIndex; }; int GetNextIndex () const { return m_NextIndex; };
void GetSymmKey (int index, uint8_t * key); void GetSymmKey (int index, uint8_t * key);
private: std::shared_ptr<ECIESX25519AEADRatchetSession> GetSession () { return m_Session.lock (); };
int GetTagSetID () const { return m_TagSetID; };
void SetTagSetID (int tagsetID) { m_TagSetID = tagsetID; };
void CalculateSymmKeyCK (int index, uint8_t * key); void Expire ();
bool IsExpired (uint64_t ts) const { return m_ExpirationTimestamp && ts > m_ExpirationTimestamp; };
private: private:
@ -41,8 +71,12 @@ namespace garlic
uint64_t GetTag () const { return ll[4]; }; // tag = keydata[32:39] uint64_t GetTag () const { return ll[4]; }; // tag = keydata[32:39]
} m_KeyData; } m_KeyData;
uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64]; uint8_t m_SessTagConstant[32], m_SymmKeyCK[32], m_CurrentSymmKeyCK[64], m_NextRootKey[32];
int m_NextIndex, m_NextSymmKeyIndex; int m_NextIndex, m_NextSymmKeyIndex;
std::unordered_map<int, i2p::data::Tag<32> > m_ItermediateSymmKeys;
std::weak_ptr<ECIESX25519AEADRatchetSession> m_Session;
int m_TagSetID = 0;
uint64_t m_ExpirationTimestamp = 0;
}; };
enum ECIESx25519BlockType enum ECIESx25519BlockType
@ -51,34 +85,42 @@ namespace garlic
eECIESx25519BlkSessionID = 1, eECIESx25519BlkSessionID = 1,
eECIESx25519BlkTermination = 4, eECIESx25519BlkTermination = 4,
eECIESx25519BlkOptions = 5, eECIESx25519BlkOptions = 5,
eECIESx25519BlkNextSessionKey = 7, eECIESx25519BlkNextKey = 7,
eECIESx25519BlkAck = 8, eECIESx25519BlkAck = 8,
eECIESx25519BlkAckRequest = 9, eECIESx25519BlkAckRequest = 9,
eECIESx25519BlkGalicClove = 11, eECIESx25519BlkGalicClove = 11,
eECIESx25519BlkPadding = 254 eECIESx25519BlkPadding = 254
}; };
const uint8_t ECIESX25519_NEXT_KEY_KEY_PRESENT_FLAG = 0x01;
const int ECIESX25519_RESTART_TIMEOUT = 120; // number of second of inactivity we should restart after const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02;
const int ECIESX25519_EXPIRATION_TIMEOUT = 600; // in seconds 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, public std::enable_shared_from_this<ECIESX25519AEADRatchetSession>
{ {
enum SessionState enum SessionState
{ {
eSessionStateNew =0, eSessionStateNew = 0,
eSessionStateNewSessionReceived, eSessionStateNewSessionReceived,
eSessionStateNewSessionSent, eSessionStateNewSessionSent,
eSessionStateNewSessionReplySent, eSessionStateNewSessionReplySent,
eSessionStateEstablished eSessionStateEstablished
}; };
struct DHRatchet
{
int keyID = 0;
i2p::crypto::X25519Keys key;
uint8_t remote[32]; // last remote public key
bool newKey = true;
};
public: public:
ECIESX25519AEADRatchetSession (GarlicDestination * owner); ECIESX25519AEADRatchetSession (GarlicDestination * owner, bool attachLeaseSet);
~ECIESX25519AEADRatchetSession (); ~ECIESX25519AEADRatchetSession ();
bool HandleNextMessage (const uint8_t * buf, size_t len, 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);
const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; }
@ -90,7 +132,10 @@ namespace garlic
} }
bool CheckExpired (uint64_t ts); // true is expired bool CheckExpired (uint64_t ts); // true is expired
bool CanBeRestarted (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_RESTART_TIMEOUT; } bool CanBeRestarted (uint64_t ts) const { return ts > m_SessionCreatedTimestamp + ECIESX25519_RESTART_TIMEOUT; }
bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); }
bool IsRatchets () const { return true; };
private: private:
@ -98,35 +143,48 @@ namespace garlic
void MixHash (const uint8_t * buf, size_t len); 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
uint64_t CreateNewSessionTag () const; std::shared_ptr<RatchetTagSet> CreateNewSessionTagset ();
bool HandleNewIncomingSession (const uint8_t * buf, size_t len); bool HandleNewIncomingSession (const uint8_t * buf, size_t len);
bool HandleNewOutgoingSessionReply (const uint8_t * buf, size_t len); bool HandleNewOutgoingSessionReply (uint8_t * buf, size_t len);
bool HandleExistingSessionMessage (const uint8_t * buf, size_t len, int index); bool HandleExistingSessionMessage (uint8_t * buf, size_t len, std::shared_ptr<RatchetTagSet> receiveTagset, int index);
void HandlePayload (const uint8_t * buf, size_t len, int index = 0); 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);
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 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);
std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg); std::vector<uint8_t> CreatePayload (std::shared_ptr<const I2NPMessage> msg, bool first);
size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination = false); size_t CreateGarlicClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len, bool isDestination = false);
size_t CreateDeliveryStatusClove (std::shared_ptr<const I2NPMessage> msg, uint8_t * buf, size_t len); size_t CreateLeaseSetClove (std::shared_ptr<const i2p::data::LocalLeaseSet> ls, uint64_t ts, uint8_t * buf, size_t len);
void GenerateMoreReceiveTags (int numTags); void GenerateMoreReceiveTags (std::shared_ptr<RatchetTagSet> receiveTagset, int numTags);
void NewNextSendRatchet ();
private: private:
uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, 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_NSRHeader[56], 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
i2p::crypto::X25519Keys m_EphemeralKeys; i2p::crypto::X25519Keys m_EphemeralKeys;
SessionState m_State = eSessionStateNew; SessionState m_State = eSessionStateNew;
uint64_t m_LastActivityTimestamp = 0; // incoming uint64_t m_SessionCreatedTimestamp = 0, m_LastActivityTimestamp = 0; // incoming
RatchetTagSet m_SendTagset, m_ReceiveTagset; std::shared_ptr<RatchetTagSet> m_SendTagset, m_NSRTagset;
std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it std::unique_ptr<i2p::data::IdentHash> m_Destination;// TODO: might not need it
std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index) std::list<std::pair<uint16_t, int> > m_AckRequests; // (tagsetid, index)
bool m_SendReverseKey = false, m_SendForwardKey = false;
std::unique_ptr<DHRatchet> m_NextReceiveRatchet, m_NextSendRatchet;
public:
// for HTTP only
int GetState () const { return (int)m_State; }
i2p::data::IdentHash GetDestination () const
{
return m_Destination ? *m_Destination : i2p::data::IdentHash ();
}
}; };
std::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag); std::shared_ptr<I2NPMessage> WrapECIESX25519AEADRatchetMessage (std::shared_ptr<const I2NPMessage> msg, const uint8_t * key, uint64_t tag);

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <openssl/sha.h> #include <openssl/sha.h>
#include "Log.h" #include "Log.h"
#include "Crypto.h" #include "Crypto.h"
@ -597,4 +605,3 @@ namespace crypto
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef ED25519_H__ #ifndef ED25519_H__
#define ED25519_H__ #define ED25519_H__
@ -128,6 +136,4 @@ namespace crypto
} }
} }
#endif #endif

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <openssl/rand.h> #include <openssl/rand.h>
#include "Crypto.h" #include "Crypto.h"
#include "Elligator.h" #include "Elligator.h"
@ -204,4 +212,3 @@ namespace crypto
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef ELLIGATOR_H__ #ifndef ELLIGATOR_H__
#define ELLIGATOR_H__ #define ELLIGATOR_H__
@ -35,5 +43,3 @@ namespace crypto
} }
#endif #endif

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2016, 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
* *

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013-2016, 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
* *
@ -35,8 +35,10 @@ namespace fs {
* std::vector<std::string> files; * std::vector<std::string> files;
* h.Traverse(files); <- finds all files in storage and saves in given vector * h.Traverse(files); <- finds all files in storage and saves in given vector
*/ */
class HashedStorage { class HashedStorage
{
protected: protected:
std::string root; /**< path to storage with it's name included */ std::string root; /**< path to storage with it's name included */
std::string name; /**< name of the storage */ std::string name; /**< name of the storage */
std::string prefix1; /**< hashed directory prefix */ std::string prefix1; /**< hashed directory prefix */
@ -44,6 +46,7 @@ namespace fs {
std::string suffix; /**< suffix of file in storage (extension) */ std::string suffix; /**< suffix of file in storage (extension) */
public: public:
typedef std::function<void(const std::string &)> FilenameVisitor; typedef std::function<void(const std::string &)> FilenameVisitor;
HashedStorage(const char *n, const char *p1, const char *p2, const char *s): HashedStorage(const char *n, const char *p1, const char *p2, const char *s):
name(n), prefix1(p1), prefix2(p2), suffix(s) {}; name(n), prefix1(p1), prefix2(p2), suffix(s) {};

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <string.h> #include <string.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
@ -113,9 +121,9 @@ namespace data
bool Families::VerifyFamily (const std::string& family, const IdentHash& ident, bool Families::VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key) const char * signature, const char * key)
{ {
uint8_t buf[50], signatureBuf[64]; uint8_t buf[100], signatureBuf[64];
size_t len = family.length (), signatureLen = strlen (signature); size_t len = family.length (), signatureLen = strlen (signature);
if (len + 32 > 50) if (len + 32 > 100)
{ {
LogPrint (eLogError, "Family: ", family, " is too long"); LogPrint (eLogError, "Family: ", family, " is too long");
return false; return false;
@ -179,4 +187,3 @@ namespace data
} }
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef FAMILY_H__ #ifndef FAMILY_H__
#define FAMILY_H__ #define FAMILY_H__

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <inttypes.h> #include <inttypes.h>
#include "I2PEndian.h" #include "I2PEndian.h"
#include <map> #include <map>
@ -466,8 +474,9 @@ namespace garlic
LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ()); LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ());
return; return;
} }
auto mod = length & 0x0f; // %16
buf += 4; // length buf += 4; // length
auto it = m_Tags.find (SessionTag(buf)); auto it = !mod ? m_Tags.find (SessionTag(buf)) : m_Tags.end (); // AES block is multiple of 16
// AES tag might be used even if encryption type is not ElGamal/AES // AES tag might be used even if encryption type is not ElGamal/AES
if (it != m_Tags.end ()) if (it != m_Tags.end ())
{ {
@ -487,15 +496,30 @@ namespace garlic
} }
else else
{ {
// tag not found. Handle depending on encryption type bool found = false;
if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET)) if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
{ {
HandleECIESx25519 (buf, length); // try ECIESx25519 tag
return; uint64_t tag;
memcpy (&tag, buf, 8);
auto it1 = m_ECIESx25519Tags.find (tag);
if (it1 != m_ECIESx25519Tags.end ())
{
found = true;
auto session = it1->second.tagset->GetSession ();
if (!session || !session->HandleNextMessage (buf, length, it1->second.tagset, it1->second.index))
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
m_ECIESx25519Tags.erase (it1);
} }
// otherwise assume ElGamal/AES }
if (!found) // assume new session
{
// AES tag not found. Handle depending on encryption type
// try ElGamal/AES first if leading block is 514
ElGamalBlock elGamal; ElGamalBlock elGamal;
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)) if (mod == 2 && length >= 514 && SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) &&
Decrypt (buf, (uint8_t *)&elGamal, m_Ctx, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL))
{ {
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey); auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
@ -504,10 +528,18 @@ 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))
{
// otherwise ECIESx25519
auto session = std::make_shared<ECIESX25519AEADRatchetSession> (this, false); // incoming
if (!session->HandleNextMessage (buf, length, nullptr, 0))
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
}
else else
LogPrint (eLogError, "Garlic: Failed to decrypt message"); LogPrint (eLogError, "Garlic: Failed to decrypt message");
} }
} }
}
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption, void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
std::shared_ptr<i2p::tunnel::InboundTunnel> from) std::shared_ptr<i2p::tunnel::InboundTunnel> from)
@ -679,18 +711,25 @@ namespace garlic
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_RARCHET && if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET &&
SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RARCHET)) SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET))
{ {
ECIESX25519AEADRatchetSessionPtr session; ECIESX25519AEADRatchetSessionPtr session;
uint8_t staticKey[32]; uint8_t staticKey[32];
destination->Encrypt (nullptr, staticKey, nullptr); // we are supposed to get static key destination->Encrypt (nullptr, staticKey, nullptr); // we are supposed to get static key
auto it = m_ECIESx25519Sessions.find (staticKey); auto it = m_ECIESx25519Sessions.find (staticKey);
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
{
session = it->second; session = it->second;
if (session->IsInactive (i2p::util::GetSecondsSinceEpoch ()))
{
LogPrint (eLogDebug, "Garlic: session restarted");
session = nullptr;
}
}
if (!session) if (!session)
{ {
session = std::make_shared<ECIESX25519AEADRatchetSession> (this); session = std::make_shared<ECIESX25519AEADRatchetSession> (this, true);
session->SetRemoteStaticKey (staticKey); session->SetRemoteStaticKey (staticKey);
} }
session->SetDestination (destination->GetIdentHash ()); // TODO: remove session->SetDestination (destination->GetIdentHash ()); // TODO: remove
@ -764,7 +803,7 @@ namespace garlic
// ECIESx25519 // ECIESx25519
for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();) for (auto it = m_ECIESx25519Tags.begin (); it != m_ECIESx25519Tags.end ();)
{ {
if (ts > it->second.creationTime + INCOMING_TAGS_EXPIRATION_TIMEOUT) if (it->second.tagset->IsExpired (ts) || ts > it->second.creationTime + ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT)
it = m_ECIESx25519Tags.erase (it); it = m_ECIESx25519Tags.erase (it);
else else
++it; ++it;
@ -906,26 +945,6 @@ namespace garlic
i2p::fs::Remove (it); i2p::fs::Remove (it);
} }
void GarlicDestination::HandleECIESx25519 (const uint8_t * buf, size_t len)
{
uint64_t tag;
memcpy (&tag, buf, 8);
ECIESX25519AEADRatchetSessionPtr session;
int index = 0;
auto it = m_ECIESx25519Tags.find (tag);
if (it != m_ECIESx25519Tags.end ())
{
session = it->second.session;
index = it->second.index;
m_ECIESx25519Tags.erase (tag);
}
else
session = std::make_shared<ECIESX25519AEADRatchetSession> (this); // incoming
if (!session->HandleNextMessage (buf, len, index))
LogPrint (eLogError, "Garlic: can't handle ECIES-X25519-AEAD-Ratchet message");
}
void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len) void GarlicDestination::HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len)
{ {
const uint8_t * buf1 = buf; const uint8_t * buf1 = buf;
@ -985,9 +1004,11 @@ namespace garlic
} }
} }
void GarlicDestination::AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session) void GarlicDestination::AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset)
{ {
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexSession{index, session, i2p::util::GetSecondsSinceEpoch ()}); auto index = tagset->GetNextIndex ();
uint64_t tag = tagset->GetNextSessionTag ();
m_ECIESx25519Tags.emplace (tag, ECIESX25519AEADRatchetIndexTagset{index, tagset, i2p::util::GetSecondsSinceEpoch ()});
} }
void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session) void GarlicDestination::AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session)
@ -997,7 +1018,10 @@ namespace garlic
if (it != m_ECIESx25519Sessions.end ()) if (it != m_ECIESx25519Sessions.end ())
{ {
if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ())) if (it->second->CanBeRestarted (i2p::util::GetSecondsSinceEpoch ()))
{
it->second->SetOwner (nullptr); // detach
m_ECIESx25519Sessions.erase (it); m_ECIESx25519Sessions.erase (it);
}
else else
{ {
LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists"); LogPrint (eLogInfo, "Garlic: ECIESx25519 session with static key ", staticKeyTag.ToBase64 (), " already exists");
@ -1007,5 +1031,14 @@ namespace garlic
m_ECIESx25519Sessions.emplace (staticKeyTag, session); m_ECIESx25519Sessions.emplace (staticKeyTag, session);
} }
void GarlicDestination::RemoveECIESx25519Session (const uint8_t * staticKey)
{
auto it = m_ECIESx25519Sessions.find (staticKey);
if (it != m_ECIESx25519Sessions.end ())
{
it->second->SetOwner (nullptr);
m_ECIESx25519Sessions.erase (it);
}
}
} }
} }

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef GARLIC_H__ #ifndef GARLIC_H__
#define GARLIC_H__ #define GARLIC_H__
@ -105,6 +113,7 @@ namespace garlic
virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0; virtual std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg) = 0;
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; };
void SetLeaseSetUpdated () void SetLeaseSetUpdated ()
{ {
@ -142,6 +151,7 @@ namespace garlic
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath; std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
public: public:
// for HTTP only // for HTTP only
virtual size_t GetNumOutgoingTags () const { return 0; }; virtual size_t GetNumOutgoingTags () const { return 0; };
}; };
@ -195,6 +205,7 @@ namespace garlic
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
public: public:
// for HTTP only // for HTTP only
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); }; size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
}; };
@ -202,10 +213,12 @@ namespace garlic
class ECIESX25519AEADRatchetSession; class ECIESX25519AEADRatchetSession;
typedef std::shared_ptr<ECIESX25519AEADRatchetSession> ECIESX25519AEADRatchetSessionPtr; typedef std::shared_ptr<ECIESX25519AEADRatchetSession> ECIESX25519AEADRatchetSessionPtr;
struct ECIESX25519AEADRatchetIndexSession class RatchetTagSet;
typedef std::shared_ptr<RatchetTagSet> RatchetTagSetPtr;
struct ECIESX25519AEADRatchetIndexTagset
{ {
int index; int index;
ECIESX25519AEADRatchetSessionPtr session; RatchetTagSetPtr tagset;
uint64_t creationTime; // seconds since epoch uint64_t creationTime; // seconds since epoch
}; };
@ -228,8 +241,9 @@ namespace garlic
void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag
virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread virtual bool SubmitSessionKey (const uint8_t * key, const uint8_t * tag); // from different thread
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID); void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
void AddECIESx25519SessionTag (int index, uint64_t tag, ECIESX25519AEADRatchetSessionPtr session); void AddECIESx25519SessionNextTag (RatchetTagSetPtr tagset);
void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session); void AddECIESx25519Session (const uint8_t * staticKey, ECIESX25519AEADRatchetSessionPtr session);
void RemoveECIESx25519Session (const uint8_t * staticKey);
void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len); void HandleECIESx25519GarlicClove (const uint8_t * buf, size_t len);
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
@ -255,9 +269,6 @@ namespace garlic
std::shared_ptr<i2p::tunnel::InboundTunnel> from); std::shared_ptr<i2p::tunnel::InboundTunnel> from);
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from); void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
// ECIES-X25519-AEAD-Ratchet
void HandleECIESx25519 (const uint8_t * buf, size_t len);
private: private:
BN_CTX * m_Ctx; // incoming BN_CTX * m_Ctx; // incoming
@ -268,7 +279,7 @@ namespace garlic
std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session std::unordered_map<i2p::data::Tag<32>, ECIESX25519AEADRatchetSessionPtr> m_ECIESx25519Sessions; // static key -> session
// incoming // incoming
std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags; std::unordered_map<SessionTag, std::shared_ptr<AESDecryption>, std::hash<i2p::data::Tag<32> > > m_Tags;
std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexSession> m_ECIESx25519Tags; // session tag -> session std::unordered_map<uint64_t, ECIESX25519AEADRatchetIndexTagset> m_ECIESx25519Tags; // session tag -> session
// DeliveryStatus // DeliveryStatus
std::mutex m_DeliveryStatusSessionsMutex; std::mutex m_DeliveryStatusSessionsMutex;
std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session std::unordered_map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
@ -277,7 +288,9 @@ namespace garlic
// for HTTP only // for HTTP only
size_t GetNumIncomingTags () const { return m_Tags.size (); } size_t GetNumIncomingTags () const { return m_Tags.size (); }
size_t GetNumIncomingECIESx25519Tags () const { return m_ECIESx25519Tags.size (); }
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
const decltype(m_ECIESx25519Sessions)& GetECIESx25519Sessions () const { return m_ECIESx25519Sessions; }
}; };
void CleanUpTagsFiles (); void CleanUpTagsFiles ();

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#include <string.h> #include <string.h>
#include <array> #include <array>
#include <openssl/bn.h> #include <openssl/bn.h>

View File

@ -1,3 +1,11 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef GOST_H__ #ifndef GOST_H__
#define GOST_H__ #define GOST_H__

View File

@ -1,5 +1,5 @@
/* /*
* 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
* *
@ -10,6 +10,7 @@
#include <string.h> /* memset */ #include <string.h> /* memset */
#include <iostream> #include <iostream>
#include "Log.h" #include "Log.h"
#include "I2PEndian.h"
#include "Gzip.h" #include "Gzip.h"
namespace i2p namespace i2p
@ -30,6 +31,21 @@ namespace data
} }
size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen)
{
if (inLen < 23) return 0;
if (in[10] == 0x01) // non compressed
{
size_t len = bufle16toh (in + 11);
if (len + 23 < inLen)
{
LogPrint (eLogError, "Gzip: Incorrect length");
return 0;
}
if (len > outLen) len = outLen;
memcpy (out, in + 15, len);
return len;
}
else
{ {
if (m_IsDirty) inflateReset (&m_Inflator); if (m_IsDirty) inflateReset (&m_Inflator);
m_IsDirty = true; m_IsDirty = true;
@ -44,6 +60,7 @@ namespace data
LogPrint (eLogError, "Gzip: Inflate error ", err); LogPrint (eLogError, "Gzip: Inflate error ", err);
return 0; return 0;
} }
}
void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os) void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os)
{ {
@ -106,10 +123,79 @@ namespace data
m_Deflator.avail_out = outLen; m_Deflator.avail_out = outLen;
int err; int err;
if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END)
{
out[9] = 0xff; // OS is always unknown
return outLen - m_Deflator.avail_out; return outLen - m_Deflator.avail_out;
}
// else // else
LogPrint (eLogError, "Gzip: Deflate error ", err); LogPrint (eLogError, "Gzip: Deflate error ", err);
return 0; return 0;
} }
size_t GzipDeflator::Deflate (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen)
{
if (m_IsDirty) deflateReset (&m_Deflator);
m_IsDirty = true;
size_t offset = 0;
int err;
for (const auto& it: bufs)
{
m_Deflator.next_in = const_cast<uint8_t *>(it.first);
m_Deflator.avail_in = it.second;
m_Deflator.next_out = out + offset;
m_Deflator.avail_out = outLen - offset;
auto flush = (it == bufs.back ()) ? Z_FINISH : Z_NO_FLUSH;
err = deflate (&m_Deflator, flush);
if (err)
{
if (flush && err == Z_STREAM_END)
{
out[9] = 0xff; // OS is always unknown
return outLen - m_Deflator.avail_out;
}
break;
}
offset = outLen - m_Deflator.avail_out;
}
// else
LogPrint (eLogError, "Gzip: Deflate error ", err);
return 0;
}
size_t GzipNoCompression (const uint8_t * in, uint16_t inLen, uint8_t * out, size_t outLen)
{
static const uint8_t gzipHeader[11] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x01 };
if (outLen < (size_t)inLen + 23) return 0;
memcpy (out, gzipHeader, 11);
htole16buf (out + 11, inLen);
htole16buf (out + 13, 0xffff - inLen);
memcpy (out + 15, in, inLen);
htole32buf (out + inLen + 15, crc32 (0, in, inLen));
htole32buf (out + inLen + 19, inLen);
return inLen + 23;
}
size_t GzipNoCompression (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen)
{
static const uint8_t gzipHeader[11] = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x01 };
memcpy (out, gzipHeader, 11);
uint32_t crc = 0;
size_t len = 0, len1;
for (const auto& it: bufs)
{
len1 = len;
len += it.second;
if (outLen < len + 23) return 0;
memcpy (out + 15 + len1, it.first, it.second);
crc = crc32 (crc, it.first, it.second);
}
if (len > 0xffff) return 0;
htole32buf (out + len + 15, crc);
htole32buf (out + len + 19, len);
htole16buf (out + 11, len);
htole16buf (out + 13, 0xffff - len);
return len + 23;
}
} // data } // data
} // i2p } // i2p

View File

@ -1,10 +1,21 @@
/*
* Copyright (c) 2013-2020, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
#ifndef GZIP_H__ #ifndef GZIP_H__
#define GZIP_H__ #define GZIP_H__
#include <zlib.h> #include <zlib.h>
#include <vector>
namespace i2p { namespace i2p
namespace data { {
namespace data
{
class GzipInflator class GzipInflator
{ {
public: public:
@ -32,12 +43,16 @@ namespace data {
void SetCompressionLevel (int level); void SetCompressionLevel (int level);
size_t Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen); size_t Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen);
size_t Deflate (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen);
private: private:
z_stream m_Deflator; z_stream m_Deflator;
bool m_IsDirty; bool m_IsDirty;
}; };
size_t GzipNoCompression (const uint8_t * in, uint16_t inLen, uint8_t * out, size_t outLen); // for < 64K
size_t GzipNoCompression (const std::vector<std::pair<const uint8_t *, size_t> >& bufs, uint8_t * out, size_t outLen); // for total size < 64K
} // data } // data
} // i2p } // i2p

View File

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

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