Merge remote-tracking branch 'purple/openssl' into streaming_race_fix_2018_01_15

This commit is contained in:
Jeff Becker 2018-01-15 08:25:58 -05:00
commit 43a751ee0b
No known key found for this signature in database
GPG key ID: F357B3B42F6F9B05
124 changed files with 3097 additions and 3100 deletions

View file

@ -37,7 +37,7 @@
## [2.15.0] - 2017-08-17 ## [2.15.0] - 2017-08-17
### Added ### Added
- QT GUI - QT GUI
- Ability to add and remove I2P tunnels without restart - Ability to add and remove I2P tunnels without restart
- Ability to disable SOCKS outproxy option - Ability to disable SOCKS outproxy option
### Changed ### Changed
@ -81,7 +81,7 @@
- Some stats in a main window for Windows version - Some stats in a main window for Windows version
### Changed ### Changed
- Reseed servers list - Reseed servers list
- MTU of 1488 for ipv6 - MTU of 1488 for ipv6
- Android and Mac OS X versions use OpenSSL 1.1 - Android and Mac OS X versions use OpenSSL 1.1
- New logo for Android - New logo for Android
### Fixed ### Fixed
@ -111,7 +111,7 @@
## [2.10.2] - 2016-12-04 ## [2.10.2] - 2016-12-04
### Fixed ### Fixed
- Fixes UPnP discovery bug, producing excessive CPU usage - Fixes UPnP discovery bug, producing excessive CPU usage
- Fixes sudden SSU thread stop for Windows. - Fixes sudden SSU thread stop for Windows.
## [2.10.1] - 2016-11-07 ## [2.10.1] - 2016-11-07
### Fixed ### Fixed

View file

@ -13,13 +13,13 @@ RUN mkdir /user && adduser -S -h /user i2pd && chown -R i2pd:nobody /user
# #
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the # Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer. # image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
# #
# 1. install deps, clone and build. # 1. install deps, clone and build.
# 2. strip binaries. # 2. strip binaries.
# 3. Purge all dependencies and other unrelated packages, including build directory. # 3. Purge all dependencies and other unrelated packages, including build directory.
RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \ RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \
&& mkdir -p /tmp/build \ && mkdir -p /tmp/build \
&& cd /tmp/build && git clone -b ${GIT_BRANCH} https://github.com/PurpleI2P/i2pd.git \ && cd /tmp/build && git clone -b ${GIT_BRANCH} https://github.com/PurpleI2P/i2pd.git \

View file

@ -4,7 +4,7 @@ BOOSTROOT = ${BREWROOT}/opt/boost
SSLROOT = ${BREWROOT}/opt/libressl SSLROOT = ${BREWROOT}/opt/libressl
UPNPROOT = ${BREWROOT}/opt/miniupnpc UPNPROOT = ${BREWROOT}/opt/miniupnpc
CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual CXXFLAGS = -g -Wall -std=c++11 -DMAC_OSX -Wno-overloaded-virtual
INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include INCFLAGS = -I${SSLROOT}/include -I${BOOSTROOT}/include
ifndef TRAVIS ifndef TRAVIS
CXX = clang++ CXX = clang++

View file

@ -12,7 +12,7 @@ INCFLAGS ?=
# detect proper flag for c++11 support by compilers # detect proper flag for c++11 support by compilers
CXXVER := $(shell $(CXX) -dumpversion) CXXVER := $(shell $(CXX) -dumpversion)
ifeq ($(shell expr match $(CXX) 'clang'),5) ifeq ($(shell expr match $(CXX) 'clang'),5)
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10 else ifeq ($(shell expr match ${CXXVER} "4\.[0-9][0-9]"),4) # gcc >= 4.10
NEEDED_CXXFLAGS += -std=c++11 NEEDED_CXXFLAGS += -std=c++11
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7 else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7

View file

@ -1,7 +1,7 @@
CXX = clang++ CXX = clang++
CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX
#CXXFLAGS = -g -O2 -Wall -std=c++11 #CXXFLAGS = -g -O2 -Wall -std=c++11
INCFLAGS = -I/usr/local/include INCFLAGS = -I/usr/local/include
LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib LDFLAGS = -Wl,-rpath,/usr/local/lib -L/usr/local/lib
ifeq ($(USE_STATIC),yes) ifeq ($(USE_STATIC),yes)

View file

@ -5,13 +5,13 @@ i2pd
i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client. i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client.
I2P (Invisible Internet Protocol) is a universal anonymous network layer. I2P (Invisible Internet Protocol) is a universal anonymous network layer.
All communications over I2P are anonymous and end-to-end encrypted, participants All communications over I2P are anonymous and end-to-end encrypted, participants
don't reveal their real IP addresses. don't reveal their real IP addresses.
I2P client is a software used for building and using anonymous I2P I2P client is a software used for building and using anonymous I2P
networks. Such networks are commonly used for anonymous peer-to-peer networks. Such networks are commonly used for anonymous peer-to-peer
applications (filesharing, cryptocurrencies) and anonymous client-server applications (filesharing, cryptocurrencies) and anonymous client-server
applications (websites, instant messengers, chat-servers). applications (websites, instant messengers, chat-servers).
I2P allows people from all around the world to communicate and share information I2P allows people from all around the world to communicate and share information
@ -38,9 +38,9 @@ Resources
Installing Installing
---------- ----------
The easiest way to install i2pd is by using The easiest way to install i2pd is by using
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest). [precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
i2pd from source on your OS. i2pd from source on your OS.
@ -58,25 +58,25 @@ Build instructions:
* 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)
* FreeBSD * FreeBSD
* Android * Android
* iOS * iOS
Using i2pd Using i2pd
---------- ----------
See [documentation](https://i2pd.readthedocs.io/en/latest/user-guide/run/) and See [documentation](https://i2pd.readthedocs.io/en/latest/user-guide/run/) and
[example config file](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/i2pd.conf). [example config file](https://github.com/PurpleI2P/i2pd/blob/openssl/contrib/i2pd.conf).
Donations Donations
--------- ---------
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59 LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
License License
------- -------

View file

@ -23,4 +23,4 @@
</activity> </activity>
<service android:enabled="true" android:name=".ForegroundService"/> <service android:enabled="true" android:name=".ForegroundService"/>
</application> </application>
</manifest> </manifest>

View file

@ -1,7 +1,7 @@
<menu <menu
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
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=".I2PD"> tools:context=".I2PD">
<item <item
android:id="@+id/action_graceful_quit" android:id="@+id/action_graceful_quit"

View file

@ -14,10 +14,10 @@ public class DaemonSingleton {
public static DaemonSingleton getInstance() { public static DaemonSingleton getInstance() {
return instance; return instance;
} }
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
public synchronized void stopAcceptingTunnels() { public synchronized void stopAcceptingTunnels() {
if(isStartedOkay()){ if(isStartedOkay()){
state=State.gracefulShutdownInProgress; state=State.gracefulShutdownInProgress;
@ -25,19 +25,19 @@ public class DaemonSingleton {
I2PD_JNI.stopAcceptingTunnels(); I2PD_JNI.stopAcceptingTunnels();
} }
} }
public void onNetworkStateChange(boolean isConnected) { public void onNetworkStateChange(boolean isConnected) {
I2PD_JNI.onNetworkStateChanged(isConnected); I2PD_JNI.onNetworkStateChanged(isConnected);
} }
private boolean startedOkay; private boolean startedOkay;
public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress}; public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress};
private State state = State.uninitialized; private State state = State.uninitialized;
public State getState() { return state; } public State getState() { return state; }
public synchronized void start() { public synchronized void start() {
if(state != State.uninitialized)return; if(state != State.uninitialized)return;
state = State.starting; state = State.starting;
@ -76,9 +76,9 @@ public class DaemonSingleton {
fireStateUpdate(); fireStateUpdate();
} }
return; return;
} }
} }
}, "i2pdDaemonStart").start(); }, "i2pdDaemonStart").start();
} }
private Throwable lastThrowable; private Throwable lastThrowable;
@ -87,10 +87,10 @@ public class DaemonSingleton {
private synchronized void fireStateUpdate() { private synchronized void fireStateUpdate() {
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) {
Log.e(TAG, "exception in listener ignored", tr); Log.e(TAG, "exception in listener ignored", tr);
} }
} }
} }
@ -102,7 +102,7 @@ public class DaemonSingleton {
public String getDaemonStartResult() { public String getDaemonStartResult() {
return daemonStartResult; return daemonStartResult;
} }
private final Object startedOkayLock = new Object(); private final Object startedOkayLock = new Object();
public boolean isStartedOkay() { public boolean isStartedOkay() {

View file

@ -50,7 +50,7 @@ public class ForegroundService extends Service {
public void onDestroy() { public void onDestroy() {
// Cancel the persistent notification. // Cancel the persistent notification.
notificationManager.cancel(NOTIFICATION); notificationManager.cancel(NOTIFICATION);
stopForeground(true); stopForeground(true);
// Tell the user we stopped. // Tell the user we stopped.
@ -91,7 +91,7 @@ public class ForegroundService extends Service {
//mNM.notify(NOTIFICATION, notification); //mNM.notify(NOTIFICATION, notification);
startForeground(NOTIFICATION, notification); startForeground(NOTIFICATION, notification);
} }
private final DaemonSingleton daemon = DaemonSingleton.getInstance(); private final DaemonSingleton daemon = DaemonSingleton.getInstance();
} }

View file

@ -24,12 +24,12 @@ public class I2PD extends Activity {
private static final String TAG = "i2pd"; private static final String TAG = "i2pd";
private TextView textView; private TextView textView;
private final DaemonSingleton daemon = DaemonSingleton.getInstance(); private final DaemonSingleton daemon = DaemonSingleton.getInstance();
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() { new DaemonSingleton.StateUpdateListener() {
@Override @Override
public void daemonStateUpdate() { public void daemonStateUpdate() {
runOnUiThread(new Runnable(){ runOnUiThread(new Runnable(){
@ -53,7 +53,7 @@ public class I2PD extends Activity {
}); });
} }
}; };
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -123,7 +123,7 @@ public class I2PD extends Activity {
} }
}; };
private boolean mIsBound; private boolean mIsBound;
private void doBindService() { private void doBindService() {
@ -147,7 +147,7 @@ public class I2PD extends Activity {
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present. // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.options_main, menu); getMenuInflater().inflate(R.menu.options_main, menu);
return true; return true;
} }
@ -216,9 +216,9 @@ public class I2PD extends Activity {
@Override @Override
public void run() { public void run() {
quit(); quit();
} }
}, 10*60*1000/*milliseconds*/); }, 10*60*1000/*milliseconds*/);
}else{ }else{
quit(); quit();
@ -227,7 +227,7 @@ public class I2PD extends Activity {
Log.e(TAG,"",tr); Log.e(TAG,"",tr);
} }
} }
},"gracQuitInit").start(); },"gracQuitInit").start();
} }

View file

@ -9,9 +9,9 @@ public class I2PD_JNI {
public static native String startDaemon(); public static native String startDaemon();
//should only be called after startDaemon() success //should only be called after startDaemon() success
public static native void stopDaemon(); public static native void stopDaemon();
public static native void stopAcceptingTunnels(); public static native void stopAcceptingTunnels();
public static native void onNetworkStateChanged(boolean isConnected); public static native void onNetworkStateChanged(boolean isConnected);
public static void loadLibraries() { public static void loadLibraries() {

View file

@ -24,5 +24,5 @@ else()
endif() endif()
mark_as_advanced(MINIUPNPC_INCLUDE_DIR MINIUPNPC_LIBRARY) mark_as_advanced(MINIUPNPC_INCLUDE_DIR MINIUPNPC_LIBRARY)
endif() endif()

View file

@ -5,7 +5,7 @@ RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \
libssl-dev git build-essential libssl-dev git build-essential
RUN git clone https://github.com/PurpleI2P/i2pd.git RUN git clone https://github.com/PurpleI2P/i2pd.git
WORKDIR /i2pd WORKDIR /i2pd
RUN make RUN make
CMD ./i2pd CMD ./i2pd

View file

@ -1,4 +1,4 @@
# Basic profile for i2pd # Basic profile for i2pd
# Should work without modifications with Ubuntu/Debian packages # Should work without modifications with Ubuntu/Debian packages
# Author: Darknet Villain <supervillain@riseup.net> # Author: Darknet Villain <supervillain@riseup.net>
# #

View file

@ -17,13 +17,13 @@ RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
&& chown -R i2pd:nobody "$I2PD_HOME" && chown -R i2pd:nobody "$I2PD_HOME"
# #
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the # Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
# image under 20mb we need to remove all the build dependencies in the same "RUN" / layer. # image under 20mb we need to remove all the build dependencies in the same "RUN" / layer.
# #
# 1. install deps, clone and build. # 1. install deps, clone and build.
# 2. strip binaries. # 2. strip binaries.
# 3. Purge all dependencies and other unrelated packages, including build directory. # 3. Purge all dependencies and other unrelated packages, including build directory.
RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \ RUN apk --no-cache --virtual build-dependendencies add make gcc g++ libtool boost-dev build-base openssl-dev openssl git \
&& mkdir -p /tmp/build \ && mkdir -p /tmp/build \
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \ && cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \

View file

@ -54,7 +54,7 @@ ipv4 = true
ipv6 = false ipv6 = false
## Network interface to bind to ## Network interface to bind to
# ifname = # ifname =
## Enable NTCP transport (default = true) ## Enable NTCP transport (default = true)
# ntcp = true # ntcp = true
@ -88,18 +88,18 @@ ipv6 = false
[upnp] [upnp]
## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID) ## Enable or disable UPnP: automatic port forwarding (enabled by default in WINDOWS, ANDROID)
# enabled = false # enabled = false
## Name i2pd appears in UPnP forwardings list (default = I2Pd) ## Name i2pd appears in UPnP forwardings list (default = I2Pd)
# name = I2Pd # name = I2Pd
[reseed] [reseed]
## Enable or disable reseed data verification. ## Enable or disable reseed data verification.
verify = true verify = true
## URLs to request reseed data from, separated by comma ## URLs to request reseed data from, separated by comma
## Default: "mainline" I2P Network reseeds ## Default: "mainline" I2P Network reseeds
# urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/ # urls = https://reseed.i2p-projekt.de/,https://i2p.mooo.com/netDb/,https://netdb.i2p2.no/
## Path to local reseed data file (.su3) for manual reseeding ## Path to local reseed data file (.su3) for manual reseeding
# file = /path/to/i2pseeds.su3 # file = /path/to/i2pseeds.su3
## or HTTPS URL to reseed from ## or HTTPS URL to reseed from
# file = https://legit-website.com/i2pseeds.su3 # file = https://legit-website.com/i2pseeds.su3

View file

@ -48,7 +48,7 @@ using dedicated user's permissions.
%build %build
cd build cd build
%if 0%{?rhel} == 7 %if 0%{?rhel} == 7
%cmake3 \ %cmake3 \
-DWITH_LIBRARY=OFF \ -DWITH_LIBRARY=OFF \
-DWITH_UPNP=ON \ -DWITH_UPNP=ON \
@ -133,7 +133,7 @@ getent passwd i2pd >/dev/null || \
- Fixed QT GUI issues - Fixed QT GUI issues
* Thu Aug 17 2017 orignal <i2porignal@yandex.ru> - 2.15.0 * Thu Aug 17 2017 orignal <i2porignal@yandex.ru> - 2.15.0
- Added QT GUI - Added QT GUI
- Added ability add and remove I2P tunnels without restart - Added ability add and remove I2P tunnels without restart
- Added ability to disable SOCKS outproxy option - Added ability to disable SOCKS outproxy option
- Changed strip-out Accept-* hedaers in HTTP proxy - Changed strip-out Accept-* hedaers in HTTP proxy

View file

@ -123,7 +123,7 @@ namespace i2p
LogPrint(eLogInfo, "AESNI enabled"); LogPrint(eLogInfo, "AESNI enabled");
#endif #endif
#if defined(__AVX__) #if defined(__AVX__)
LogPrint(eLogInfo, "AVX enabled"); LogPrint(eLogInfo, "AVX enabled");
#endif #endif
LogPrint(eLogDebug, "FS: main config file: ", config); LogPrint(eLogDebug, "FS: main config file: ", config);
LogPrint(eLogDebug, "FS: data directory: ", datadir); LogPrint(eLogDebug, "FS: data directory: ", datadir);

View file

@ -505,7 +505,7 @@ namespace http {
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#endif #endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n"; s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n";
s << "<br>\r\n<b>Logging level</b><br>\r\n"; s << "<br>\r\n<b>Logging level</b><br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\">[none]</a> "; s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\">[none]</a> ";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> "; s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> ";

View file

@ -10,12 +10,12 @@
#include <sstream> #include <sstream>
#include "HTTP.h" #include "HTTP.h"
namespace i2p namespace i2p
{ {
namespace http namespace http
{ {
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192; const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
class HTTPConnection: public std::enable_shared_from_this<HTTPConnection> class HTTPConnection: public std::enable_shared_from_this<HTTPConnection>
{ {
@ -23,7 +23,7 @@ namespace http
HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket); HTTPConnection (std::shared_ptr<boost::asio::ip::tcp::socket> socket);
void Receive (); void Receive ();
private: private:
void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred);
@ -63,11 +63,11 @@ namespace http
private: private:
void Run (); void Run ();
void Accept (); void Accept ();
void HandleAccept(const boost::system::error_code& ecode, void HandleAccept(const boost::system::error_code& ecode,
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket); std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket); void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
private: private:
bool m_IsRunning; bool m_IsRunning;

View file

@ -67,7 +67,7 @@ namespace client
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler; m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
// I2PControl // I2PControl
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler; m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
// RouterInfo // RouterInfo
m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler; m_RouterInfoHandlers["i2p.router.uptime"] = &I2PControlService::UptimeHandler;
@ -80,13 +80,13 @@ namespace client
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;
// RouterManager // RouterManager
m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler; m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler; m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler; m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
// NetworkSetting // NetworkSetting
@ -133,8 +133,8 @@ namespace client
m_Service.run (); m_Service.run ();
} catch (std::exception& ex) { } catch (std::exception& ex) {
LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ()); LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ());
} }
} }
} }
void I2PControlService::Accept () void I2PControlService::Accept ()
@ -160,7 +160,7 @@ namespace client
void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket) void I2PControlService::Handshake (std::shared_ptr<ssl_socket> socket)
{ {
socket->async_handshake(boost::asio::ssl::stream_base::server, socket->async_handshake(boost::asio::ssl::stream_base::server,
std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket)); std::bind( &I2PControlService::HandleHandshake, this, std::placeholders::_1, socket));
} }
void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket) void I2PControlService::HandleHandshake (const boost::system::error_code& ecode, std::shared_ptr<ssl_socket> socket)
@ -168,7 +168,7 @@ namespace client
if (ecode) { if (ecode) {
LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ()); LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ());
return; return;
} }
//std::this_thread::sleep_for (std::chrono::milliseconds(5)); //std::this_thread::sleep_for (std::chrono::milliseconds(5));
ReadRequest (socket); ReadRequest (socket);
} }
@ -187,15 +187,15 @@ namespace client
} }
void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode, void I2PControlService::HandleRequestReceived (const boost::system::error_code& ecode,
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket, size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
std::shared_ptr<I2PControlBuffer> buf) std::shared_ptr<I2PControlBuffer> buf)
{ {
if (ecode) if (ecode)
{ {
LogPrint (eLogError, "I2PControl: read error: ", ecode.message ()); LogPrint (eLogError, "I2PControl: read error: ", ecode.message ());
return; return;
} }
else else
{ {
bool isHtml = !memcmp (buf->data (), "POST", 4); bool isHtml = !memcmp (buf->data (), "POST", 4);
try try
@ -243,8 +243,8 @@ namespace client
response << "{\"id\":" << id << ",\"result\":{"; response << "{\"id\":" << id << ",\"result\":{";
(this->*(it->second))(pt.get_child ("params"), response); (this->*(it->second))(pt.get_child ("params"), response);
response << "},\"jsonrpc\":\"2.0\"}"; response << "},\"jsonrpc\":\"2.0\"}";
} }
else else
{ {
LogPrint (eLogWarning, "I2PControl: unknown method ", method); LogPrint (eLogWarning, "I2PControl: unknown method ", method);
response << "{\"id\":null,\"error\":"; response << "{\"id\":null,\"error\":";
@ -337,9 +337,9 @@ namespace client
InsertParam (results, "API", api); InsertParam (results, "API", api);
results << ","; results << ",";
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ()); std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
m_Tokens.insert (token); m_Tokens.insert (token);
InsertParam (results, "Token", token); InsertParam (results, "Token", token);
} }
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results) void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
{ {
@ -364,7 +364,7 @@ namespace client
} }
else else
LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first); LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first);
} }
} }
void I2PControlService::PasswordHandler (const std::string& value) void I2PControlService::PasswordHandler (const std::string& value)
@ -394,28 +394,28 @@ namespace client
void I2PControlService::UptimeHandler (std::ostringstream& results) void I2PControlService::UptimeHandler (std::ostringstream& results)
{ {
InsertParam (results, "i2p.router.uptime", (int)i2p::context.GetUptime ()*1000); InsertParam (results, "i2p.router.uptime", (int)i2p::context.GetUptime ()*1000);
} }
void I2PControlService::VersionHandler (std::ostringstream& results) void I2PControlService::VersionHandler (std::ostringstream& results)
{ {
InsertParam (results, "i2p.router.version", VERSION); InsertParam (results, "i2p.router.version", VERSION);
} }
void I2PControlService::StatusHandler (std::ostringstream& results) void I2PControlService::StatusHandler (std::ostringstream& results)
{ {
auto dest = i2p::client::context.GetSharedLocalDestination (); auto dest = i2p::client::context.GetSharedLocalDestination ();
InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0"); InsertParam (results, "i2p.router.status", (dest && dest->IsReady ()) ? "1" : "0");
} }
void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results) void I2PControlService::NetDbKnownPeersHandler (std::ostringstream& results)
{ {
InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ()); InsertParam (results, "i2p.router.netdb.knownpeers", i2p::data::netdb.GetNumRouters ());
} }
void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results) void I2PControlService::NetDbActivePeersHandler (std::ostringstream& results)
{ {
InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ()); InsertParam (results, "i2p.router.netdb.activepeers", (int)i2p::transport::transports.GetPeers ().size ());
} }
void I2PControlService::NetStatusHandler (std::ostringstream& results) void I2PControlService::NetStatusHandler (std::ostringstream& results)
@ -463,11 +463,11 @@ namespace client
{ {
for (auto it = params.begin (); it != params.end (); it++) for (auto it = params.begin (); it != params.end (); it++)
{ {
if (it != params.begin ()) results << ","; if (it != params.begin ()) results << ",";
LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first); LogPrint (eLogDebug, "I2PControl: RouterManager request: ", it->first);
auto it1 = m_RouterManagerHandlers.find (it->first); auto it1 = m_RouterManagerHandlers.find (it->first);
if (it1 != m_RouterManagerHandlers.end ()) { if (it1 != m_RouterManagerHandlers.end ()) {
(this->*(it1->second))(results); (this->*(it1->second))(results);
} else } else
LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first); LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first);
} }
@ -516,7 +516,7 @@ namespace client
auto it1 = m_NetworkSettingHandlers.find (it->first); auto it1 = m_NetworkSettingHandlers.find (it->first);
if (it1 != m_NetworkSettingHandlers.end ()) { if (it1 != m_NetworkSettingHandlers.end ()) {
if (it != params.begin ()) results << ","; if (it != params.begin ()) results << ",";
(this->*(it1->second))(it->second.data (), results); (this->*(it1->second))(it->second.data (), results);
} else } else
LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first); LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
} }
@ -538,7 +538,7 @@ namespace client
InsertParam (results, "i2p.router.net.bw.out", bw); InsertParam (results, "i2p.router.net.bw.out", bw);
} }
// certificate // certificate
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path) void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
{ {
FILE *f = NULL; FILE *f = NULL;

View file

@ -10,7 +10,7 @@
#include <map> #include <map>
#include <set> #include <set>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>
namespace i2p namespace i2p

View file

@ -42,13 +42,13 @@ namespace transport
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address); std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
private: private:
bool m_IsRunning; bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread; std::unique_ptr<std::thread> m_Thread;
std::condition_variable m_Started; std::condition_variable m_Started;
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;
struct UPNPUrls m_upnpUrls; struct UPNPUrls m_upnpUrls;
struct IGDdatas m_upnpData; struct IGDdatas m_upnpData;

View file

@ -163,7 +163,7 @@ namespace i2p
sigaction(SIGABRT, &sa, 0); sigaction(SIGABRT, &sa, 0);
sigaction(SIGTERM, &sa, 0); sigaction(SIGTERM, &sa, 0);
sigaction(SIGINT, &sa, 0); sigaction(SIGINT, &sa, 0);
sigaction(SIGPIPE, &sa, 0); sigaction(SIGPIPE, &sa, 0);
return Daemon_Singleton::start(); return Daemon_Singleton::start();
} }

4
debian/changelog vendored
View file

@ -62,7 +62,7 @@ i2pd (2.10.0-1) unstable; urgency=low
* updated to version 2.10.0/0.9.27 * updated to version 2.10.0/0.9.27
* reseed.verify set to true by default * reseed.verify set to true by default
-- orignal <orignal@i2pmail.org> Sun, 16 Oct 2016 13:55:40 +0000 -- orignal <orignal@i2pmail.org> Sun, 16 Oct 2016 13:55:40 +0000
i2pd (2.9.0-1) unstable; urgency=low i2pd (2.9.0-1) unstable; urgency=low
@ -73,7 +73,7 @@ i2pd (2.9.0-1) unstable; urgency=low
* removed all port assigments in services files * removed all port assigments in services files
* fixed logrotate * fixed logrotate
* subscriptions.txt and tunnels.conf taken from docs folder * subscriptions.txt and tunnels.conf taken from docs folder
-- orignal <orignal@i2pmail.org> Fri, 12 Aug 2016 14:25:40 +0000 -- orignal <orignal@i2pmail.org> Fri, 12 Aug 2016 14:25:40 +0000
i2pd (2.7.0-1) unstable; urgency=low i2pd (2.7.0-1) unstable; urgency=low

2
debian/i2pd.default vendored
View file

@ -7,5 +7,5 @@ I2PD_ENABLED="yes"
# see possible switches in /usr/share/doc/i2pd/configuration.md.gz # see possible switches in /usr/share/doc/i2pd/configuration.md.gz
DAEMON_OPTS="" DAEMON_OPTS=""
# If you have problems with hunging i2pd, you can try enable this # If you have problems with hunging i2pd, you can try enable this
ulimit -n 4096 ulimit -n 4096

View file

@ -1,12 +1,11 @@
diff --git a/Makefile b/Makefile diff --git a/Makefile b/Makefile
index bdadfe0..2f71eec 100644 index bdadfe0..2f71eec 100644
--- a/Makefile --- a/Makefile
+++ b/Makefile +++ b/Makefile
@@ -9,10 +9,10 @@ DEPS := obj/make.dep @@ -9,10 +9,10 @@ DEPS := obj/make.dep
include filelist.mk include filelist.mk
-USE_AESNI := yes -USE_AESNI := yes
+USE_AESNI := no +USE_AESNI := no
-USE_AVX := yes -USE_AVX := yes

View file

@ -43,8 +43,8 @@ namespace data
const char * GetBase64SubstitutionTable () const char * GetBase64SubstitutionTable ()
{ {
return T64; return T64;
} }
/* /*
* Reverse Substitution Table (built in run time) * Reverse Substitution Table (built in run time)
*/ */
@ -53,10 +53,10 @@ namespace data
static int isFirstTime = 1; static int isFirstTime = 1;
/* /*
* Padding * Padding
*/ */
static char P64 = '='; static char P64 = '=';
/* /*
* *
@ -68,11 +68,11 @@ namespace data
*/ */
size_t /* Number of bytes in the encoded buffer */ size_t /* Number of bytes in the encoded buffer */
ByteStreamToBase64 ( 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 */
) )
{ {
@ -80,9 +80,9 @@ namespace data
unsigned char * pd; unsigned char * pd;
unsigned char acc_1; unsigned char acc_1;
unsigned char acc_2; unsigned char acc_2;
int i; int i;
int n; int n;
int m; int m;
size_t outCount; size_t outCount;
ps = (unsigned char *)InBuffer; ps = (unsigned char *)InBuffer;
@ -96,7 +96,7 @@ namespace data
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++;
@ -109,7 +109,7 @@ namespace data
*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 */
@ -122,7 +122,7 @@ namespace data
} }
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++;
@ -133,7 +133,7 @@ namespace data
*pd++ = T64[acc_1]; *pd++ = T64[acc_1];
*pd++ = P64; *pd++ = P64;
} }
return outCount; return outCount;
} }
@ -148,10 +148,10 @@ namespace data
*/ */
size_t /* Number of output bytes */ size_t /* Number of output bytes */
Base64ToByteStream ( 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 */
size_t len /* length of output buffer */ size_t len /* length of output buffer */
) )
{ {
@ -159,28 +159,28 @@ namespace data
unsigned char * pd; unsigned char * pd;
unsigned char acc_1; unsigned char acc_1;
unsigned char acc_2; unsigned char acc_2;
int i; int i;
int n; int n;
int m; int m;
size_t outCount; size_t outCount;
if (isFirstTime) iT64Build(); if (isFirstTime) iT64Build();
n = InCount/4; n = InCount/4;
m = 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++];
@ -193,7 +193,7 @@ namespace data
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;
@ -203,13 +203,13 @@ namespace data
return outCount; return outCount;
} }
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) d.quot++;
return 4*d.quot; return 4*d.quot;
} }
/* /*
* *
* iT64 * iT64
@ -228,20 +228,20 @@ namespace data
iT64[(int)P64] = 0; iT64[(int)P64] = 0;
} }
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen) size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen)
{ {
int tmp = 0, bits = 0; int tmp = 0, bits = 0;
size_t ret = 0; size_t ret = 0;
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
{ {
char ch = inBuf[i]; char ch = inBuf[i];
if (ch >= '2' && ch <= '7') // digit if (ch >= '2' && ch <= '7') // digit
ch = (ch - '2') + 26; // 26 means a-z ch = (ch - '2') + 26; // 26 means a-z
else if (ch >= 'a' && ch <= 'z') else if (ch >= 'a' && ch <= 'z')
ch = ch - 'a'; // a = 0 ch = ch - 'a'; // a = 0
else else
return 0; // unexpected character return 0; // unexpected character
tmp |= ch; tmp |= ch;
bits += 5; bits += 5;
if (bits >= 8) if (bits >= 8)
@ -261,23 +261,23 @@ namespace data
size_t ret = 0, pos = 1; size_t ret = 0, pos = 1;
int bits = 8, tmp = inBuf[0]; int bits = 8, tmp = inBuf[0];
while (ret < outLen && (bits > 0 || pos < len)) while (ret < outLen && (bits > 0 || pos < len))
{ {
if (bits < 5) if (bits < 5)
{ {
if (pos < len) if (pos < len)
{ {
tmp <<= 8; tmp <<= 8;
tmp |= inBuf[pos] & 0xFF; tmp |= inBuf[pos] & 0xFF;
pos++; pos++;
bits += 8; bits += 8;
} }
else // last byte else // last byte
{ {
tmp <<= (5 - bits); tmp <<= (5 - bits);
bits = 5; bits = 5;
} }
} }
bits -= 5; bits -= 5;
int ind = (tmp >> bits) & 0x1F; int ind = (tmp >> bits) & 0x1F;
outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2'); outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2');

View file

@ -10,8 +10,8 @@ namespace data {
size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len); size_t ByteStreamToBase64 (const uint8_t * InBuffer, size_t InCount, char * OutBuffer, size_t len);
size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len ); size_t Base64ToByteStream (const char * InBuffer, size_t InCount, uint8_t * OutBuffer, size_t len );
const char * GetBase32SubstitutionTable (); const char * GetBase32SubstitutionTable ();
const char * GetBase64SubstitutionTable (); const char * GetBase64SubstitutionTable ();
size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen); size_t Base32ToByteStream (const char * inBuf, size_t len, uint8_t * outBuf, size_t outLen);
size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen); size_t ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);

View file

@ -79,10 +79,10 @@ namespace config {
} }
template<typename T> template<typename T>
bool GetOption(const std::string& name, T& value) bool GetOption(const std::string& name, T& value)
{ {
return GetOption (name.c_str (), value); return GetOption (name.c_str (), value);
} }
bool GetOptionAsAny(const char *name, boost::any& value); bool GetOptionAsAny(const char *name, boost::any& value);
bool GetOptionAsAny(const std::string& name, boost::any& value); bool GetOptionAsAny(const std::string& name, boost::any& value);

View file

@ -22,7 +22,7 @@ namespace crypto
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,

View file

@ -24,7 +24,7 @@ namespace crypto
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len); bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
// DSA // DSA
DSA * CreateDSA (); DSA * CreateDSA ();
// RSA // RSA
const BIGNUM * GetRSAE (); const BIGNUM * GetRSAE ();
@ -33,20 +33,20 @@ namespace crypto
class DHKeys class DHKeys
{ {
public: public:
DHKeys (); DHKeys ();
~DHKeys (); ~DHKeys ();
void GenerateKeys (); void GenerateKeys ();
const uint8_t * GetPublicKey () const { return m_PublicKey; }; const uint8_t * GetPublicKey () const { return m_PublicKey; };
void Agree (const uint8_t * pub, uint8_t * shared); void Agree (const uint8_t * pub, uint8_t * shared);
private: private:
DH * m_DH; DH * m_DH;
uint8_t m_PublicKey[256]; uint8_t m_PublicKey[256];
}; };
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false); void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding = false);
bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false); bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, bool zeroPadding = false);
@ -54,15 +54,15 @@ namespace crypto
// ECIES // ECIES
void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); // 222 bytes data, 514 bytes encrypted void ECIESEncrypt (const EC_GROUP * curve, const EC_POINT * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); // 222 bytes data, 514 bytes encrypted
bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); bool ECIESDecrypt (const EC_GROUP * curve, const BIGNUM * key, const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub); void GenerateECIESKeyPair (const EC_GROUP * curve, BIGNUM *& priv, EC_POINT *& pub);
// HMAC // HMAC
typedef i2p::data::Tag<32> MACKey; typedef i2p::data::Tag<32> MACKey;
void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest); void HMACMD5Digest (uint8_t * msg, size_t len, const MACKey& key, uint8_t * digest);
// AES // AES
struct ChipherBlock struct ChipherBlock
{ {
uint8_t buf[16]; uint8_t buf[16];
@ -71,40 +71,40 @@ namespace crypto
#if defined(__AVX__) // AVX #if defined(__AVX__) // AVX
__asm__ __asm__
( (
"vmovups (%[buf]), %%xmm0 \n" "vmovups (%[buf]), %%xmm0 \n"
"vmovups (%[other]), %%xmm1 \n" "vmovups (%[other]), %%xmm1 \n"
"vxorps %%xmm0, %%xmm1, %%xmm0 \n" "vxorps %%xmm0, %%xmm1, %%xmm0 \n"
"vmovups %%xmm0, (%[buf]) \n" "vmovups %%xmm0, (%[buf]) \n"
: :
: [buf]"r"(buf), [other]"r"(other.buf) : [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
#elif defined(__SSE__) // SSE #elif defined(__SSE__) // SSE
__asm__ __asm__
( (
"movups (%[buf]), %%xmm0 \n" "movups (%[buf]), %%xmm0 \n"
"movups (%[other]), %%xmm1 \n" "movups (%[other]), %%xmm1 \n"
"pxor %%xmm1, %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[buf]) \n" "movups %%xmm0, (%[buf]) \n"
: :
: [buf]"r"(buf), [other]"r"(other.buf) : [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory" : "%xmm0", "%xmm1", "memory"
); );
#else #else
// TODO: implement it better // TODO: implement it better
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
buf[i] ^= other.buf[i]; buf[i] ^= other.buf[i];
#endif #endif
} }
}; };
typedef i2p::data::Tag<32> AESKey; typedef i2p::data::Tag<32> AESKey;
template<size_t sz> template<size_t sz>
class AESAlignedBuffer // 16 bytes alignment class AESAlignedBuffer // 16 bytes alignment
{ {
public: public:
AESAlignedBuffer () AESAlignedBuffer ()
{ {
m_Buf = m_UnalignedBuffer; m_Buf = m_UnalignedBuffer;
@ -112,22 +112,22 @@ namespace crypto
if (rem) if (rem)
m_Buf += (16 - rem); m_Buf += (16 - rem);
} }
operator uint8_t * () { return m_Buf; }; operator uint8_t * () { return m_Buf; };
operator const uint8_t * () const { return m_Buf; }; operator const uint8_t * () const { return m_Buf; };
ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; }; ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; };
const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; }; const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; };
private: private:
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
uint8_t * m_Buf; uint8_t * m_Buf;
}; };
#ifdef AESNI #ifdef AESNI
class ECBCryptoAESNI class ECBCryptoAESNI
{ {
public: public:
uint8_t * GetKeySchedule () { return m_KeySchedule; }; uint8_t * GetKeySchedule () { return m_KeySchedule; };
@ -135,27 +135,27 @@ namespace crypto
protected: protected:
void ExpandKey (const AESKey& key); void ExpandKey (const AESKey& key);
private: private:
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
}; };
class ECBEncryptionAESNI: public ECBCryptoAESNI class ECBEncryptionAESNI: public ECBCryptoAESNI
{ {
public: public:
void SetKey (const AESKey& key) { ExpandKey (key); }; void SetKey (const AESKey& key) { ExpandKey (key); };
void Encrypt (const ChipherBlock * in, ChipherBlock * out); void Encrypt (const ChipherBlock * in, ChipherBlock * out);
}; };
class ECBDecryptionAESNI: public ECBCryptoAESNI class ECBDecryptionAESNI: public ECBCryptoAESNI
{ {
public: public:
void SetKey (const AESKey& key); void SetKey (const AESKey& key);
void Decrypt (const ChipherBlock * in, ChipherBlock * out); void Decrypt (const ChipherBlock * in, ChipherBlock * out);
}; };
typedef ECBEncryptionAESNI ECBEncryption; typedef ECBEncryptionAESNI ECBEncryption;
typedef ECBDecryptionAESNI ECBDecryption; typedef ECBDecryptionAESNI ECBDecryption;
@ -165,46 +165,46 @@ namespace crypto
class ECBEncryption class ECBEncryption
{ {
public: public:
void SetKey (const AESKey& key) void SetKey (const AESKey& key)
{ {
AES_set_encrypt_key (key, 256, &m_Key); AES_set_encrypt_key (key, 256, &m_Key);
} }
void Encrypt (const ChipherBlock * in, ChipherBlock * out) void Encrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
AES_encrypt (in->buf, out->buf, &m_Key); AES_encrypt (in->buf, out->buf, &m_Key);
} }
private: private:
AES_KEY m_Key; AES_KEY m_Key;
}; };
class ECBDecryption class ECBDecryption
{ {
public: public:
void SetKey (const AESKey& key) void SetKey (const AESKey& key)
{ {
AES_set_decrypt_key (key, 256, &m_Key); AES_set_decrypt_key (key, 256, &m_Key);
} }
void Decrypt (const ChipherBlock * in, ChipherBlock * out) void Decrypt (const ChipherBlock * in, ChipherBlock * out)
{ {
AES_decrypt (in->buf, out->buf, &m_Key); AES_decrypt (in->buf, out->buf, &m_Key);
} }
private: private:
AES_KEY m_Key; AES_KEY m_Key;
}; };
#endif #endif
class CBCEncryption class CBCEncryption
{ {
public: public:
CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); }; CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); };
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
@ -217,14 +217,14 @@ namespace crypto
private: private:
AESAlignedBuffer<16> m_LastBlock; AESAlignedBuffer<16> m_LastBlock;
ECBEncryption m_ECBEncryption; ECBEncryption m_ECBEncryption;
}; };
class CBCDecryption class CBCDecryption
{ {
public: public:
CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); }; CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); };
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
@ -238,7 +238,7 @@ namespace crypto
AESAlignedBuffer<16> m_IV; AESAlignedBuffer<16> m_IV;
ECBDecryption m_ECBDecryption; ECBDecryption m_ECBDecryption;
}; };
class TunnelEncryption // with double IV encryption class TunnelEncryption // with double IV encryption
{ {
@ -248,9 +248,9 @@ namespace crypto
{ {
m_LayerEncryption.SetKey (layerKey); m_LayerEncryption.SetKey (layerKey);
m_IVEncryption.SetKey (ivKey); m_IVEncryption.SetKey (ivKey);
} }
void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data) void Encrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
private: private:
@ -270,9 +270,9 @@ namespace crypto
{ {
m_LayerDecryption.SetKey (layerKey); m_LayerDecryption.SetKey (layerKey);
m_IVDecryption.SetKey (ivKey); m_IVDecryption.SetKey (ivKey);
} }
void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data) void Decrypt (const uint8_t * in, uint8_t * out); // 1024 bytes (16 IV + 1008 data)
private: private:
@ -282,72 +282,72 @@ namespace crypto
#else #else
CBCDecryption m_LayerDecryption; CBCDecryption m_LayerDecryption;
#endif #endif
}; };
void InitCrypto (bool precomputation); void InitCrypto (bool precomputation);
void TerminateCrypto (); void TerminateCrypto ();
} }
} }
// take care about openssl version // take care about openssl version
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL #if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL
// define getters and setters introduced in 1.1.0 // define getters and setters introduced in 1.1.0
inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{ {
if (d->p) BN_free (d->p); if (d->p) BN_free (d->p);
if (d->q) BN_free (d->q); if (d->q) BN_free (d->q);
if (d->g) BN_free (d->g); if (d->g) BN_free (d->g);
d->p = p; d->q = q; d->g = g; return 1; d->p = p; d->q = q; d->g = g; return 1;
} }
inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) inline int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
{ {
if (d->pub_key) BN_free (d->pub_key); if (d->pub_key) BN_free (d->pub_key);
if (d->priv_key) BN_free (d->priv_key); if (d->priv_key) BN_free (d->priv_key);
d->pub_key = pub_key; d->priv_key = priv_key; return 1; d->pub_key = pub_key; d->priv_key = priv_key; return 1;
} }
inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key) inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = d->pub_key; *priv_key = d->priv_key; } { *pub_key = d->pub_key; *priv_key = d->priv_key; }
inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) inline int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{ {
if (sig->r) BN_free (sig->r); if (sig->r) BN_free (sig->r);
if (sig->s) BN_free (sig->s); if (sig->s) BN_free (sig->s);
sig->r = r; sig->s = s; return 1; sig->r = r; sig->s = s; return 1;
} }
inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) inline void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; } { *pr = sig->r; *ps = sig->s; }
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
{ {
if (sig->r) BN_free (sig->r); if (sig->r) BN_free (sig->r);
if (sig->s) BN_free (sig->s); if (sig->s) BN_free (sig->s);
sig->r = r; sig->s = s; return 1; sig->r = r; sig->s = s; return 1;
} }
inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) inline void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps)
{ *pr = sig->r; *ps = sig->s; } { *pr = sig->r; *ps = sig->s; }
inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
{ {
if (r->n) BN_free (r->n); if (r->n) BN_free (r->n);
if (r->e) BN_free (r->e); if (r->e) BN_free (r->e);
if (r->d) BN_free (r->d); if (r->d) BN_free (r->d);
r->n = n; r->e = e; r->d = d; return 1; r->n = n; r->e = e; r->d = d; return 1;
} }
inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
{ *n = r->n; *e = r->e; *d = r->d; } { *n = r->n; *e = r->e; *d = r->d; }
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{ {
if (dh->p) BN_free (dh->p); if (dh->p) BN_free (dh->p);
if (dh->q) BN_free (dh->q); if (dh->q) BN_free (dh->q);
if (dh->g) BN_free (dh->g); if (dh->g) BN_free (dh->g);
dh->p = p; dh->q = q; dh->g = g; return 1; dh->p = p; dh->q = q; dh->g = g; return 1;
} }
inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
{ {
if (dh->pub_key) BN_free (dh->pub_key); if (dh->pub_key) BN_free (dh->pub_key);
if (dh->priv_key) BN_free (dh->priv_key); if (dh->priv_key) BN_free (dh->priv_key);
dh->pub_key = pub_key; dh->priv_key = priv_key; return 1; dh->pub_key = pub_key; dh->priv_key = priv_key; return 1;
} }
inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
{ *pub_key = dh->pub_key; *priv_key = dh->priv_key; } { *pub_key = dh->pub_key; *priv_key = dh->priv_key; }

View file

@ -72,7 +72,7 @@ namespace crypto
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub) void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub)
{ {
EC_GROUP * curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1); EC_GROUP * curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1);
EC_POINT * p = nullptr; EC_POINT * p = nullptr;
BIGNUM * key = nullptr; BIGNUM * key = nullptr;
GenerateECIESKeyPair (curve, key, p); GenerateECIESKeyPair (curve, key, p);
bn2buf (key, priv, 32); bn2buf (key, priv, 32);
@ -81,11 +81,11 @@ namespace crypto
BIGNUM * x = BN_new (), * y = BN_new (); BIGNUM * x = BN_new (), * y = BN_new ();
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL); EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL);
bn2buf (x, pub, 32); bn2buf (x, pub, 32);
bn2buf (y, pub + 32, 32); bn2buf (y, pub + 32, 32);
RAND_bytes (pub + 64, 192); RAND_bytes (pub + 64, 192);
EC_POINT_free (p); EC_POINT_free (p);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
EC_GROUP_free (curve); EC_GROUP_free (curve);
} }
ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub) ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub)
@ -131,7 +131,7 @@ namespace crypto
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub) void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub)
{ {
auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA); auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA);
EC_POINT * p = nullptr; EC_POINT * p = nullptr;
BIGNUM * key = nullptr; BIGNUM * key = nullptr;
GenerateECIESKeyPair (curve->GetGroup (), key, p); GenerateECIESKeyPair (curve->GetGroup (), key, p);
bn2buf (key, priv, 32); bn2buf (key, priv, 32);
@ -140,9 +140,9 @@ namespace crypto
BIGNUM * x = BN_new (), * y = BN_new (); BIGNUM * x = BN_new (), * y = BN_new ();
EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL); EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL);
bn2buf (x, pub, 32); bn2buf (x, pub, 32);
bn2buf (y, pub + 32, 32); bn2buf (y, pub + 32, 32);
RAND_bytes (pub + 64, 192); RAND_bytes (pub + 64, 192);
EC_POINT_free (p); EC_POINT_free (p);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }

View file

@ -8,15 +8,15 @@ namespace i2p
{ {
namespace crypto namespace crypto
{ {
class CryptoKeyEncryptor class CryptoKeyEncryptor
{ {
public: public:
virtual ~CryptoKeyEncryptor () {}; virtual ~CryptoKeyEncryptor () {};
virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) = 0; // 222 bytes data, 512 bytes encrypted virtual void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) = 0; // 222 bytes data, 512 bytes encrypted
}; };
class CryptoKeyDecryptor class CryptoKeyDecryptor
{ {
public: public:
@ -30,7 +30,7 @@ namespace crypto
public: public:
ElGamalEncryptor (const uint8_t * pub); ElGamalEncryptor (const uint8_t * pub);
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
private: private:
@ -42,7 +42,7 @@ namespace crypto
public: public:
ElGamalDecryptor (const uint8_t * priv); ElGamalDecryptor (const uint8_t * priv);
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
private: private:
@ -51,13 +51,13 @@ namespace crypto
// ECIES P256 // ECIES P256
class ECIESP256Encryptor: public CryptoKeyEncryptor class ECIESP256Encryptor: public CryptoKeyEncryptor
{ {
public: public:
ECIESP256Encryptor (const uint8_t * pub); ECIESP256Encryptor (const uint8_t * pub);
~ECIESP256Encryptor (); ~ECIESP256Encryptor ();
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
private: private:
@ -72,7 +72,7 @@ namespace crypto
ECIESP256Decryptor (const uint8_t * priv); ECIESP256Decryptor (const uint8_t * priv);
~ECIESP256Decryptor (); ~ECIESP256Decryptor ();
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
private: private:
@ -80,17 +80,17 @@ namespace crypto
BIGNUM * m_PrivateKey; BIGNUM * m_PrivateKey;
}; };
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub); void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub);
// ECIES GOST R 34.10 // ECIES GOST R 34.10
class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor
{ {
public: public:
ECIESGOSTR3410Encryptor (const uint8_t * pub); ECIESGOSTR3410Encryptor (const uint8_t * pub);
~ECIESGOSTR3410Encryptor (); ~ECIESGOSTR3410Encryptor ();
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx); void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx);
private: private:
@ -104,7 +104,7 @@ namespace crypto
ECIESGOSTR3410Decryptor (const uint8_t * priv); ECIESGOSTR3410Decryptor (const uint8_t * priv);
~ECIESGOSTR3410Decryptor (); ~ECIESGOSTR3410Decryptor ();
bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx);
private: private:

View file

@ -11,20 +11,20 @@ namespace i2p
{ {
namespace datagram namespace datagram
{ {
DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner): DatagramDestination::DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner):
m_Owner (owner.get()), m_Owner (owner.get()),
m_Receiver (nullptr) m_Receiver (nullptr)
{ {
m_Identity.FromBase64 (owner->GetIdentity()->ToBase64()); m_Identity.FromBase64 (owner->GetIdentity()->ToBase64());
} }
DatagramDestination::~DatagramDestination () DatagramDestination::~DatagramDestination ()
{ {
m_Sessions.clear(); m_Sessions.clear();
} }
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; auto owner = m_Owner;
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE); std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
uint8_t * buf = v.data(); uint8_t * buf = v.data();
@ -33,11 +33,11 @@ namespace datagram
auto signatureLen = m_Identity.GetSignatureLen (); auto signatureLen = m_Identity.GetSignatureLen ();
uint8_t * buf1 = signature + signatureLen; uint8_t * buf1 = signature + signatureLen;
size_t headerLen = identityLen + signatureLen; size_t headerLen = identityLen + signatureLen;
memcpy (buf1, payload, len); memcpy (buf1, payload, len);
if (m_Identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) if (m_Identity.GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1)
{ {
uint8_t hash[32]; uint8_t hash[32];
SHA256(buf1, len, hash); SHA256(buf1, len, hash);
owner->Sign (hash, 32, signature); owner->Sign (hash, 32, signature);
} }
@ -63,10 +63,10 @@ namespace datagram
uint8_t hash[32]; uint8_t hash[32];
SHA256(buf + headerLen, len - headerLen, hash); SHA256(buf + headerLen, len - headerLen, hash);
verified = identity.Verify (hash, 32, signature); verified = identity.Verify (hash, 32, signature);
} }
else else
verified = identity.Verify (buf + headerLen, len - headerLen, signature); verified = identity.Verify (buf + headerLen, len - headerLen, signature);
if (verified) if (verified)
{ {
auto h = identity.GetIdentHash(); auto h = identity.GetIdentHash();
@ -79,7 +79,7 @@ namespace datagram
LogPrint (eLogWarning, "DatagramDestination: no receiver for port ", toPort); LogPrint (eLogWarning, "DatagramDestination: no receiver for port ", toPort);
} }
else else
LogPrint (eLogWarning, "Datagram signature verification failed"); LogPrint (eLogWarning, "Datagram signature verification failed");
} }
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port) DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
@ -113,24 +113,24 @@ namespace datagram
{ {
htobe32buf (msg->GetPayload (), size); // length htobe32buf (msg->GetPayload (), size); // length
htobe16buf (buf + 4, fromPort); // source port htobe16buf (buf + 4, fromPort); // source port
htobe16buf (buf + 6, toPort); // destination port htobe16buf (buf + 6, toPort); // destination port
buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol buf[9] = i2p::client::PROTOCOL_TYPE_DATAGRAM; // datagram protocol
msg->len += size + 4; msg->len += size + 4;
msg->FillI2NPMessageHeader (eI2NPData); msg->FillI2NPMessageHeader (eI2NPData);
} }
else else
msg = nullptr; msg = nullptr;
return msg; return msg;
} }
void DatagramDestination::CleanUp () void DatagramDestination::CleanUp ()
{ {
if (m_Sessions.empty ()) return; if (m_Sessions.empty ()) return;
auto now = i2p::util::GetMillisecondsSinceEpoch(); auto now = i2p::util::GetMillisecondsSinceEpoch();
LogPrint(eLogDebug, "DatagramDestination: clean up sessions"); LogPrint(eLogDebug, "DatagramDestination: clean up sessions");
std::unique_lock<std::mutex> lock(m_SessionsMutex); std::unique_lock<std::mutex> lock(m_SessionsMutex);
// for each session ... // for each session ...
for (auto it = m_Sessions.begin (); it != m_Sessions.end (); ) for (auto it = m_Sessions.begin (); it != m_Sessions.end (); )
{ {
// check if expired // check if expired
if (now - it->second->LastActivity() >= DATAGRAM_SESSION_MAX_IDLE) if (now - it->second->LastActivity() >= DATAGRAM_SESSION_MAX_IDLE)
@ -143,7 +143,7 @@ namespace datagram
it++; it++;
} }
} }
std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & identity) std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & identity)
{ {
std::shared_ptr<DatagramSession> session = nullptr; std::shared_ptr<DatagramSession> session = nullptr;
@ -169,7 +169,7 @@ namespace datagram
} }
return nullptr; return nullptr;
} }
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination, DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
const i2p::data::IdentHash & remoteIdent) : const i2p::data::IdentHash & remoteIdent) :
m_LocalDestination(localDestination), m_LocalDestination(localDestination),
@ -203,7 +203,7 @@ namespace datagram
{ {
if(!m_RoutingSession) if(!m_RoutingSession)
return DatagramSession::Info(nullptr, nullptr, m_LastUse); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
auto routingPath = m_RoutingSession->GetSharedRoutingPath(); auto routingPath = m_RoutingSession->GetSharedRoutingPath();
if (!routingPath) if (!routingPath)
return DatagramSession::Info(nullptr, nullptr, m_LastUse); return DatagramSession::Info(nullptr, nullptr, m_LastUse);
@ -318,7 +318,7 @@ namespace datagram
m_RoutingSession->SetSharedRoutingPath(path); m_RoutingSession->SetSharedRoutingPath(path);
} }
return path; return path;
} }
void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls) void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls)

View file

@ -106,7 +106,7 @@ namespace datagram
DatagramDestination (std::shared_ptr<i2p::client::ClientDestination> owner); 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);
void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleDataMessagePayload (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; }; void SetReceiver (const Receiver& receiver) { m_Receiver = receiver; };

View file

@ -24,9 +24,9 @@ namespace client
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY; int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
int numTags = DEFAULT_TAGS_TO_SEND; int numTags = DEFAULT_TAGS_TO_SEND;
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers; std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
try try
{ {
if (params) if (params)
{ {
auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH); auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
if (it != params->end ()) if (it != params->end ())
@ -59,16 +59,16 @@ namespace client
} }
} }
it = params->find (I2CP_PARAM_INBOUND_NICKNAME); it = params->find (I2CP_PARAM_INBOUND_NICKNAME);
if (it != params->end ()) m_Nickname = it->second; if (it != params->end ()) m_Nickname = it->second;
else // try outbound else // try outbound
{ {
it = params->find (I2CP_PARAM_OUTBOUND_NICKNAME); it = params->find (I2CP_PARAM_OUTBOUND_NICKNAME);
if (it != params->end ()) m_Nickname = it->second; if (it != params->end ()) m_Nickname = it->second;
// otherwise we set deafult nickname in Start when we know local address // otherwise we set deafult nickname in Start when we know local address
} }
} }
} }
catch (std::exception & ex) catch (std::exception & ex)
{ {
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what()); LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what());
} }
@ -492,7 +492,7 @@ namespace client
m_PublishReplyToken = 0; m_PublishReplyToken = 0;
if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) if (GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL)
{ {
LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again"); LogPrint (eLogWarning, "Destination: Publish confirmation was not received in ", PUBLISH_CONFIRMATION_TIMEOUT, " seconds, will try again");
Publish (); Publish ();
} }
else else
@ -503,7 +503,7 @@ namespace client
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT)); m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer, m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
} }
} }
@ -728,14 +728,14 @@ namespace client
if (isPublic) if (isPublic)
PersistTemporaryKeys (); PersistTemporaryKeys ();
else else
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (), i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
m_EncryptionPrivateKey, m_EncryptionPublicKey); m_EncryptionPrivateKey, m_EncryptionPublicKey);
m_Decryptor = m_Keys.CreateDecryptor (m_EncryptionPrivateKey); m_Decryptor = m_Keys.CreateDecryptor (m_EncryptionPrivateKey);
if (isPublic) if (isPublic)
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created"); LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
// extract streaming params // extract streaming params
if (params) if (params)
{ {
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY); auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
if (it != params->end ()) if (it != params->end ())
@ -780,7 +780,7 @@ namespace client
delete m_DatagramDestination; delete m_DatagramDestination;
m_DatagramDestination = nullptr; m_DatagramDestination = nullptr;
} }
return true; return true;
} }
else else
return false; return false;
@ -956,7 +956,7 @@ namespace client
} }
LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p"); LogPrint (eLogInfo, "Destination: Creating new temporary keys for address ", ident, ".b32.i2p");
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (), i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
m_EncryptionPrivateKey, m_EncryptionPublicKey); m_EncryptionPrivateKey, m_EncryptionPublicKey);
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out); std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);

View file

@ -190,9 +190,9 @@ namespace client
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
// ref counter // ref counter
int Acquire () { return ++m_RefCounter; }; int Acquire () { return ++m_RefCounter; };
int Release () { return --m_RefCounter; }; int Release () { return --m_RefCounter; };
int GetRefCounter () const { return m_RefCounter; }; int GetRefCounter () const { return m_RefCounter; };
// streaming // streaming
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
@ -239,7 +239,7 @@ namespace client
int m_StreamingAckDelay; int m_StreamingAckDelay;
std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default std::shared_ptr<i2p::stream::StreamingDestination> m_StreamingDestination; // default
std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts; std::map<uint16_t, std::shared_ptr<i2p::stream::StreamingDestination> > m_StreamingDestinationsByPorts;
i2p::datagram::DatagramDestination * m_DatagramDestination; i2p::datagram::DatagramDestination * m_DatagramDestination;
int m_RefCounter; // how many clients(tunnels) use this destination int m_RefCounter; // how many clients(tunnels) use this destination
boost::asio::deadline_timer m_ReadyChecker; boost::asio::deadline_timer m_ReadyChecker;

View file

@ -30,7 +30,7 @@ namespace i2p
} }
m_collected[key].Val += val; m_collected[key].Val += val;
} }
void EventCore::PumpCollected(EventListener * listener) void EventCore::PumpCollected(EventListener * listener)
{ {
std::unique_lock<std::mutex> lock(m_collect_mutex); std::unique_lock<std::mutex> lock(m_collect_mutex);

View file

@ -29,7 +29,7 @@ namespace i2p
void CollectEvent(const std::string & type, const std::string & ident, uint64_t val); void CollectEvent(const std::string & type, const std::string & ident, uint64_t val);
void SetListener(EventListener * l); void SetListener(EventListener * l);
void PumpCollected(EventListener * l); void PumpCollected(EventListener * l);
private: private:
std::mutex m_collect_mutex; std::mutex m_collect_mutex;
struct CollectedEvent struct CollectedEvent
@ -41,7 +41,7 @@ namespace i2p
std::map<std::string, CollectedEvent> m_collected; std::map<std::string, CollectedEvent> m_collected;
EventListener * m_listener = nullptr; EventListener * m_listener = nullptr;
}; };
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
extern EventCore core; extern EventCore core;
#endif #endif
} }

View file

@ -68,7 +68,7 @@ namespace fs {
#else /* other unix */ #else /* other unix */
#if defined(ANDROID) #if defined(ANDROID)
const char * ext = getenv("EXTERNAL_STORAGE"); const char * ext = getenv("EXTERNAL_STORAGE");
if (!ext) ext = "/sdcard"; if (!ext) ext = "/sdcard";
if (boost::filesystem::exists(ext)) if (boost::filesystem::exists(ext))
{ {
dataDir = std::string (ext) + "/" + appName; dataDir = std::string (ext) + "/" + appName;
@ -96,7 +96,7 @@ namespace fs {
boost::filesystem::create_directory(destinations); boost::filesystem::create_directory(destinations);
std::string tags = DataDirPath("tags"); std::string tags = DataDirPath("tags");
if (!boost::filesystem::exists(tags)) if (!boost::filesystem::exists(tags))
boost::filesystem::create_directory(tags); boost::filesystem::create_directory(tags);
else else
i2p::garlic::CleanUpTagsFiles (); i2p::garlic::CleanUpTagsFiles ();
@ -123,12 +123,12 @@ namespace fs {
} }
uint32_t GetLastUpdateTime (const std::string & path) uint32_t GetLastUpdateTime (const std::string & path)
{ {
if (!boost::filesystem::exists(path)) return 0; if (!boost::filesystem::exists(path)) return 0;
boost::system::error_code ec; boost::system::error_code ec;
auto t = boost::filesystem::last_write_time (path, ec); auto t = boost::filesystem::last_write_time (path, ec);
return ec ? 0 : t; return ec ? 0 : t;
} }
bool Remove(const std::string & path) { bool Remove(const std::string & path) {
if (!boost::filesystem::exists(path)) if (!boost::filesystem::exists(path))
@ -136,7 +136,7 @@ namespace fs {
return boost::filesystem::remove(path); return boost::filesystem::remove(path);
} }
bool CreateDirectory (const std::string& path) bool CreateDirectory (const std::string& path)
{ {
if (boost::filesystem::exists(path) && if (boost::filesystem::exists(path) &&
boost::filesystem::is_directory (boost::filesystem::status (path))) return true; boost::filesystem::is_directory (boost::filesystem::status (path))) return true;

View file

@ -97,7 +97,7 @@ namespace fs {
* @param files Vector to store found files * @param files Vector to store found files
* @return true on success and false if directory not exists * @return true on success and false if directory not exists
*/ */
bool ReadDir(const std::string & path, std::vector<std::string> & files); bool ReadDir(const std::string & path, std::vector<std::string> & files);
/** /**
* @brief Remove file with given path * @brief Remove file with given path
@ -113,9 +113,9 @@ namespace fs {
*/ */
bool Exists(const std::string & path); bool Exists(const std::string & path);
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
bool CreateDirectory (const std::string& path); bool CreateDirectory (const std::string& path);
template<typename T> template<typename T>
void _ExpandPath(std::stringstream & path, T c) { void _ExpandPath(std::stringstream & path, T c) {
@ -153,7 +153,7 @@ namespace fs {
_ExpandPath(s, filenames...); _ExpandPath(s, filenames...);
return s.str(); return s.str();
} }
} // fs } // fs
} // i2p } // i2p

View file

@ -21,24 +21,24 @@ namespace data
void Families::LoadCertificate (const std::string& filename) void Families::LoadCertificate (const std::string& filename)
{ {
SSL_CTX * ctx = SSL_CTX_new (TLS_method ()); SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM); int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret) if (ret)
{ {
SSL * ssl = SSL_new (ctx); SSL * ssl = SSL_new (ctx);
X509 * cert = SSL_get_certificate (ssl); X509 * cert = SSL_get_certificate (ssl);
if (cert) if (cert)
{ {
std::shared_ptr<i2p::crypto::Verifier> verifier; std::shared_ptr<i2p::crypto::Verifier> verifier;
// extract issuer name // extract issuer name
char name[100]; char name[100];
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100); X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
char * cn = strstr (name, "CN="); char * cn = strstr (name, "CN=");
if (cn) if (cn)
{ {
cn += 3; cn += 3;
char * family = strstr (cn, ".family"); char * family = strstr (cn, ".family");
if (family) family[0] = 0; if (family) family[0] = 0;
} }
auto pkey = X509_get_pubkey (cert); auto pkey = X509_get_pubkey (cert);
int keyType = EVP_PKEY_base_id (pkey); int keyType = EVP_PKEY_base_id (pkey);
switch (keyType) switch (keyType)
@ -65,7 +65,7 @@ namespace data
i2p::crypto::bn2buf (y, signingKey + 32, 32); i2p::crypto::bn2buf (y, signingKey + 32, 32);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>(signingKey); verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>(signingKey);
} }
else else
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
} }
@ -79,12 +79,12 @@ namespace data
EVP_PKEY_free (pkey); EVP_PKEY_free (pkey);
if (verifier && cn) if (verifier && cn)
m_SigningKeys[cn] = verifier; m_SigningKeys[cn] = verifier;
} }
SSL_free (ssl); SSL_free (ssl);
} }
else else
LogPrint (eLogError, "Family: Can't open certificate file ", filename); LogPrint (eLogError, "Family: Can't open certificate file ", filename);
SSL_CTX_free (ctx); SSL_CTX_free (ctx);
} }
void Families::LoadCertificates () void Families::LoadCertificates ()
@ -105,11 +105,11 @@ namespace data
} }
LoadCertificate (file); LoadCertificate (file);
numCertificates++; numCertificates++;
} }
LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded"); LogPrint (eLogInfo, "Family: ", numCertificates, " certificates loaded");
} }
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[50], signatureBuf[64];
@ -118,12 +118,12 @@ namespace data
{ {
LogPrint (eLogError, "Family: ", family, " is too long"); LogPrint (eLogError, "Family: ", family, " is too long");
return false; return false;
} }
memcpy (buf, family.c_str (), len); memcpy (buf, family.c_str (), len);
memcpy (buf + len, (const uint8_t *)ident, 32); memcpy (buf + len, (const uint8_t *)ident, 32);
len += 32; len += 32;
Base64ToByteStream (signature, signatureLen, signatureBuf, 64); Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
auto it = m_SigningKeys.find (family); auto it = m_SigningKeys.find (family);
if (it != m_SigningKeys.end ()) if (it != m_SigningKeys.end ())
return it->second->Verify (buf, len, signatureBuf); return it->second->Verify (buf, len, signatureBuf);
@ -136,7 +136,7 @@ namespace data
auto filename = i2p::fs::DataDirPath("family", (family + ".key")); auto filename = i2p::fs::DataDirPath("family", (family + ".key"));
std::string sig; std::string sig;
SSL_CTX * ctx = SSL_CTX_new (TLS_method ()); SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.c_str (), SSL_FILETYPE_PEM); int ret = SSL_CTX_use_PrivateKey_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret) if (ret)
{ {
SSL * ssl = SSL_new (ctx); SSL * ssl = SSL_new (ctx);
@ -167,15 +167,15 @@ namespace data
} }
else else
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported"); LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
} }
} }
SSL_free (ssl); SSL_free (ssl);
} }
else else
LogPrint (eLogError, "Family: Can't open keys file: ", filename); LogPrint (eLogError, "Family: Can't open keys file: ", filename);
SSL_CTX_free (ctx); SSL_CTX_free (ctx);
return sig; return sig;
} }
} }
} }

View file

@ -18,7 +18,7 @@ namespace data
Families (); Families ();
~Families (); ~Families ();
void LoadCertificates (); void LoadCertificates ();
bool VerifyFamily (const std::string& family, const IdentHash& ident, bool VerifyFamily (const std::string& family, const IdentHash& ident,
const char * signature, const char * key = nullptr); const char * signature, const char * key = nullptr);
private: private:
@ -28,7 +28,7 @@ namespace data
private: private:
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys; std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys;
}; };
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident); std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);
// return base64 signature of empty string in case of failure // return base64 signature of empty string in case of failure

View file

@ -17,16 +17,16 @@ namespace i2p
{ {
namespace garlic namespace garlic
{ {
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner, GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner,
std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet): std::shared_ptr<const i2p::data::RoutingDestination> destination, int numTags, bool attachLeaseSet):
m_Owner (owner), m_Destination (destination), m_NumTags (numTags), m_Owner (owner), m_Destination (destination), m_NumTags (numTags),
m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend), m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend),
m_LeaseSetUpdateMsgID (0) m_LeaseSetUpdateMsgID (0)
{ {
// create new session tags and session key // create new session tags and session key
RAND_bytes (m_SessionKey, 32); RAND_bytes (m_SessionKey, 32);
m_Encryption.SetKey (m_SessionKey); m_Encryption.SetKey (m_SessionKey);
} }
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag): GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0) m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
@ -35,10 +35,10 @@ namespace garlic
m_Encryption.SetKey (m_SessionKey); m_Encryption.SetKey (m_SessionKey);
m_SessionTags.push_back (sessionTag); m_SessionTags.push_back (sessionTag);
m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch (); m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch ();
} }
GarlicRoutingSession::~GarlicRoutingSession () GarlicRoutingSession::~GarlicRoutingSession ()
{ {
} }
std::shared_ptr<GarlicRoutingPath> GarlicRoutingSession::GetSharedRoutingPath () std::shared_ptr<GarlicRoutingPath> GarlicRoutingSession::GetSharedRoutingPath ()
@ -53,56 +53,56 @@ namespace garlic
if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++; if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++;
return m_SharedRoutingPath; return m_SharedRoutingPath;
} }
void GarlicRoutingSession::SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path) void GarlicRoutingSession::SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path)
{ {
if (path && path->outboundTunnel && path->remoteLease) if (path && path->outboundTunnel && path->remoteLease)
{ {
path->updateTime = i2p::util::GetSecondsSinceEpoch (); path->updateTime = i2p::util::GetSecondsSinceEpoch ();
path->numTimesUsed = 0; path->numTimesUsed = 0;
} }
else else
path = nullptr; path = nullptr;
m_SharedRoutingPath = path; m_SharedRoutingPath = path;
} }
GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags () GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags ()
{ {
auto tags = new UnconfirmedTags (m_NumTags); auto tags = new UnconfirmedTags (m_NumTags);
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch (); tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
for (int i = 0; i < m_NumTags; i++) for (int i = 0; i < m_NumTags; i++)
{ {
RAND_bytes (tags->sessionTags[i], 32); RAND_bytes (tags->sessionTags[i], 32);
tags->sessionTags[i].creationTime = tags->tagsCreationTime; tags->sessionTags[i].creationTime = tags->tagsCreationTime;
} }
return tags; return tags;
} }
void GarlicRoutingSession::MessageConfirmed (uint32_t msgID) void GarlicRoutingSession::MessageConfirmed (uint32_t msgID)
{ {
TagsConfirmed (msgID); TagsConfirmed (msgID);
if (msgID == m_LeaseSetUpdateMsgID) if (msgID == m_LeaseSetUpdateMsgID)
{ {
m_LeaseSetUpdateStatus = eLeaseSetUpToDate; m_LeaseSetUpdateStatus = eLeaseSetUpToDate;
m_LeaseSetUpdateMsgID = 0; m_LeaseSetUpdateMsgID = 0;
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed"); LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
} }
else else
CleanupExpiredTags (); CleanupExpiredTags ();
} }
void GarlicRoutingSession::TagsConfirmed (uint32_t msgID) void GarlicRoutingSession::TagsConfirmed (uint32_t msgID)
{ {
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
auto it = m_UnconfirmedTagsMsgs.find (msgID); auto it = m_UnconfirmedTagsMsgs.find (msgID);
if (it != m_UnconfirmedTagsMsgs.end ()) if (it != m_UnconfirmedTagsMsgs.end ())
{ {
auto& tags = it->second; auto& tags = it->second;
if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
{ {
for (int i = 0; i < tags->numTags; i++) for (int i = 0; i < tags->numTags; i++)
m_SessionTags.push_back (tags->sessionTags[i]); m_SessionTags.push_back (tags->sessionTags[i]);
} }
m_UnconfirmedTagsMsgs.erase (it); m_UnconfirmedTagsMsgs.erase (it);
} }
} }
@ -114,7 +114,7 @@ namespace garlic
{ {
if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
it = m_SessionTags.erase (it); it = m_SessionTags.erase (it);
else else
++it; ++it;
} }
CleanupUnconfirmedTags (); CleanupUnconfirmedTags ();
@ -123,9 +123,9 @@ namespace garlic
if (m_Owner) if (m_Owner)
m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
m_LeaseSetUpdateMsgID = 0; m_LeaseSetUpdateMsgID = 0;
} }
return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty ();
} }
bool GarlicRoutingSession::CleanupUnconfirmedTags () bool GarlicRoutingSession::CleanupUnconfirmedTags ()
{ {
@ -140,10 +140,10 @@ namespace garlic
m_Owner->RemoveDeliveryStatusSession (it->first); m_Owner->RemoveDeliveryStatusSession (it->first);
it = m_UnconfirmedTagsMsgs.erase (it); it = m_UnconfirmedTagsMsgs.erase (it);
ret = true; ret = true;
} }
else else
++it; ++it;
} }
return ret; return ret;
} }
@ -155,10 +155,10 @@ namespace garlic
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
// find non-expired tag // find non-expired tag
bool tagFound = false; bool tagFound = false;
SessionTag tag; SessionTag tag;
if (m_NumTags > 0) if (m_NumTags > 0)
{ {
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
while (!m_SessionTags.empty ()) while (!m_SessionTags.empty ())
{ {
@ -168,11 +168,11 @@ namespace garlic
m_SessionTags.pop_front (); // use same tag only once m_SessionTags.pop_front (); // use same tag only once
tagFound = true; tagFound = true;
break; break;
} }
else else
m_SessionTags.pop_front (); // remove expired tag m_SessionTags.pop_front (); // remove expired tag
} }
} }
// create message // create message
if (!tagFound) // new session if (!tagFound) // new session
{ {
@ -184,34 +184,34 @@ namespace garlic
} }
// create ElGamal block // create ElGamal block
ElGamalBlock elGamal; ElGamalBlock elGamal;
memcpy (elGamal.sessionKey, m_SessionKey, 32); memcpy (elGamal.sessionKey, m_SessionKey, 32);
RAND_bytes (elGamal.preIV, 32); // Pre-IV RAND_bytes (elGamal.preIV, 32); // Pre-IV
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(elGamal.preIV, 32, iv); SHA256(elGamal.preIV, 32, iv);
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx); m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
m_Encryption.SetIV (iv); m_Encryption.SetIV (iv);
buf += 514; buf += 514;
len += 514; len += 514;
} }
else // existing session else // existing session
{ {
// session tag // session tag
memcpy (buf, tag, 32); memcpy (buf, tag, 32);
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(tag, 32, iv); SHA256(tag, 32, iv);
m_Encryption.SetIV (iv); m_Encryption.SetIV (iv);
buf += 32; buf += 32;
len += 32; len += 32;
} }
// AES block // AES block
len += CreateAESBlock (buf, msg); len += CreateAESBlock (buf, msg);
htobe32buf (m->GetPayload (), len); htobe32buf (m->GetPayload (), len);
m->len += len + 4; m->len += len + 4;
m->FillI2NPMessageHeader (eI2NPGarlic); m->FillI2NPMessageHeader (eI2NPGarlic);
return m; return m;
} }
size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg) size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg)
{ {
@ -221,13 +221,13 @@ namespace garlic
htobuf16 (buf, newTags ? htobe16 (newTags->numTags) : 0); // tag count htobuf16 (buf, newTags ? htobe16 (newTags->numTags) : 0); // tag count
blockSize += 2; blockSize += 2;
if (newTags) // session tags recreated if (newTags) // session tags recreated
{ {
for (int i = 0; i < newTags->numTags; i++) for (int i = 0; i < newTags->numTags; i++)
{ {
memcpy (buf + blockSize, newTags->sessionTags[i], 32); // tags memcpy (buf + blockSize, newTags->sessionTags[i], 32); // tags
blockSize += 32; blockSize += 32;
} }
} }
uint32_t * payloadSize = (uint32_t *)(buf + blockSize); uint32_t * payloadSize = (uint32_t *)(buf + blockSize);
blockSize += 4; blockSize += 4;
uint8_t * payloadHash = buf + blockSize; uint8_t * payloadHash = buf + blockSize;
@ -243,7 +243,7 @@ namespace garlic
blockSize += (16-rem); //padding blockSize += (16-rem); //padding
m_Encryption.Encrypt(buf, blockSize, buf); m_Encryption.Encrypt(buf, blockSize, buf);
return blockSize; return blockSize;
} }
size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags) size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags)
{ {
@ -256,7 +256,7 @@ namespace garlic
size++; size++;
if (m_Owner) if (m_Owner)
{ {
// resubmit non-confirmed LeaseSet // resubmit non-confirmed LeaseSet
if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && ts > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT) if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && ts > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
{ {
@ -267,7 +267,7 @@ namespace garlic
// attach DeviveryStatus if necessary // attach DeviveryStatus if necessary
if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated
{ {
// clove is DeliveryStatus // clove is DeliveryStatus
auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID); auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID);
if (cloveSize > 0) // successive? if (cloveSize > 0) // successive?
{ {
@ -278,14 +278,14 @@ namespace garlic
newTags->msgID = msgID; newTags->msgID = msgID;
m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr<UnconfirmedTags>(newTags))); m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr<UnconfirmedTags>(newTags)));
newTags = nullptr; // got acquired newTags = nullptr; // got acquired
} }
m_Owner->DeliveryStatusSent (shared_from_this (), msgID); m_Owner->DeliveryStatusSent (shared_from_this (), msgID);
} }
else else
LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created"); LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created");
} }
// attach LeaseSet // attach LeaseSet
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated) if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
{ {
if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous
m_LeaseSetUpdateStatus = eLeaseSetSubmitted; m_LeaseSetUpdateStatus = eLeaseSetSubmitted;
@ -293,25 +293,25 @@ namespace garlic
m_LeaseSetSubmissionTime = ts; m_LeaseSetSubmissionTime = ts;
// clove if our leaseSet must be attached // clove if our leaseSet must be attached
auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ()); auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ());
size += CreateGarlicClove (payload + size, leaseSet, false); size += CreateGarlicClove (payload + size, leaseSet, false);
(*numCloves)++; (*numCloves)++;
} }
} }
if (msg) // clove message ifself if presented if (msg) // clove message ifself if presented
{ {
size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false); size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false);
(*numCloves)++; (*numCloves)++;
} }
memset (payload + size, 0, 3); // certificate of message memset (payload + size, 0, 3); // certificate of message
size += 3; size += 3;
htobe32buf (payload + size, msgID); // MessageID htobe32buf (payload + size, msgID); // MessageID
size += 4; size += 4;
htobe64buf (payload + size, ts + 8000); // Expiration of message, 8 sec htobe64buf (payload + size, ts + 8000); // Expiration of message, 8 sec
size += 8; size += 8;
if (newTags) delete newTags; // not acquired, delete if (newTags) delete newTags; // not acquired, delete
return size; return size;
} }
size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination) size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination)
{ {
@ -323,13 +323,13 @@ namespace garlic
size++; size++;
memcpy (buf + size, m_Destination->GetIdentHash (), 32); memcpy (buf + size, m_Destination->GetIdentHash (), 32);
size += 32; size += 32;
} }
else else
{ {
buf[size] = 0;// delivery instructions flag local buf[size] = 0;// delivery instructions flag local
size++; size++;
} }
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
size += msg->GetLength (); size += msg->GetLength ();
uint32_t cloveID; uint32_t cloveID;
@ -341,34 +341,34 @@ namespace garlic
memset (buf + size, 0, 3); // certificate of clove memset (buf + size, 0, 3); // certificate of clove
size += 3; size += 3;
return size; return size;
} }
size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID) size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID)
{ {
size_t size = 0; size_t size = 0;
if (m_Owner) if (m_Owner)
{ {
auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel (); auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel ();
if (inboundTunnel) if (inboundTunnel)
{ {
buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel
size++; size++;
// hash and tunnelID sequence is reversed for Garlic // hash and tunnelID sequence is reversed for Garlic
memcpy (buf + size, inboundTunnel->GetNextIdentHash (), 32); // To Hash memcpy (buf + size, inboundTunnel->GetNextIdentHash (), 32); // To Hash
size += 32; size += 32;
htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID
size += 4; size += 4;
// create msg // create msg
auto msg = CreateDeliveryStatusMsg (msgID); auto msg = CreateDeliveryStatusMsg (msgID);
if (m_Owner) if (m_Owner)
{ {
//encrypt //encrypt
uint8_t key[32], tag[32]; uint8_t key[32], tag[32];
RAND_bytes (key, 32); // random session key RAND_bytes (key, 32); // random session key
RAND_bytes (tag, 32); // random session tag RAND_bytes (tag, 32); // random session tag
m_Owner->SubmitSessionKey (key, tag); m_Owner->SubmitSessionKey (key, tag);
GarlicRoutingSession garlic (key, tag); GarlicRoutingSession garlic (key, tag);
msg = garlic.WrapSingleMessage (msg); msg = garlic.WrapSingleMessage (msg);
} }
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
size += msg->GetLength (); size += msg->GetLength ();
@ -383,7 +383,7 @@ namespace garlic
memset (buf + size, 0, 3); // certificate of clove memset (buf + size, 0, 3); // certificate of clove
size += 3; size += 3;
} }
else else
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus"); LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
} }
else else
@ -395,19 +395,19 @@ namespace garlic
GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default
{ {
m_Ctx = BN_CTX_new (); m_Ctx = BN_CTX_new ();
} }
GarlicDestination::~GarlicDestination () GarlicDestination::~GarlicDestination ()
{ {
BN_CTX_free (m_Ctx); BN_CTX_free (m_Ctx);
} }
void GarlicDestination::CleanUp () void GarlicDestination::CleanUp ()
{ {
m_Sessions.clear (); m_Sessions.clear ();
m_DeliveryStatusSessions.clear (); m_DeliveryStatusSessions.clear ();
m_Tags.clear (); m_Tags.clear ();
} }
void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag) void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag)
{ {
if (key) if (key)
@ -417,7 +417,7 @@ namespace garlic
} }
} }
bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag) bool GarlicDestination::SubmitSessionKey (const uint8_t * key, const uint8_t * tag)
{ {
AddSessionKey (key, tag); AddSessionKey (key, tag);
return true; return true;
@ -431,22 +431,22 @@ 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;
} }
buf += 4; // length buf += 4; // length
auto it = m_Tags.find (SessionTag(buf)); auto it = m_Tags.find (SessionTag(buf));
if (it != m_Tags.end ()) if (it != m_Tags.end ())
{ {
// tag found. Use AES // tag found. Use AES
auto decryption = it->second; auto decryption = it->second;
m_Tags.erase (it); // tag might be used only once m_Tags.erase (it); // tag might be used only once
if (length >= 32) if (length >= 32)
{ {
uint8_t iv[32]; // IV is first 16 bytes uint8_t iv[32]; // IV is first 16 bytes
SHA256(buf, 32, iv); SHA256(buf, 32, iv);
decryption->SetIV (iv); decryption->SetIV (iv);
decryption->Decrypt (buf + 32, length - 32, buf + 32); decryption->Decrypt (buf + 32, length - 32, buf + 32);
HandleAESBlock (buf + 32, length - 32, decryption, msg->from); HandleAESBlock (buf + 32, length - 32, decryption, msg->from);
} }
else else
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes"); LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
} }
@ -455,35 +455,35 @@ namespace garlic
// tag not found. Use ElGamal // tag not found. Use ElGamal
ElGamalBlock elGamal; ElGamalBlock elGamal;
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx)) if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
{ {
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
SHA256(elGamal.preIV, 32, iv); SHA256(elGamal.preIV, 32, iv);
decryption->SetIV (iv); decryption->SetIV (iv);
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 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)
{ {
uint16_t tagCount = bufbe16toh (buf); uint16_t tagCount = bufbe16toh (buf);
buf += 2; len -= 2; buf += 2; len -= 2;
if (tagCount > 0) if (tagCount > 0)
{ {
if (tagCount*32 > len) if (tagCount*32 > len)
{ {
LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len); LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len);
return ; return ;
} }
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (int i = 0; i < tagCount; i++) for (int i = 0; i < tagCount; i++)
m_Tags[SessionTag(buf + i*32, ts)] = decryption; m_Tags[SessionTag(buf + i*32, ts)] = decryption;
} }
buf += tagCount*32; buf += tagCount*32;
len -= tagCount*32; len -= tagCount*32;
uint32_t payloadSize = bufbe32toh (buf); uint32_t payloadSize = bufbe32toh (buf);
@ -491,10 +491,10 @@ namespace garlic
{ {
LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize); LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize);
return; return;
} }
buf += 4; buf += 4;
uint8_t * payloadHash = buf; uint8_t * payloadHash = buf;
buf += 32;// payload hash. buf += 32;// payload hash.
if (*buf) // session key? if (*buf) // session key?
buf += 32; // new session key buf += 32; // new session key
buf++; // flag buf++; // flag
@ -506,9 +506,9 @@ namespace garlic
{ {
LogPrint (eLogError, "Garlic: wrong payload hash"); LogPrint (eLogError, "Garlic: wrong payload hash");
return; return;
} }
HandleGarlicPayload (buf, payloadSize, from); HandleGarlicPayload (buf, payloadSize, from);
} }
void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) void GarlicDestination::HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
@ -530,8 +530,8 @@ namespace garlic
{ {
// TODO: implement // TODO: implement
LogPrint (eLogWarning, "Garlic: clove encrypted"); LogPrint (eLogWarning, "Garlic: clove encrypted");
buf += 32; buf += 32;
} }
ptrdiff_t offset = buf - buf1; ptrdiff_t offset = buf - buf1;
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03); GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
switch (deliveryType) switch (deliveryType)
@ -542,10 +542,10 @@ namespace garlic
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: message is too short");
break; break;
} }
HandleI2NPMessage (buf, len - offset, from); HandleI2NPMessage (buf, len - offset, from);
break; break;
case eGarlicDeliveryTypeDestination: case eGarlicDeliveryTypeDestination:
LogPrint (eLogDebug, "Garlic: type destination"); LogPrint (eLogDebug, "Garlic: type destination");
buf += 32; // destination. check it later or for multiple destinations buf += 32; // destination. check it later or for multiple destinations
offset = buf - buf1; offset = buf - buf1;
@ -553,11 +553,11 @@ namespace garlic
{ {
LogPrint (eLogError, "Garlic: message is too short"); LogPrint (eLogError, "Garlic: message is too short");
break; break;
} }
HandleI2NPMessage (buf, len - offset, from); HandleI2NPMessage (buf, len - offset, from);
break; break;
case eGarlicDeliveryTypeTunnel: case eGarlicDeliveryTypeTunnel:
{ {
LogPrint (eLogDebug, "Garlic: type tunnel"); LogPrint (eLogDebug, "Garlic: type tunnel");
// gwHash and gwTunnel sequence is reverted // gwHash and gwTunnel sequence is reverted
uint8_t * gwHash = buf; uint8_t * gwHash = buf;
@ -591,7 +591,7 @@ namespace garlic
{ {
uint8_t * ident = buf; uint8_t * ident = buf;
buf += 32; buf += 32;
offset = buf - buf1; offset = buf - buf1;
if (!from) // received directly if (!from) // received directly
{ {
if (offset > (int)len) if (offset > (int)len)
@ -604,7 +604,7 @@ namespace garlic
} }
else else
LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported"); LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported");
break; break;
} }
default: default:
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType); LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
@ -623,23 +623,23 @@ namespace garlic
{ {
LogPrint (eLogError, "Garlic: clove is too long"); LogPrint (eLogError, "Garlic: clove is too long");
break; break;
} }
len -= offset; len -= offset;
} }
} }
std::shared_ptr<I2NPMessage> GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination, std::shared_ptr<I2NPMessage> GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet) std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet)
{ {
auto session = GetRoutingSession (destination, attachLeaseSet); auto session = GetRoutingSession (destination, attachLeaseSet);
return session->WrapSingleMessage (msg); return session->WrapSingleMessage (msg);
} }
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession ( std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet) std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
{ {
GarlicRoutingSessionPtr session; GarlicRoutingSessionPtr session;
{ {
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
auto it = m_Sessions.find (destination->GetIdentHash ()); auto it = m_Sessions.find (destination->GetIdentHash ());
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
@ -647,14 +647,14 @@ namespace garlic
} }
if (!session) if (!session)
{ {
session = std::make_shared<GarlicRoutingSession> (this, destination, session = std::make_shared<GarlicRoutingSession> (this, destination,
attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests attachLeaseSet ? m_NumTags : 4, attachLeaseSet); // specified num tags for connections and 4 for LS requests
std::unique_lock<std::mutex> l(m_SessionsMutex); std::unique_lock<std::mutex> l(m_SessionsMutex);
m_Sessions[destination->GetIdentHash ()] = session; m_Sessions[destination->GetIdentHash ()] = session;
} }
return session; return session;
} }
void GarlicDestination::CleanupExpiredTags () void GarlicDestination::CleanupExpiredTags ()
{ {
// incoming // incoming
@ -666,7 +666,7 @@ namespace garlic
{ {
numExpiredTags++; numExpiredTags++;
it = m_Tags.erase (it); it = m_Tags.erase (it);
} }
else else
++it; ++it;
} }
@ -690,7 +690,7 @@ namespace garlic
} }
} }
// delivery status sessions // delivery status sessions
{ {
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex); std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
for (auto it = m_DeliveryStatusSessions.begin (); it != m_DeliveryStatusSessions.end (); ) for (auto it = m_DeliveryStatusSessions.begin (); it != m_DeliveryStatusSessions.end (); )
{ {
@ -699,7 +699,7 @@ namespace garlic
else else
++it; ++it;
} }
} }
} }
void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID) void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID)
@ -756,7 +756,7 @@ namespace garlic
if (m_Tags.empty ()) return; if (m_Tags.empty ()) return;
std::string ident = GetIdentHash().ToBase32(); std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags")); std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags"));
std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc); std::ofstream f (path, std::ofstream::binary | std::ofstream::out | std::ofstream::trunc);
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
// 4 bytes timestamp, 32 bytes tag, 32 bytes key // 4 bytes timestamp, 32 bytes tag, 32 bytes key
for (auto it: m_Tags) for (auto it: m_Tags)
@ -766,7 +766,7 @@ namespace garlic
f.write ((char *)&it.first.creationTime, 4); f.write ((char *)&it.first.creationTime, 4);
f.write ((char *)it.first.data (), 32); f.write ((char *)it.first.data (), 32);
f.write ((char *)it.second->GetKey ().data (), 32); f.write ((char *)it.second->GetKey ().data (), 32);
} }
} }
} }
@ -775,11 +775,11 @@ namespace garlic
std::string ident = GetIdentHash().ToBase32(); std::string ident = GetIdentHash().ToBase32();
std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags")); std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags"));
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT) if (ts < i2p::fs::GetLastUpdateTime (path) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
{ {
// might contain non-expired tags // might contain non-expired tags
std::ifstream f (path, std::ifstream::binary); std::ifstream f (path, std::ifstream::binary);
if (f) if (f)
{ {
std::map<i2p::crypto::AESKey, std::shared_ptr<AESDecryption> > keys; std::map<i2p::crypto::AESKey, std::shared_ptr<AESDecryption> > keys;
// 4 bytes timestamp, 32 bytes tag, 32 bytes key // 4 bytes timestamp, 32 bytes tag, 32 bytes key
@ -794,7 +794,7 @@ namespace garlic
f.read ((char *)key, 32); f.read ((char *)key, 32);
} }
else else
f.seekg (64, std::ios::cur); // skip f.seekg (64, std::ios::cur); // skip
if (f.eof ()) break; if (f.eof ()) break;
std::shared_ptr<AESDecryption> decryption; std::shared_ptr<AESDecryption> decryption;
@ -805,21 +805,21 @@ namespace garlic
decryption = std::make_shared<AESDecryption>(key); decryption = std::make_shared<AESDecryption>(key);
m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption)); m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
} }
if (!m_Tags.empty ()) if (!m_Tags.empty ())
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident); LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
} }
} }
i2p::fs::Remove (path); i2p::fs::Remove (path);
} }
void CleanUpTagsFiles () void CleanUpTagsFiles ()
{ {
std::vector<std::string> files; std::vector<std::string> files;
i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files); i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files);
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: files) for (auto it: files)
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT) if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
i2p::fs::Remove (it); i2p::fs::Remove (it);
} }
} }
} }

View file

@ -17,46 +17,46 @@
namespace i2p namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
class OutboundTunnel; class OutboundTunnel;
} }
namespace garlic namespace garlic
{ {
enum GarlicDeliveryType enum GarlicDeliveryType
{ {
eGarlicDeliveryTypeLocal = 0, eGarlicDeliveryTypeLocal = 0,
eGarlicDeliveryTypeDestination = 1, eGarlicDeliveryTypeDestination = 1,
eGarlicDeliveryTypeRouter = 2, eGarlicDeliveryTypeRouter = 2,
eGarlicDeliveryTypeTunnel = 3 eGarlicDeliveryTypeTunnel = 3
}; };
struct ElGamalBlock struct ElGamalBlock
{ {
uint8_t sessionKey[32]; uint8_t sessionKey[32];
uint8_t preIV[32]; uint8_t preIV[32];
uint8_t padding[158]; uint8_t padding[158];
}; };
const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes const int INCOMING_TAGS_EXPIRATION_TIMEOUT = 960; // 16 minutes
const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes const int OUTGOING_TAGS_EXPIRATION_TIMEOUT = 720; // 12 minutes
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
struct SessionTag: public i2p::data::Tag<32> struct SessionTag: public i2p::data::Tag<32>
{ {
SessionTag (const uint8_t * buf, uint32_t ts = 0): Tag<32>(buf), creationTime (ts) {}; SessionTag (const uint8_t * buf, uint32_t ts = 0): Tag<32>(buf), creationTime (ts) {};
SessionTag () = default; SessionTag () = default;
SessionTag (const SessionTag& ) = default; SessionTag (const SessionTag& ) = default;
SessionTag& operator= (const SessionTag& ) = default; SessionTag& operator= (const SessionTag& ) = default;
#ifndef _WIN32 #ifndef _WIN32
SessionTag (SessionTag&& ) = default; SessionTag (SessionTag&& ) = default;
SessionTag& operator= (SessionTag&& ) = default; SessionTag& operator= (SessionTag&& ) = default;
#endif #endif
uint32_t creationTime; // seconds since epoch uint32_t creationTime; // seconds since epoch
}; };
// AESDecryption is associated with session tags and store key // AESDecryption is associated with session tags and store key
@ -67,7 +67,7 @@ namespace garlic
AESDecryption (const uint8_t * key): m_Key (key) AESDecryption (const uint8_t * key): m_Key (key)
{ {
SetKey (key); SetKey (key);
} }
const i2p::crypto::AESKey& GetKey () const { return m_Key; }; const i2p::crypto::AESKey& GetKey () const { return m_Key; };
private: private:
@ -81,8 +81,8 @@ namespace garlic
std::shared_ptr<const i2p::data::Lease> remoteLease; std::shared_ptr<const i2p::data::Lease> remoteLease;
int rtt; // RTT int rtt; // RTT
uint32_t updateTime; // seconds since epoch uint32_t updateTime; // seconds since epoch
int numTimesUsed; int numTimesUsed;
}; };
class GarlicDestination; class GarlicDestination;
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession> class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
@ -94,7 +94,7 @@ namespace garlic
eLeaseSetSubmitted, eLeaseSetSubmitted,
eLeaseSetDoNotSend eLeaseSetDoNotSend
}; };
struct UnconfirmedTags struct UnconfirmedTags
{ {
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; }; UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
@ -107,23 +107,23 @@ namespace garlic
public: public:
GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination, GarlicRoutingSession (GarlicDestination * owner, std::shared_ptr<const i2p::data::RoutingDestination> destination,
int numTags, bool attachLeaseSet); int numTags, bool attachLeaseSet);
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
~GarlicRoutingSession (); ~GarlicRoutingSession ();
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg); std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
void MessageConfirmed (uint32_t msgID); void MessageConfirmed (uint32_t msgID);
bool CleanupExpiredTags (); // returns true if something left bool CleanupExpiredTags (); // returns true if something left
bool CleanupUnconfirmedTags (); // returns true if something has been deleted bool CleanupUnconfirmedTags (); // returns true if something has been deleted
void SetLeaseSetUpdated () void SetLeaseSetUpdated ()
{ {
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated; if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
}; };
bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; }; bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; }; bool IsLeaseSetUpdated () const { return m_LeaseSetUpdateStatus == eLeaseSetUpdated; };
uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; } uint64_t GetLeaseSetSubmissionTime () const { return m_LeaseSetSubmissionTime; }
std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath (); std::shared_ptr<GarlicRoutingPath> GetSharedRoutingPath ();
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path); void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
@ -144,26 +144,26 @@ namespace garlic
GarlicDestination * m_Owner; GarlicDestination * m_Owner;
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination; std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
i2p::crypto::AESKey m_SessionKey; i2p::crypto::AESKey m_SessionKey;
std::list<SessionTag> m_SessionTags; std::list<SessionTag> m_SessionTags;
int m_NumTags; int m_NumTags;
std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags std::map<uint32_t, std::unique_ptr<UnconfirmedTags> > m_UnconfirmedTagsMsgs; // msgID->tags
LeaseSetUpdateStatus m_LeaseSetUpdateStatus; LeaseSetUpdateStatus m_LeaseSetUpdateStatus;
uint32_t m_LeaseSetUpdateMsgID; uint32_t m_LeaseSetUpdateMsgID;
uint64_t m_LeaseSetSubmissionTime; // in milliseconds uint64_t m_LeaseSetSubmissionTime; // in milliseconds
i2p::crypto::CBCEncryption m_Encryption; i2p::crypto::CBCEncryption m_Encryption;
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath; std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
public: public:
// for HTTP only // for HTTP only
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); }; size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
}; };
//using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>; //using GarlicRoutingSessionPtr = std::shared_ptr<GarlicRoutingSession>;
typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8 typedef std::shared_ptr<GarlicRoutingSession> GarlicRoutingSessionPtr; // TODO: replace to using after switch to 4.8
class GarlicDestination: public i2p::data::LocalDestination class GarlicDestination: public i2p::data::LocalDestination
{ {
@ -173,36 +173,36 @@ namespace garlic
~GarlicDestination (); ~GarlicDestination ();
void CleanUp (); void CleanUp ();
void SetNumTags (int numTags) { m_NumTags = numTags; }; void SetNumTags (int numTags) { m_NumTags = numTags; };
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet); std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
void CleanupExpiredTags (); void CleanupExpiredTags ();
void RemoveDeliveryStatusSession (uint32_t msgID); void RemoveDeliveryStatusSession (uint32_t msgID);
std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination, std::shared_ptr<I2NPMessage> WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false); std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet = false);
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);
virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); virtual void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); virtual void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
virtual void SetLeaseSetUpdated (); virtual void SetLeaseSetUpdated ();
virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO virtual std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0; virtual std::shared_ptr<i2p::tunnel::TunnelPool> GetTunnelPool () const = 0;
virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0; virtual void HandleI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) = 0;
protected: protected:
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg); void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
void SaveTags (); void SaveTags ();
void LoadTags (); void LoadTags ();
private: private:
void HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption, void 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);
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);
@ -218,17 +218,17 @@ namespace garlic
// DeliveryStatus // DeliveryStatus
std::mutex m_DeliveryStatusSessionsMutex; std::mutex m_DeliveryStatusSessionsMutex;
std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
public: public:
// for HTTP only // for HTTP only
size_t GetNumIncomingTags () const { return m_Tags.size (); } size_t GetNumIncomingTags () const { return m_Tags.size (); }
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
}; };
void CleanUpTagsFiles (); void CleanUpTagsFiles ();
} }
} }
#endif #endif

View file

@ -28,7 +28,7 @@ namespace crypto
GOSTR3410Curve::~GOSTR3410Curve () GOSTR3410Curve::~GOSTR3410Curve ()
{ {
EC_GROUP_free (m_Group); EC_GROUP_free (m_Group);
} }
EC_POINT * GOSTR3410Curve::MulP (const BIGNUM * n) const EC_POINT * GOSTR3410Curve::MulP (const BIGNUM * n) const
{ {
@ -81,12 +81,12 @@ namespace crypto
BN_mod_inverse (h, h, q, ctx); // 1/h mod q BN_mod_inverse (h, h, q, ctx); // 1/h mod q
BIGNUM * z1 = BN_CTX_get (ctx); BIGNUM * z1 = BN_CTX_get (ctx);
BN_mod_mul (z1, s, h, q, ctx); // z1 = s/h BN_mod_mul (z1, s, h, q, ctx); // z1 = s/h
BIGNUM * z2 = BN_CTX_get (ctx); BIGNUM * z2 = BN_CTX_get (ctx);
BN_sub (z2, q, r); // z2 = -r BN_sub (z2, q, r); // z2 = -r
BN_mod_mul (z2, z2, h, q, ctx); // z2 = -r/h BN_mod_mul (z2, z2, h, q, ctx); // z2 = -r/h
EC_POINT * C = EC_POINT_new (m_Group); EC_POINT * C = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub EC_POINT_mul (m_Group, C, z1, pub, z2, ctx); // z1*P + z2*pub
BIGNUM * x = BN_CTX_get (ctx); BIGNUM * x = BN_CTX_get (ctx);
GetXY (C, x, nullptr); // Cx GetXY (C, x, nullptr); // Cx
BN_mod (x, x, q, ctx); // Cx % q BN_mod (x, x, q, ctx); // Cx % q
bool ret = !BN_cmp (x, r); // Cx = r ? bool ret = !BN_cmp (x, r); // Cx = r ?
@ -94,9 +94,9 @@ namespace crypto
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
return ret; return ret;
} }
EC_POINT * GOSTR3410Curve::RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY) const EC_POINT * GOSTR3410Curve::RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY) const
{ {
// s*P = r*Q + h*C // s*P = r*Q + h*C
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
@ -104,7 +104,7 @@ namespace crypto
EC_POINT * C = EC_POINT_new (m_Group); // C = k*P = (rx, ry) EC_POINT * C = EC_POINT_new (m_Group); // C = k*P = (rx, ry)
EC_POINT * Q = nullptr; EC_POINT * Q = nullptr;
if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx)) if (EC_POINT_set_compressed_coordinates_GFp (m_Group, C, r, isNegativeY ? 1 : 0, ctx))
{ {
EC_POINT * S = EC_POINT_new (m_Group); // S = s*P EC_POINT * S = EC_POINT_new (m_Group); // S = s*P
EC_POINT_mul (m_Group, S, s, nullptr, nullptr, ctx); EC_POINT_mul (m_Group, S, s, nullptr, nullptr, ctx);
BIGNUM * q = BN_CTX_get (ctx); BIGNUM * q = BN_CTX_get (ctx);
@ -112,28 +112,28 @@ namespace crypto
BIGNUM * h = BN_CTX_get (ctx); BIGNUM * h = BN_CTX_get (ctx);
BN_mod (h, digest, q, ctx); // h = digest % q BN_mod (h, digest, q, ctx); // h = digest % q
BN_sub (h, q, h); // h = -h BN_sub (h, q, h); // h = -h
EC_POINT * H = EC_POINT_new (m_Group); EC_POINT * H = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, H, nullptr, C, h, ctx); // -h*C EC_POINT_mul (m_Group, H, nullptr, C, h, ctx); // -h*C
EC_POINT_add (m_Group, C, S, H, ctx); // s*P - h*C EC_POINT_add (m_Group, C, S, H, ctx); // s*P - h*C
EC_POINT_free (H); EC_POINT_free (H);
EC_POINT_free (S); EC_POINT_free (S);
BIGNUM * r1 = BN_CTX_get (ctx); BIGNUM * r1 = BN_CTX_get (ctx);
BN_mod_inverse (r1, r, q, ctx); BN_mod_inverse (r1, r, q, ctx);
Q = EC_POINT_new (m_Group); Q = EC_POINT_new (m_Group);
EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
} }
EC_POINT_free (C); EC_POINT_free (C);
BN_CTX_end (ctx); BN_CTX_end (ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
return Q; return Q;
} }
static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet) static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet)
{ {
// a, b, p, q, x, y // a, b, p, q, x, y
static const char * params[eGOSTR3410NumParamSets][6] = static const char * params[eGOSTR3410NumParamSets][6] =
{ {
{ {
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
"A6", "A6",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
@ -147,10 +147,10 @@ namespace crypto
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275", "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",
"3", "3",
"7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4" "7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4"
} // tc26-2012-paramSetA-512 } // tc26-2012-paramSetA-512
}; };
BIGNUM * a = nullptr, * b = nullptr, * p = nullptr, * q =nullptr, * x = nullptr, * y = nullptr; BIGNUM * a = nullptr, * b = nullptr, * p = nullptr, * q =nullptr, * x = nullptr, * y = nullptr;
BN_hex2bn(&a, params[paramSet][0]); BN_hex2bn(&a, params[paramSet][0]);
BN_hex2bn(&b, params[paramSet][1]); BN_hex2bn(&b, params[paramSet][1]);
@ -161,25 +161,25 @@ namespace crypto
auto curve = new GOSTR3410Curve (a, b, p, q, x, y); auto curve = new GOSTR3410Curve (a, b, p, q, x, y);
BN_free (a); BN_free (b); BN_free (p); BN_free (q); BN_free (x); BN_free (y); BN_free (a); BN_free (b); BN_free (p); BN_free (q); BN_free (x); BN_free (y);
return curve; return curve;
} }
static std::array<std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves; static std::array<std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves;
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet) std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet)
{ {
if (!g_GOSTR3410Curves[paramSet]) if (!g_GOSTR3410Curves[paramSet])
{ {
auto c = CreateGOSTR3410Curve (paramSet); auto c = CreateGOSTR3410Curve (paramSet);
if (!g_GOSTR3410Curves[paramSet]) // make sure it was not created already if (!g_GOSTR3410Curves[paramSet]) // make sure it was not created already
g_GOSTR3410Curves[paramSet].reset (c); g_GOSTR3410Curves[paramSet].reset (c);
else else
delete c; delete c;
} }
return g_GOSTR3410Curves[paramSet]; return g_GOSTR3410Curves[paramSet];
} }
// ГОСТ 34.11-2012 // ГОСТ 34.11-2012
static const uint64_t T0[256] = static const uint64_t T0[256] =
{ {
0xE6F87E5C5B711FD0, 0x258377800924FA16, 0xC849E07E852EA4A8, 0x5B4686A18F06C16A, 0xE6F87E5C5B711FD0, 0x258377800924FA16, 0xC849E07E852EA4A8, 0x5B4686A18F06C16A,
0x0B32E9A2D77B416E, 0xABDA37A467815C66, 0xF61796A81A686676, 0xF5DC0B706391954B, 0x0B32E9A2D77B416E, 0xABDA37A467815C66, 0xF61796A81A686676, 0xF5DC0B706391954B,
@ -246,7 +246,7 @@ namespace crypto
0x92BDE697D67F3422, 0xC78933E10514BC61, 0xE1C1D9B975C9B54A, 0xD2266160CF1BCD80, 0x92BDE697D67F3422, 0xC78933E10514BC61, 0xE1C1D9B975C9B54A, 0xD2266160CF1BCD80,
0x9A4492ED78FD8671, 0xB3CCAB2A881A9793, 0x72CEBF667FE1D088, 0xD6D45B5D985A9427 0x9A4492ED78FD8671, 0xB3CCAB2A881A9793, 0x72CEBF667FE1D088, 0xD6D45B5D985A9427
}; };
static const uint64_t T1[256] = static const uint64_t T1[256] =
{ {
0xC811A8058C3F55DE, 0x65F5B43196B50619, 0xF74F96B1D6706E43, 0x859D1E8BCB43D336, 0xC811A8058C3F55DE, 0x65F5B43196B50619, 0xF74F96B1D6706E43, 0x859D1E8BCB43D336,
0x5AAB8A85CCFA3D84, 0xF9C7BF99C295FCFD, 0xA21FD5A1DE4B630F, 0xCDB3EF763B8B456D, 0x5AAB8A85CCFA3D84, 0xF9C7BF99C295FCFD, 0xA21FD5A1DE4B630F, 0xCDB3EF763B8B456D,
@ -313,7 +313,7 @@ namespace crypto
0x57B69E77B57354A0, 0x3969441D8097D0B4, 0x3330CAFBF3E2F0CF, 0xE28E77DDE0BE8CC3, 0x57B69E77B57354A0, 0x3969441D8097D0B4, 0x3330CAFBF3E2F0CF, 0xE28E77DDE0BE8CC3,
0x62B12E259C494F46, 0xA6CE726FB9DBD1CA, 0x41E242C1EED14DBA, 0x76032FF47AA30FB0 0x62B12E259C494F46, 0xA6CE726FB9DBD1CA, 0x41E242C1EED14DBA, 0x76032FF47AA30FB0
}; };
static const uint64_t T2[256] = static const uint64_t T2[256] =
{ {
0x45B268A93ACDE4CC, 0xAF7F0BE884549D08, 0x048354B3C1468263, 0x925435C2C80EFED2, 0x45B268A93ACDE4CC, 0xAF7F0BE884549D08, 0x048354B3C1468263, 0x925435C2C80EFED2,
0xEE4E37F27FDFFBA7, 0x167A33920C60F14D, 0xFB123B52EA03E584, 0x4A0CAB53FDBB9007, 0xEE4E37F27FDFFBA7, 0x167A33920C60F14D, 0xFB123B52EA03E584, 0x4A0CAB53FDBB9007,
@ -380,7 +380,7 @@ namespace crypto
0xF9DD11850420A43B, 0x4BE5BEB68A243ED6, 0x5584255F19C8D65D, 0x3B67404E633FA006, 0xF9DD11850420A43B, 0x4BE5BEB68A243ED6, 0x5584255F19C8D65D, 0x3B67404E633FA006,
0xA68DB6766C472A1F, 0xF78AC79AB4C97E21, 0xC353442E1080AAEC, 0x9A4F9DB95782E714 0xA68DB6766C472A1F, 0xF78AC79AB4C97E21, 0xC353442E1080AAEC, 0x9A4F9DB95782E714
}; };
static const uint64_t T3[256] = static const uint64_t T3[256] =
{ {
0x05BA7BC82C9B3220, 0x31A54665F8B65E4F, 0xB1B651F77547F4D4, 0x8BFA0D857BA46682, 0x05BA7BC82C9B3220, 0x31A54665F8B65E4F, 0xB1B651F77547F4D4, 0x8BFA0D857BA46682,
0x85A96C5AA16A98BB, 0x990FAEF908EB79C9, 0xA15E37A247F4A62D, 0x76857DCD5D27741E, 0x85A96C5AA16A98BB, 0x990FAEF908EB79C9, 0xA15E37A247F4A62D, 0x76857DCD5D27741E,
@ -447,7 +447,7 @@ namespace crypto
0x77059157F359DC47, 0x1D262E3907FF492B, 0xFB582233E59AC557, 0xDDB2BCE242F8B673, 0x77059157F359DC47, 0x1D262E3907FF492B, 0xFB582233E59AC557, 0xDDB2BCE242F8B673,
0x2577B76248E096CF, 0x6F99C4A6D83DA74C, 0xC1147E41EB795701, 0xF48BAF76912A9337 0x2577B76248E096CF, 0x6F99C4A6D83DA74C, 0xC1147E41EB795701, 0xF48BAF76912A9337
}; };
static const uint64_t T4[256] = static const uint64_t T4[256] =
{ {
0x3EF29D249B2C0A19, 0xE9E16322B6F8622F, 0x5536994047757F7A, 0x9F4D56D5A47B0B33, 0x3EF29D249B2C0A19, 0xE9E16322B6F8622F, 0x5536994047757F7A, 0x9F4D56D5A47B0B33,
0x822567466AA1174C, 0xB8F5057DEB082FB2, 0xCC48C10BF4475F53, 0x373088D4275DEC3A, 0x822567466AA1174C, 0xB8F5057DEB082FB2, 0xCC48C10BF4475F53, 0x373088D4275DEC3A,
@ -514,7 +514,7 @@ namespace crypto
0x6853032B59F3EE6E, 0x65B3E9C4FF073AAA, 0x772AC3399AE5EBEC, 0x87816E97F842A75B, 0x6853032B59F3EE6E, 0x65B3E9C4FF073AAA, 0x772AC3399AE5EBEC, 0x87816E97F842A75B,
0x110E2DB2E0484A4B, 0x331277CB3DD8DEDD, 0xBD510CAC79EB9FA5, 0x352179552A91F5C7 0x110E2DB2E0484A4B, 0x331277CB3DD8DEDD, 0xBD510CAC79EB9FA5, 0x352179552A91F5C7
}; };
static const uint64_t T5[256] = static const uint64_t T5[256] =
{ {
0x8AB0A96846E06A6D, 0x43C7E80B4BF0B33A, 0x08C9B3546B161EE5, 0x39F1C235EBA990BE, 0x8AB0A96846E06A6D, 0x43C7E80B4BF0B33A, 0x08C9B3546B161EE5, 0x39F1C235EBA990BE,
0xC1BEF2376606C7B2, 0x2C209233614569AA, 0xEB01523B6FC3289A, 0x946953AB935ACEDD, 0xC1BEF2376606C7B2, 0x2C209233614569AA, 0xEB01523B6FC3289A, 0x946953AB935ACEDD,
@ -581,7 +581,7 @@ namespace crypto
0xEFEB8511D4C82766, 0x961CB6BE40D147A3, 0xAAB35F25F7B812DE, 0x76154E407044329D, 0xEFEB8511D4C82766, 0x961CB6BE40D147A3, 0xAAB35F25F7B812DE, 0x76154E407044329D,
0x513D76B64E570693, 0xF3479AC7D2F90AA8, 0x9B8B2E4477079C85, 0x297EB99D3D85AC69 0x513D76B64E570693, 0xF3479AC7D2F90AA8, 0x9B8B2E4477079C85, 0x297EB99D3D85AC69
}; };
static const uint64_t T6[256] = static const uint64_t T6[256] =
{ {
0x7E37E62DFC7D40C3, 0x776F25A4EE939E5B, 0xE045C850DD8FB5AD, 0x86ED5BA711FF1952, 0x7E37E62DFC7D40C3, 0x776F25A4EE939E5B, 0xE045C850DD8FB5AD, 0x86ED5BA711FF1952,
0xE91D0BD9CF616B35, 0x37E0AB256E408FFB, 0x9607F6C031025A7A, 0x0B02F5E116D23C9D, 0xE91D0BD9CF616B35, 0x37E0AB256E408FFB, 0x9607F6C031025A7A, 0x0B02F5E116D23C9D,
@ -648,7 +648,7 @@ namespace crypto
0xE6AB92E8D1CB8EA2, 0x3354C7F5663856F1, 0xD93EE170AF7BAE4D, 0x616BD27BC22AE67C, 0xE6AB92E8D1CB8EA2, 0x3354C7F5663856F1, 0xD93EE170AF7BAE4D, 0x616BD27BC22AE67C,
0x92B39A10397A8370, 0xABC8B3304B8E9890, 0xBF967287630B02B2, 0x5B67D607B6FC6E15 0x92B39A10397A8370, 0xABC8B3304B8E9890, 0xBF967287630B02B2, 0x5B67D607B6FC6E15
}; };
static uint64_t T7[256] = static uint64_t T7[256] =
{ {
0xD031C397CE553FE6, 0x16BA5B01B006B525, 0xA89BADE6296E70C8, 0x6A1F525D77D3435B, 0xD031C397CE553FE6, 0x16BA5B01B006B525, 0xA89BADE6296E70C8, 0x6A1F525D77D3435B,
0x6E103570573DFA0B, 0x660EFB2A17FC95AB, 0x76327A9E97634BF6, 0x4BAD9D6462458BF5, 0x6E103570573DFA0B, 0x660EFB2A17FC95AB, 0x76327A9E97634BF6, 0x4BAD9D6462458BF5,
@ -716,59 +716,59 @@ namespace crypto
0x717E7067AF4F499A, 0x938290A9ECD1DBB3, 0x88E3B293344DD172, 0x2734158C250FA3D6 0x717E7067AF4F499A, 0x938290A9ECD1DBB3, 0x88E3B293344DD172, 0x2734158C250FA3D6
}; };
static const uint64_t C_[12][8] = static const uint64_t C_[12][8] =
{ {
{ {
0xe9daca1eda5b08b1, 0x1f7c65c0812fcbeb, 0x16d0452e43766a2f, 0xfcc485758db84e71, 0xe9daca1eda5b08b1, 0x1f7c65c0812fcbeb, 0x16d0452e43766a2f, 0xfcc485758db84e71,
0x0169679291e07c4b, 0x15d360a4082a42a2, 0x234d74cc36747605, 0x0745a6f2596580dd 0x0169679291e07c4b, 0x15d360a4082a42a2, 0x234d74cc36747605, 0x0745a6f2596580dd
}, },
{ {
0x1a2f9da98ab5a36f, 0xd7b5700f469de34f, 0x982b230a72eafef3, 0x3101b5160f5ed561, 0x1a2f9da98ab5a36f, 0xd7b5700f469de34f, 0x982b230a72eafef3, 0x3101b5160f5ed561,
0x5899d6126b17b59a, 0xcaa70adbc261b55c, 0x56cdcbd71ba2dd55, 0xb79bb121700479e6 0x5899d6126b17b59a, 0xcaa70adbc261b55c, 0x56cdcbd71ba2dd55, 0xb79bb121700479e6
}, },
{ {
0xc72fce2bacdc74f5, 0x35843d6a28fc390a, 0x8b1f9c525f5ef106, 0x7b7b29b11475eaf2, 0xc72fce2bacdc74f5, 0x35843d6a28fc390a, 0x8b1f9c525f5ef106, 0x7b7b29b11475eaf2,
0xb19e3590e40fe2d3, 0x09db6260373ac9c1, 0x31db7a8643f4b6c2, 0xb20aba0af5961e99 0xb19e3590e40fe2d3, 0x09db6260373ac9c1, 0x31db7a8643f4b6c2, 0xb20aba0af5961e99
}, },
{ {
0xd26615e8b3df1fef, 0xdde4715da0e148f9, 0x7d3c5c337e858e48, 0x3f355e68ad1c729d, 0xd26615e8b3df1fef, 0xdde4715da0e148f9, 0x7d3c5c337e858e48, 0x3f355e68ad1c729d,
0x75d603ed822cd7a9, 0xbe0352933313b7d8, 0xf137e893a1ea5334, 0x2ed1e384bcbe0c22 0x75d603ed822cd7a9, 0xbe0352933313b7d8, 0xf137e893a1ea5334, 0x2ed1e384bcbe0c22
}, },
{ {
0x994747adac6bea4b, 0x6323a96c0c413f9a, 0x4a1086161f1c157f, 0xbdff0f80d7359e35, 0x994747adac6bea4b, 0x6323a96c0c413f9a, 0x4a1086161f1c157f, 0xbdff0f80d7359e35,
0xa3f53a254717cdbf, 0x161a2723b700ffdf, 0xf563eaa97ea2567a, 0x57fe6c7cfd581760 0xa3f53a254717cdbf, 0x161a2723b700ffdf, 0xf563eaa97ea2567a, 0x57fe6c7cfd581760
}, },
{ {
0xd9d33a1daeae4fae, 0xc039307a3bc3a46f, 0x6ca44251f9c4662d, 0xc68ef09ab49a7f18, 0xd9d33a1daeae4fae, 0xc039307a3bc3a46f, 0x6ca44251f9c4662d, 0xc68ef09ab49a7f18,
0xb4b79a1cb7a6facf, 0xb6c6bec2661ff20a, 0x354f903672c571bf, 0x6e7d64467a4068fa 0xb4b79a1cb7a6facf, 0xb6c6bec2661ff20a, 0x354f903672c571bf, 0x6e7d64467a4068fa
}, },
{ {
0xecc5aaee160ec7f4, 0x540924bffe86ac51, 0xc987bfe6c7c69e39, 0xc9937a19333e47d3, 0xecc5aaee160ec7f4, 0x540924bffe86ac51, 0xc987bfe6c7c69e39, 0xc9937a19333e47d3,
0x372c822dc5ab9209, 0x04054a2883694706, 0xf34a3ca24c451735, 0x93d4143a4d568688 0x372c822dc5ab9209, 0x04054a2883694706, 0xf34a3ca24c451735, 0x93d4143a4d568688
}, },
{ {
0xa7c9934d425b1f9b, 0x41416e0c02aae703, 0x1ede369c71f8b74e, 0x9ac4db4d3b44b489, 0xa7c9934d425b1f9b, 0x41416e0c02aae703, 0x1ede369c71f8b74e, 0x9ac4db4d3b44b489,
0x90069b92cb2b89f4, 0x2fc4a5d12b8dd169, 0xd9a8515935c2ac36, 0x1ee702bfd40d7fa4 0x90069b92cb2b89f4, 0x2fc4a5d12b8dd169, 0xd9a8515935c2ac36, 0x1ee702bfd40d7fa4
}, },
{ {
0x9b223116545a8f37, 0xde5f16ecd89a4c94, 0x244289251b3a7d3a, 0x84090de0b755d93c, 0x9b223116545a8f37, 0xde5f16ecd89a4c94, 0x244289251b3a7d3a, 0x84090de0b755d93c,
0xb1ceb2db0b440a80, 0x549c07a69a8a2b7b, 0x602a1fcb92dc380e, 0xdb5a238351446172 0xb1ceb2db0b440a80, 0x549c07a69a8a2b7b, 0x602a1fcb92dc380e, 0xdb5a238351446172
}, },
{ {
0x526f0580a6debeab, 0xf3f3e4b248e52a38, 0xdb788aff1ce74189, 0x0361331b8ae1ff1f, 0x526f0580a6debeab, 0xf3f3e4b248e52a38, 0xdb788aff1ce74189, 0x0361331b8ae1ff1f,
0x4b3369af0267e79f, 0xf452763b306c1e7a, 0xc3b63b15d1fa9836, 0xed9c4598fbc7b474 0x4b3369af0267e79f, 0xf452763b306c1e7a, 0xc3b63b15d1fa9836, 0xed9c4598fbc7b474
}, },
{ {
0xfb89c8efd09ecd7b, 0x94fe5a63cdc60230, 0x6107abebbb6bfad8, 0x7966841421800120, 0xfb89c8efd09ecd7b, 0x94fe5a63cdc60230, 0x6107abebbb6bfad8, 0x7966841421800120,
0xcab948eaef711d8a, 0x986e477d1dcdbaef, 0x5dd86fc04a59a2de, 0x1b2df381cda4ca6b 0xcab948eaef711d8a, 0x986e477d1dcdbaef, 0x5dd86fc04a59a2de, 0x1b2df381cda4ca6b
}, },
{ {
0xba3116f167e78e37, 0x7ab14904b08013d2, 0x771ddfbc323ca4cd, 0x9b9f2130d41220f8, 0xba3116f167e78e37, 0x7ab14904b08013d2, 0x771ddfbc323ca4cd, 0x9b9f2130d41220f8,
0x86cc91189def805d, 0x5228e188aaa41de7, 0x991bb2d9d517f4fa, 0x20d71bf14a92bc48 0x86cc91189def805d, 0x5228e188aaa41de7, 0x991bb2d9d517f4fa, 0x20d71bf14a92bc48
} }
}; };
union GOST3411Block // 8 bytes aligned union GOST3411Block // 8 bytes aligned
{ {
uint8_t buf[64]; uint8_t buf[64];
@ -780,15 +780,15 @@ namespace crypto
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
ret.ll[i] = ll[i]^other.ll[i]; ret.ll[i] = ll[i]^other.ll[i];
return ret; return ret;
} }
GOST3411Block operator^(const uint64_t * other) const GOST3411Block operator^(const uint64_t * other) const
{ {
GOST3411Block ret; GOST3411Block ret;
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
ret.ll[i] = ll[i]^other[i]; ret.ll[i] = ll[i]^other[i];
return ret; return ret;
} }
GOST3411Block operator+(const GOST3411Block& other) const GOST3411Block operator+(const GOST3411Block& other) const
{ {
@ -799,7 +799,7 @@ namespace crypto
uint16_t sum = buf[i] + other.buf[i] + carry; uint16_t sum = buf[i] + other.buf[i] + carry;
ret.buf[i] = sum; ret.buf[i] = sum;
carry = sum >> 8; carry = sum >> 8;
} }
return ret; return ret;
} }
@ -807,17 +807,17 @@ namespace crypto
{ {
for (int i = 63; i >= 0; i--) for (int i = 63; i >= 0; i--)
{ {
if (!c) return; if (!c) return;
c += buf[i]; c += buf[i];
buf[i] = c; buf[i] = c;
c >>= 8; c >>= 8;
} }
} }
void F () void F ()
{ {
uint64_t res[8]; uint64_t res[8];
for (int b=0; b<8; b++) for (int b=0; b<8; b++)
{ {
uint64_t r; uint64_t r;
r = T0[buf[b+56]]; r = T0[buf[b+56]];
@ -843,11 +843,11 @@ namespace crypto
k = k^C_[i]; k = k^C_[i];
k.F (); k.F ();
res = k^res; res = k^res;
} }
return res; return res;
} }
}; };
static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m) static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m)
{ {
GOST3411Block res = N ^ h; GOST3411Block res = N ^ h;
@ -855,12 +855,12 @@ namespace crypto
res = res.E (m); res = res.E (m);
res = res^h; res = res^h;
res = res^m; res = res^m;
return res; return res;
} }
static void H (const uint8_t * iv, const uint8_t * buf, size_t len, uint8_t * digest) static void H (const uint8_t * iv, const uint8_t * buf, size_t len, uint8_t * digest)
{ {
// stage 1 // stage 1
GOST3411Block h, N, s, m; GOST3411Block h, N, s, m;
memcpy (h.buf, iv, 64); memcpy (h.buf, iv, 64);
memset (N.buf, 0, 64); memset (N.buf, 0, 64);
@ -885,15 +885,15 @@ namespace crypto
memcpy (m.buf + padding, buf, l); memcpy (m.buf + padding, buf, l);
h = gN (N, h, m); h = gN (N, h, m);
N.Add (l*8); N.Add (l*8);
s = m + s; s = m + s;
GOST3411Block N0; GOST3411Block N0;
memset (N0.buf, 0, 64); memset (N0.buf, 0, 64);
h = gN (N0, h, N); h = gN (N0, h, N);
h = gN (N0, h, s); h = gN (N0, h, s);
memcpy (digest, h.buf, 64); memcpy (digest, h.buf, 64);
} }
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest) void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest)
@ -919,7 +919,7 @@ namespace crypto
size_t len; size_t len;
bool is512; bool is512;
}; };
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new () GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ()
{ {
return new GOSTR3411_2012_CTX; return new GOSTR3411_2012_CTX;
@ -949,7 +949,7 @@ namespace crypto
size_t l = 64 - ctx->len; size_t l = 64 - ctx->len;
if (len < l) l = len; if (len < l) l = len;
for (size_t i = 0; i < l; i++) for (size_t i = 0; i < l; i++)
ctx->m.buf[ctx->len + i] = buf[l-i-1]; // invert ctx->m.buf[ctx->len + i] = buf[l-i-1]; // invert
ctx->len += l; len -= l; buf += l; ctx->len += l; len -= l; buf += l;
ctx->h = gN (ctx->N, ctx->h, ctx->m); ctx->h = gN (ctx->N, ctx->h, ctx->m);
@ -959,7 +959,7 @@ namespace crypto
while (len >= 64) while (len >= 64)
{ {
for (size_t i = 0; i < 64; i++) for (size_t i = 0; i < 64; i++)
ctx->m.buf[i] = buf[63-i]; // invert ctx->m.buf[i] = buf[63-i]; // invert
len -= 64; buf += 64; len -= 64; buf += 64;
ctx->h = gN (ctx->N, ctx->h, ctx->m); ctx->h = gN (ctx->N, ctx->h, ctx->m);
ctx->N.Add (512); ctx->N.Add (512);
@ -975,7 +975,7 @@ namespace crypto
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx) void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx)
{ {
GOST3411Block m; GOST3411Block m;
size_t padding = 64 - ctx->len; size_t padding = 64 - ctx->len;
if (padding) if (padding)
{ {
@ -985,14 +985,14 @@ namespace crypto
memcpy (m.buf + padding, ctx->m.buf, ctx->len); memcpy (m.buf + padding, ctx->m.buf, ctx->len);
ctx->h = gN (ctx->N, ctx->h, m); ctx->h = gN (ctx->N, ctx->h, m);
ctx->N.Add (ctx->len*8); ctx->N.Add (ctx->len*8);
ctx->s = m + ctx->s; ctx->s = m + ctx->s;
GOST3411Block N0; GOST3411Block N0;
memset (N0.buf, 0, 64); memset (N0.buf, 0, 64);
ctx->h = gN (N0, ctx->h, ctx->N); ctx->h = gN (N0, ctx->h, ctx->N);
ctx->h = gN (N0, ctx->h, ctx->s); ctx->h = gN (N0, ctx->h, ctx->s);
size_t sz = ctx->is512 ? 64 : 32; size_t sz = ctx->is512 ? 64 : 32;
for (size_t i = 0; i < sz; i++) for (size_t i = 0; i < sz; i++)
digest[i] = ctx->h.buf[sz - i - 1]; digest[i] = ctx->h.buf[sz - i - 1];

View file

@ -10,25 +10,25 @@ namespace crypto
{ {
// ГОСТ Р 34.10 // ГОСТ Р 34.10
enum GOSTR3410ParamSet enum GOSTR3410ParamSet
{ {
eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1 eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1
// XchA = A, XchB = C // XchA = A, XchB = C
//eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0 //eGOSTR3410CryptoProXchA, // 1.2.643.2.2.36.0
//eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1 //eGOSTR3410CryptoProXchB, // 1.2.643.2.2.36.1
eGOSTR3410TC26A512, // 1.2.643.7.1.2.1.2.1 eGOSTR3410TC26A512, // 1.2.643.7.1.2.1.2.1
eGOSTR3410NumParamSets eGOSTR3410NumParamSets
}; };
class GOSTR3410Curve class GOSTR3410Curve
{ {
public: public:
GOSTR3410Curve (BIGNUM * a, BIGNUM * b, BIGNUM * p, BIGNUM * q, BIGNUM * x, BIGNUM * y); GOSTR3410Curve (BIGNUM * a, BIGNUM * b, BIGNUM * p, BIGNUM * q, BIGNUM * x, BIGNUM * y);
~GOSTR3410Curve (); ~GOSTR3410Curve ();
size_t GetKeyLen () const { return m_KeyLen; }; size_t GetKeyLen () const { return m_KeyLen; };
const EC_GROUP * GetGroup () const { return m_Group; }; const EC_GROUP * GetGroup () const { return m_Group; };
EC_POINT * MulP (const BIGNUM * n) const; EC_POINT * MulP (const BIGNUM * n) const;
bool GetXY (const EC_POINT * p, BIGNUM * x, BIGNUM * y) const; bool GetXY (const EC_POINT * p, BIGNUM * x, BIGNUM * y) const;
@ -36,7 +36,7 @@ namespace crypto
void Sign (const BIGNUM * priv, const BIGNUM * digest, BIGNUM * r, BIGNUM * s); void Sign (const BIGNUM * priv, const BIGNUM * digest, BIGNUM * r, BIGNUM * s);
bool Verify (const EC_POINT * pub, const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s); bool Verify (const EC_POINT * pub, const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s);
EC_POINT * RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY = false) const; EC_POINT * RecoverPublicKey (const BIGNUM * digest, const BIGNUM * r, const BIGNUM * s, bool isNegativeY = false) const;
private: private:
EC_GROUP * m_Group; EC_GROUP * m_Group;
@ -47,14 +47,14 @@ namespace crypto
// Big Endian // Big Endian
void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest); void GOSTR3411_2012_256 (const uint8_t * buf, size_t len, uint8_t * digest);
void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest); void GOSTR3411_2012_512 (const uint8_t * buf, size_t len, uint8_t * digest);
// Little Endian // Little Endian
struct GOSTR3411_2012_CTX; struct GOSTR3411_2012_CTX;
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new (); GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ();
void GOSTR3411_2012_CTX_Init (GOSTR3411_2012_CTX * ctx, bool is512 = true); void GOSTR3411_2012_CTX_Init (GOSTR3411_2012_CTX * ctx, bool is512 = true);
void GOSTR3411_2012_CTX_Update (const uint8_t * buf, size_t len, GOSTR3411_2012_CTX * ctx); void GOSTR3411_2012_CTX_Update (const uint8_t * buf, size_t len, GOSTR3411_2012_CTX * ctx);
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx); void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx);
void GOSTR3411_2012_CTX_free (GOSTR3411_2012_CTX * ctx); void GOSTR3411_2012_CTX_free (GOSTR3411_2012_CTX * ctx);
} }
} }

View file

@ -12,9 +12,9 @@
#include "Log.h" #include "Log.h"
#include "Gzip.h" #include "Gzip.h"
namespace i2p namespace i2p
{ {
namespace data namespace data
{ {
const size_t GZIP_CHUNK_SIZE = 16384; const size_t GZIP_CHUNK_SIZE = 16384;
@ -38,7 +38,7 @@ namespace data
m_Inflator.next_out = out; m_Inflator.next_out = out;
m_Inflator.avail_out = outLen; m_Inflator.avail_out = outLen;
int err; int err;
if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END)
return outLen - m_Inflator.avail_out; return outLen - m_Inflator.avail_out;
// else // else
LogPrint (eLogError, "Gzip: Inflate error ", err); LogPrint (eLogError, "Gzip: Inflate error ", err);
@ -52,19 +52,19 @@ namespace data
m_Inflator.next_in = const_cast<uint8_t *>(in); m_Inflator.next_in = const_cast<uint8_t *>(in);
m_Inflator.avail_in = inLen; m_Inflator.avail_in = inLen;
int ret; int ret;
do do
{ {
m_Inflator.next_out = out; m_Inflator.next_out = out;
m_Inflator.avail_out = GZIP_CHUNK_SIZE; m_Inflator.avail_out = GZIP_CHUNK_SIZE;
ret = inflate (&m_Inflator, Z_NO_FLUSH); ret = inflate (&m_Inflator, Z_NO_FLUSH);
if (ret < 0) if (ret < 0)
{ {
inflateEnd (&m_Inflator); inflateEnd (&m_Inflator);
os.setstate(std::ios_base::failbit); os.setstate(std::ios_base::failbit);
break; break;
} }
os.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); os.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
} }
while (!m_Inflator.avail_out); // more data to read while (!m_Inflator.avail_out); // more data to read
delete[] out; delete[] out;
} }
@ -105,7 +105,7 @@ namespace data
m_Deflator.next_out = out; m_Deflator.next_out = out;
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)
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);

View file

@ -44,7 +44,7 @@ namespace http {
} }
} }
static std::pair<std::string, std::string> parse_header_line(const std::string& line) static std::pair<std::string, std::string> parse_header_line(const std::string& line)
{ {
std::size_t pos = 0; std::size_t pos = 0;
std::size_t len = 2; /* strlen(": ") */ std::size_t len = 2; /* strlen(": ") */
@ -251,14 +251,14 @@ namespace http {
uri = tokens[1]; uri = tokens[1];
version = tokens[2]; version = tokens[2];
expect = HEADER_LINE; expect = HEADER_LINE;
} }
else else
{ {
std::string line = str.substr(pos, eol - pos); std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
if (p.first.length () > 0) if (p.first.length () > 0)
headers.push_back (p); headers.push_back (p);
else else
return -1; return -1;
} }
pos = eol + strlen(CRLF); pos = eol + strlen(CRLF);
@ -268,11 +268,11 @@ namespace http {
return eoh + strlen(HTTP_EOH); return eoh + strlen(HTTP_EOH);
} }
void HTTPReq::write(std::ostream & o) void HTTPReq::write(std::ostream & o)
{ {
o << method << " " << uri << " " << version << CRLF; o << method << " " << uri << " " << version << CRLF;
for (auto & h : headers) for (auto & h : headers)
o << h.first << ": " << h.second << CRLF; o << h.first << ": " << h.second << CRLF;
o << CRLF; o << CRLF;
} }
@ -284,7 +284,7 @@ namespace http {
} }
void HTTPReq::AddHeader (const std::string& name, const std::string& value) void HTTPReq::AddHeader (const std::string& name, const std::string& value)
{ {
headers.push_back (std::make_pair(name, value)); headers.push_back (std::make_pair(name, value));
} }
@ -295,28 +295,28 @@ namespace http {
{ {
it.second = value; it.second = value;
break; break;
} }
} }
void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt) void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt)
{ {
for (auto it = headers.begin (); it != headers.end ();) for (auto it = headers.begin (); it != headers.end ();)
{ {
if (!it->first.compare(0, name.length (), name) && it->first != exempt) if (!it->first.compare(0, name.length (), name) && it->first != exempt)
it = headers.erase (it); it = headers.erase (it);
else else
it++; it++;
} }
} }
std::string HTTPReq::GetHeader (const std::string& name) const std::string HTTPReq::GetHeader (const std::string& name) const
{ {
for (auto& it : headers) for (auto& it : headers)
if (it.first == name) if (it.first == name)
return it.second; return it.second;
return ""; return "";
} }
bool HTTPRes::is_chunked() const bool HTTPRes::is_chunked() const
{ {
auto it = headers.find("Transfer-Encoding"); auto it = headers.find("Transfer-Encoding");
@ -335,10 +335,10 @@ namespace http {
if (it->second.find("gzip") != std::string::npos) if (it->second.find("gzip") != std::string::npos)
return true; /* gotcha! */ return true; /* gotcha! */
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos) if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
return true; return true;
return false; return false;
} }
long int HTTPMsg::content_length() const long int HTTPMsg::content_length() const
{ {
unsigned long int length = 0; unsigned long int length = 0;
@ -385,8 +385,8 @@ namespace http {
std::string line = str.substr(pos, eol - pos); std::string line = str.substr(pos, eol - pos);
auto p = parse_header_line(line); auto p = parse_header_line(line);
if (p.first.length () > 0) if (p.first.length () > 0)
headers.insert (p); headers.insert (p);
else else
return -1; return -1;
} }
pos = eol + strlen(CRLF); pos = eol + strlen(CRLF);

View file

@ -16,16 +16,16 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace i2p namespace i2p
{ {
namespace http namespace http
{ {
const char CRLF[] = "\r\n"; /**< HTTP line terminator */ const char CRLF[] = "\r\n"; /**< HTTP line terminator */
const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */ const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */
extern const std::vector<std::string> HTTP_METHODS; /**< list of valid HTTP methods */ extern const std::vector<std::string> HTTP_METHODS; /**< list of valid HTTP methods */
extern const std::vector<std::string> HTTP_VERSIONS; /**< list of valid HTTP versions */ extern const std::vector<std::string> HTTP_VERSIONS; /**< list of valid HTTP versions */
struct URL struct URL
{ {
std::string schema; std::string schema;
std::string user; std::string user;
@ -63,7 +63,7 @@ namespace http
bool is_i2p() const; bool is_i2p() const;
}; };
struct HTTPMsg struct HTTPMsg
{ {
std::map<std::string, std::string> headers; std::map<std::string, std::string> headers;
@ -75,9 +75,9 @@ namespace http
long int content_length() const; long int content_length() const;
}; };
struct HTTPReq struct HTTPReq
{ {
std::list<std::pair<std::string, std::string> > headers; std::list<std::pair<std::string, std::string> > headers;
std::string version; std::string version;
std::string method; std::string method;
std::string uri; std::string uri;
@ -97,10 +97,10 @@ namespace http
void write(std::ostream & o); void write(std::ostream & o);
void AddHeader (const std::string& name, const std::string& value); void AddHeader (const std::string& name, const std::string& value);
void UpdateHeader (const std::string& name, const std::string& value); void UpdateHeader (const std::string& name, const std::string& value);
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt
void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); }; void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); };
std::string GetHeader (const std::string& name) const; std::string GetHeader (const std::string& name) const;
}; };
struct HTTPRes : HTTPMsg { struct HTTPRes : HTTPMsg {

View file

@ -21,7 +21,7 @@ namespace i2p
{ {
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >(); return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >();
} }
std::shared_ptr<I2NPMessage> NewI2NPShortMessage () std::shared_ptr<I2NPMessage> NewI2NPShortMessage ()
{ {
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >(); return std::make_shared<I2NPMessageBuffer<I2NP_MAX_SHORT_MESSAGE_SIZE> >();
@ -32,38 +32,38 @@ namespace i2p
auto msg = new I2NPMessageBuffer<i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34>(); // reserved for alignment and NTCP 16 + 6 + 12 auto msg = new I2NPMessageBuffer<i2p::tunnel::TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE + 34>(); // reserved for alignment and NTCP 16 + 6 + 12
msg->Align (12); msg->Align (12);
return std::shared_ptr<I2NPMessage>(msg); return std::shared_ptr<I2NPMessage>(msg);
} }
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len) std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
{ {
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage (); return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage ();
} }
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID) void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID)
{ {
SetTypeID (msgType); SetTypeID (msgType);
if (!replyMsgID) RAND_bytes ((uint8_t *)&replyMsgID, 4); if (!replyMsgID) RAND_bytes ((uint8_t *)&replyMsgID, 4);
SetMsgID (replyMsgID); SetMsgID (replyMsgID);
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT); SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
UpdateSize (); UpdateSize ();
UpdateChks (); UpdateChks ();
} }
void I2NPMessage::RenewI2NPMessageHeader () void I2NPMessage::RenewI2NPMessageHeader ()
{ {
uint32_t msgID; uint32_t msgID;
RAND_bytes ((uint8_t *)&msgID, 4); RAND_bytes ((uint8_t *)&msgID, 4);
SetMsgID (msgID); SetMsgID (msgID);
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT); SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
} }
bool I2NPMessage::IsExpired () const bool I2NPMessage::IsExpired () const
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
auto exp = GetExpiration (); auto exp = GetExpiration ();
return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future return (ts > exp + I2NP_MESSAGE_CLOCK_SKEW) || (ts < exp - 3*I2NP_MESSAGE_CLOCK_SKEW); // check if expired or too far in future
} }
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID) std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
{ {
auto msg = NewI2NPMessage (len); auto msg = NewI2NPMessage (len);
@ -71,7 +71,7 @@ namespace i2p
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen); LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen);
msg->FillI2NPMessageHeader (msgType, replyMsgID); msg->FillI2NPMessageHeader (msgType, replyMsgID);
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from) std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from)
{ {
@ -85,7 +85,7 @@ namespace i2p
else else
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length"); LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length");
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg) std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg)
{ {
@ -94,8 +94,8 @@ namespace i2p
newMsg->offset = msg->offset; newMsg->offset = msg->offset;
*newMsg = *msg; *newMsg = *msg;
return newMsg; return newMsg;
} }
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID) std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
{ {
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
@ -109,14 +109,14 @@ namespace i2p
{ {
RAND_bytes ((uint8_t *)&msgID, 4); RAND_bytes ((uint8_t *)&msgID, 4);
htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID); htobe32buf (buf + DELIVERY_STATUS_MSGID_OFFSET, msgID);
htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::context.GetNetID ()); htobe64buf (buf + DELIVERY_STATUS_TIMESTAMP_OFFSET, i2p::context.GetNetID ());
} }
m->len += DELIVERY_STATUS_SIZE; m->len += DELIVERY_STATUS_SIZE;
m->FillI2NPMessageHeader (eI2NPDeliveryStatus); m->FillI2NPMessageHeader (eI2NPDeliveryStatus);
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers) uint32_t replyTunnelID, bool exploratory, std::set<i2p::data::IdentHash> * excludedPeers)
{ {
auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage (); auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
@ -125,7 +125,7 @@ namespace i2p
buf += 32; buf += 32;
memcpy (buf, from, 32); // from memcpy (buf, from, 32); // from
buf += 32; buf += 32;
uint8_t flag = exploratory ? DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP : DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP; uint8_t flag = exploratory ? DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP : DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP;
if (replyTunnelID) if (replyTunnelID)
{ {
*buf = flag | DATABASE_LOOKUP_DELIVERY_FLAG; // set delivery flag *buf = flag | DATABASE_LOOKUP_DELIVERY_FLAG; // set delivery flag
@ -133,11 +133,11 @@ namespace i2p
buf += 5; buf += 5;
} }
else else
{ {
*buf = flag; // flag *buf = flag; // flag
buf++; buf++;
} }
if (excludedPeers) if (excludedPeers)
{ {
int cnt = excludedPeers->size (); int cnt = excludedPeers->size ();
@ -147,21 +147,21 @@ namespace i2p
{ {
memcpy (buf, it, 32); memcpy (buf, it, 32);
buf += 32; buf += 32;
} }
} }
else else
{ {
// nothing to exclude // nothing to exclude
htobuf16 (buf, 0); htobuf16 (buf, 0);
buf += 2; buf += 2;
} }
m->len += (buf - m->GetPayload ());
m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m;
}
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, m->len += (buf - m->GetPayload ());
m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m;
}
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag) std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
{ {
@ -176,7 +176,7 @@ namespace i2p
buf ++; buf ++;
htobe32buf (buf, replyTunnel->GetNextTunnelID ()); // reply tunnel ID htobe32buf (buf, replyTunnel->GetNextTunnelID ()); // reply tunnel ID
buf += 4; buf += 4;
// excluded // excluded
htobe16buf (buf, cnt); htobe16buf (buf, cnt);
buf += 2; buf += 2;
@ -187,19 +187,19 @@ namespace i2p
memcpy (buf, it, 32); memcpy (buf, it, 32);
buf += 32; buf += 32;
} }
} }
// encryption // encryption
memcpy (buf, replyKey, 32); memcpy (buf, replyKey, 32);
buf[32] = uint8_t( 1 ); // 1 tag buf[32] = uint8_t( 1 ); // 1 tag
memcpy (buf + 33, replyTag, 32); memcpy (buf + 33, replyTag, 32);
buf += 65; buf += 65;
m->len += (buf - m->GetPayload ()); m->len += (buf - m->GetPayload ());
m->FillI2NPMessageHeader (eI2NPDatabaseLookup); m->FillI2NPMessageHeader (eI2NPDatabaseLookup);
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident,
std::vector<i2p::data::IdentHash> routers) std::vector<i2p::data::IdentHash> routers)
{ {
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
@ -207,27 +207,27 @@ namespace i2p
size_t len = 0; size_t len = 0;
memcpy (buf, ident, 32); memcpy (buf, ident, 32);
len += 32; len += 32;
buf[len] = routers.size (); buf[len] = routers.size ();
len++; len++;
for (const auto& it: routers) for (const auto& it: routers)
{ {
memcpy (buf + len, it, 32); memcpy (buf + len, it, 32);
len += 32; len += 32;
} }
memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32); memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
len += 32; len += 32;
m->len += len; m->len += len;
m->FillI2NPMessageHeader (eI2NPDatabaseSearchReply); m->FillI2NPMessageHeader (eI2NPDatabaseSearchReply);
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router, uint32_t replyToken) std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router, uint32_t replyToken)
{ {
if (!router) // we send own RouterInfo if (!router) // we send own RouterInfo
router = context.GetSharedRouterInfo (); router = context.GetSharedRouterInfo ();
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload (); uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, router->GetIdentHash (), 32); memcpy (payload + DATABASE_STORE_KEY_OFFSET, router->GetIdentHash (), 32);
payload[DATABASE_STORE_TYPE_OFFSET] = 0; // RouterInfo payload[DATABASE_STORE_TYPE_OFFSET] = 0; // RouterInfo
@ -239,7 +239,7 @@ namespace i2p
buf += 4; buf += 4;
memcpy (buf, router->GetIdentHash (), 32); memcpy (buf, router->GetIdentHash (), 32);
buf += 32; buf += 32;
} }
uint8_t * sizePtr = buf; uint8_t * sizePtr = buf;
buf += 2; buf += 2;
@ -247,22 +247,22 @@ namespace i2p
i2p::data::GzipDeflator deflator; i2p::data::GzipDeflator deflator;
size_t size = deflator.Deflate (router->GetBuffer (), router->GetBufferLen (), buf, m->maxLen -m->len); size_t size = deflator.Deflate (router->GetBuffer (), router->GetBufferLen (), buf, m->maxLen -m->len);
if (size) if (size)
{ {
htobe16buf (sizePtr, size); // size htobe16buf (sizePtr, size); // size
m->len += size; m->len += size;
} }
else else
m = nullptr; m = nullptr;
if (m) if (m)
m->FillI2NPMessageHeader (eI2NPDatabaseStore); m->FillI2NPMessageHeader (eI2NPDatabaseStore);
return m; return m;
} }
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet) std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
{ {
if (!leaseSet) return nullptr; if (!leaseSet) return nullptr;
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload (); uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32); memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0); htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
@ -278,7 +278,7 @@ namespace i2p
{ {
if (!leaseSet) return nullptr; if (!leaseSet) return nullptr;
auto m = NewI2NPShortMessage (); auto m = NewI2NPShortMessage ();
uint8_t * payload = m->GetPayload (); uint8_t * payload = m->GetPayload ();
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32); memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken); htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
@ -306,8 +306,8 @@ namespace i2p
{ {
if (!msg || msg->GetTypeID () != eI2NPDatabaseStore) return false; if (!msg || msg->GetTypeID () != eI2NPDatabaseStore) return false;
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
} }
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO: static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels) void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
{ {
@ -321,37 +321,37 @@ namespace i2p
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText) bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
{ {
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{ {
uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE; uint8_t * record = records + i*TUNNEL_BUILD_RECORD_SIZE;
if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16)) if (!memcmp (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)i2p::context.GetRouterInfo ().GetIdentHash (), 16))
{ {
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours"); LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
// replace record to reply // replace record to reply
if (i2p::context.AcceptsTunnels () && if (i2p::context.AcceptsTunnels () &&
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels && i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
!i2p::transport::transports.IsBandwidthExceeded () && !i2p::transport::transports.IsBandwidthExceeded () &&
!i2p::transport::transports.IsTransitBandwidthExceeded ()) !i2p::transport::transports.IsTransitBandwidthExceeded ())
{ {
auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80, clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40); clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40);
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0; record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0;
} }
else else
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30) record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30)
//TODO: fill filler //TODO: fill filler
SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret
record + BUILD_RESPONSE_RECORD_HASH_OFFSET); record + BUILD_RESPONSE_RECORD_HASH_OFFSET);
// encrypt reply // encrypt reply
i2p::crypto::CBCEncryption encryption; i2p::crypto::CBCEncryption encryption;
for (int j = 0; j < num; j++) for (int j = 0; j < num; j++)
@ -359,23 +359,23 @@ namespace i2p
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE; uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
} }
return true; return true;
} }
} }
return false; return false;
} }
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{ {
int num = buf[0]; int num = buf[0];
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records"); LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1) if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1)
{ {
LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len); LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len);
return; return;
} }
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID); auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
if (tunnel) if (tunnel)
@ -385,34 +385,34 @@ namespace i2p
if (tunnel->HandleTunnelBuildResponse (buf, len)) if (tunnel->HandleTunnelBuildResponse (buf, len))
{ {
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created"); LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been created");
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished); tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddInboundTunnel (tunnel); i2p::tunnel::tunnels.AddInboundTunnel (tunnel);
} }
else else
{ {
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined"); LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
} }
} }
else else
{ {
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (HandleBuildRequestRecords (num, buf + 1, clearText)) if (HandleBuildRequestRecords (num, buf + 1, clearText))
{ {
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel
{ {
// so we send it to reply tunnel // so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPVariableTunnelBuildReply, buf, len, eI2NPVariableTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
} }
else else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
} }
} }
} }
void HandleTunnelBuildMsg (uint8_t * buf, size_t len) void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
@ -421,51 +421,51 @@ namespace i2p
{ {
LogPrint (eLogError, "TunnelBuild message is too short ", len); LogPrint (eLogError, "TunnelBuild message is too short ", len);
return; return;
} }
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, buf, clearText)) if (HandleBuildRequestRecords (NUM_TUNNEL_BUILD_RECORDS, buf, clearText))
{ {
if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outbound tunnel if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outbound tunnel
{ {
// so we send it to reply tunnel // so we send it to reply tunnel
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
eI2NPTunnelBuildReply, buf, len, eI2NPTunnelBuildReply, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
} }
else else
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
CreateI2NPMessage (eI2NPTunnelBuild, buf, len, CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
} }
} }
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len) void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
{ {
int num = buf[0]; int num = buf[0];
LogPrint (eLogDebug, "I2NP: VariableTunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID); LogPrint (eLogDebug, "I2NP: VariableTunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1) if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1)
{ {
LogPrint (eLogError, "VaribleTunnelBuildReply message of ", num, " records is too short ", len); LogPrint (eLogError, "VaribleTunnelBuildReply message of ", num, " records is too short ", len);
return; return;
} }
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID); auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID);
if (tunnel) if (tunnel)
{ {
// reply for outbound tunnel // reply for outbound tunnel
if (tunnel->HandleTunnelBuildResponse (buf, len)) if (tunnel->HandleTunnelBuildResponse (buf, len))
{ {
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created"); LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been created");
tunnel->SetState (i2p::tunnel::eTunnelStateEstablished); tunnel->SetState (i2p::tunnel::eTunnelStateEstablished);
i2p::tunnel::tunnels.AddOutboundTunnel (tunnel); i2p::tunnel::tunnels.AddOutboundTunnel (tunnel);
} }
else else
{ {
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined"); LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed); tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
} }
} }
else else
LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found"); LogPrint (eLogWarning, "I2NP: Pending tunnel for message ", replyMsgID, " not found");
} }
@ -474,12 +474,12 @@ namespace i2p
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf) std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf)
{ {
auto msg = NewI2NPTunnelMessage (); auto msg = NewI2NPTunnelMessage ();
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE); msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
msg->FillI2NPMessageHeader (eI2NPTunnelData); msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload) std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload)
{ {
auto msg = NewI2NPTunnelMessage (); auto msg = NewI2NPTunnelMessage ();
htobe32buf (msg->GetPayload (), tunnelID); htobe32buf (msg->GetPayload (), tunnelID);
@ -487,15 +487,15 @@ namespace i2p
msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4); msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
msg->FillI2NPMessageHeader (eI2NPTunnelData); msg->FillI2NPMessageHeader (eI2NPTunnelData);
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg () std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ()
{ {
auto msg = NewI2NPTunnelMessage (); auto msg = NewI2NPTunnelMessage ();
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE; msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len) std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
{ {
auto msg = NewI2NPMessage (len); auto msg = NewI2NPMessage (len);
@ -504,10 +504,10 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->len += TUNNEL_GATEWAY_HEADER_SIZE; msg->len += TUNNEL_GATEWAY_HEADER_SIZE;
if (msg->Concat (buf, len) < len) if (msg->Concat (buf, len) < len)
LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen); LogPrint (eLogError, "I2NP: tunnel gateway buffer overflow ", msg->maxLen);
msg->FillI2NPMessageHeader (eI2NPTunnelGateway); msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg) std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg)
{ {
@ -520,14 +520,14 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->offset -= (I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE); msg->offset -= (I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE);
msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE +len; msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE +len;
msg->FillI2NPMessageHeader (eI2NPTunnelGateway); msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
return msg; return msg;
} }
else else
return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ()); return CreateTunnelGatewayMsg (tunnelID, msg->GetBuffer (), msg->GetLength ());
} }
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID) const uint8_t * buf, size_t len, uint32_t replyMsgID)
{ {
auto msg = NewI2NPMessage (len); auto msg = NewI2NPMessage (len);
@ -544,7 +544,7 @@ namespace i2p
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len); htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
msg->FillI2NPMessageHeader (eI2NPTunnelGateway); // gateway message msg->FillI2NPMessageHeader (eI2NPTunnelGateway); // gateway message
return msg; return msg;
} }
size_t GetI2NPMessageLength (const uint8_t * msg, size_t len) size_t GetI2NPMessageLength (const uint8_t * msg, size_t len)
{ {
@ -552,25 +552,25 @@ namespace i2p
{ {
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header"); LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header");
return len; return len;
} }
auto l = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE; auto l = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE;
if (l > len) if (l > len)
{ {
LogPrint (eLogError, "I2NP: message length ", l, " exceeds buffer length ", len); LogPrint (eLogError, "I2NP: message length ", l, " exceeds buffer length ", len);
l = len; l = len;
} }
return l; return l;
} }
void HandleI2NPMessage (uint8_t * msg, size_t len) void HandleI2NPMessage (uint8_t * msg, size_t len)
{ {
if (len < I2NP_HEADER_SIZE) if (len < I2NP_HEADER_SIZE)
{ {
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header"); LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header");
return; return;
} }
uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET]; uint8_t typeID = msg[I2NP_HEADER_TYPEID_OFFSET];
uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET); uint32_t msgID = bufbe32toh (msg + I2NP_HEADER_MSGID_OFFSET);
LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID); LogPrint (eLogDebug, "I2NP: msg received len=", len,", type=", (int)typeID, ", msgID=", (unsigned int)msgID);
uint8_t * buf = msg + I2NP_HEADER_SIZE; uint8_t * buf = msg + I2NP_HEADER_SIZE;
auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET); auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
@ -581,35 +581,35 @@ namespace i2p
size = len; size = len;
} }
switch (typeID) switch (typeID)
{ {
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
HandleVariableTunnelBuildMsg (msgID, buf, size); HandleVariableTunnelBuildMsg (msgID, buf, size);
break; break;
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
HandleVariableTunnelBuildReplyMsg (msgID, buf, size); HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
break; break;
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
HandleTunnelBuildMsg (buf, size); HandleTunnelBuildMsg (buf, size);
break; break;
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
// TODO: // TODO:
break; break;
default: default:
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID); LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
} }
} }
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg) void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (msg) if (msg)
{ {
uint8_t typeID = msg->GetTypeID (); uint8_t typeID = msg->GetTypeID ();
LogPrint (eLogDebug, "I2NP: Handling message with type ", (int)typeID); LogPrint (eLogDebug, "I2NP: Handling message with type ", (int)typeID);
switch (typeID) switch (typeID)
{ {
case eI2NPTunnelData: case eI2NPTunnelData:
i2p::tunnel::tunnels.PostTunnelData (msg); i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;
case eI2NPTunnelGateway: case eI2NPTunnelGateway:
i2p::tunnel::tunnels.PostTunnelData (msg); i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;
@ -623,7 +623,7 @@ namespace i2p
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore"); LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
} }
else else
i2p::context.ProcessGarlicMessage (msg); i2p::context.ProcessGarlicMessage (msg);
break; break;
} }
case eI2NPDatabaseStore: case eI2NPDatabaseStore:
@ -638,55 +638,55 @@ namespace i2p
msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg); msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg);
else else
i2p::context.ProcessDeliveryStatusMessage (msg); i2p::context.ProcessDeliveryStatusMessage (msg);
break; break;
} }
case eI2NPVariableTunnelBuild: case eI2NPVariableTunnelBuild:
case eI2NPVariableTunnelBuildReply: case eI2NPVariableTunnelBuildReply:
case eI2NPTunnelBuild: case eI2NPTunnelBuild:
case eI2NPTunnelBuildReply: case eI2NPTunnelBuildReply:
// forward to tunnel thread // forward to tunnel thread
i2p::tunnel::tunnels.PostTunnelData (msg); i2p::tunnel::tunnels.PostTunnelData (msg);
break; break;
default: default:
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
} }
} }
} }
I2NPMessagesHandler::~I2NPMessagesHandler () I2NPMessagesHandler::~I2NPMessagesHandler ()
{ {
Flush (); Flush ();
} }
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg) void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg)
{ {
if (msg) if (msg)
{ {
switch (msg->GetTypeID ()) switch (msg->GetTypeID ())
{ {
case eI2NPTunnelData: case eI2NPTunnelData:
m_TunnelMsgs.push_back (msg); m_TunnelMsgs.push_back (msg);
break; break;
case eI2NPTunnelGateway: case eI2NPTunnelGateway:
m_TunnelGatewayMsgs.push_back (msg); m_TunnelGatewayMsgs.push_back (msg);
break; break;
default: default:
HandleI2NPMessage (msg); HandleI2NPMessage (msg);
} }
} }
} }
void I2NPMessagesHandler::Flush () void I2NPMessagesHandler::Flush ()
{ {
if (!m_TunnelMsgs.empty ()) if (!m_TunnelMsgs.empty ())
{ {
i2p::tunnel::tunnels.PostTunnelData (m_TunnelMsgs); i2p::tunnel::tunnels.PostTunnelData (m_TunnelMsgs);
m_TunnelMsgs.clear (); m_TunnelMsgs.clear ();
} }
if (!m_TunnelGatewayMsgs.empty ()) if (!m_TunnelGatewayMsgs.empty ())
{ {
i2p::tunnel::tunnels.PostTunnelData (m_TunnelGatewayMsgs); i2p::tunnel::tunnels.PostTunnelData (m_TunnelGatewayMsgs);
m_TunnelGatewayMsgs.clear (); m_TunnelGatewayMsgs.clear ();
} }
} }
} }

View file

@ -12,7 +12,7 @@
#include "LeaseSet.h" #include "LeaseSet.h"
namespace i2p namespace i2p
{ {
// I2NP header // I2NP header
const size_t I2NP_HEADER_TYPEID_OFFSET = 0; const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1; const size_t I2NP_HEADER_MSGID_OFFSET = I2NP_HEADER_TYPEID_OFFSET + 1;
@ -25,13 +25,13 @@ namespace i2p
const size_t I2NP_SHORT_HEADER_TYPEID_OFFSET = 0; const size_t I2NP_SHORT_HEADER_TYPEID_OFFSET = 0;
const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1; const size_t I2NP_SHORT_HEADER_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1;
const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4; const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4;
// Tunnel Gateway header // Tunnel Gateway header
const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0; const size_t TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET = 0;
const size_t TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4; const size_t TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET = TUNNEL_GATEWAY_HEADER_TUNNELID_OFFSET + 4;
const size_t TUNNEL_GATEWAY_HEADER_SIZE = TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET + 2; const size_t TUNNEL_GATEWAY_HEADER_SIZE = TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET + 2;
// DeliveryStatus // DeliveryStatus
const size_t DELIVERY_STATUS_MSGID_OFFSET = 0; const size_t DELIVERY_STATUS_MSGID_OFFSET = 0;
const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4; const size_t DELIVERY_STATUS_TIMESTAMP_OFFSET = DELIVERY_STATUS_MSGID_OFFSET + 4;
const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8; const size_t DELIVERY_STATUS_SIZE = DELIVERY_STATUS_TIMESTAMP_OFFSET + 8;
@ -42,7 +42,7 @@ namespace i2p
const size_t DATABASE_STORE_REPLY_TOKEN_OFFSET = DATABASE_STORE_TYPE_OFFSET + 1; const size_t DATABASE_STORE_REPLY_TOKEN_OFFSET = DATABASE_STORE_TYPE_OFFSET + 1;
const size_t DATABASE_STORE_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4; const size_t DATABASE_STORE_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4;
// TunnelBuild // TunnelBuild
const size_t TUNNEL_BUILD_RECORD_SIZE = 528; const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
//BuildRequestRecordClearText //BuildRequestRecordClearText
@ -59,11 +59,11 @@ namespace i2p
const size_t BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4; const size_t BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET = BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET + 4;
const size_t BUILD_REQUEST_RECORD_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4; const size_t BUILD_REQUEST_RECORD_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
const size_t BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 222; const size_t BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 222;
// BuildRequestRecordEncrypted // BuildRequestRecordEncrypted
const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0; const size_t BUILD_REQUEST_RECORD_TO_PEER_OFFSET = 0;
const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16; const size_t BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
// BuildResponseRecord // BuildResponseRecord
const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0; const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0;
const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32; const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32;
@ -83,40 +83,40 @@ namespace i2p
eI2NPTunnelBuild = 21, eI2NPTunnelBuild = 21,
eI2NPTunnelBuildReply = 22, eI2NPTunnelBuildReply = 22,
eI2NPVariableTunnelBuild = 23, eI2NPVariableTunnelBuild = 23,
eI2NPVariableTunnelBuildReply = 24 eI2NPVariableTunnelBuildReply = 24
}; };
const int NUM_TUNNEL_BUILD_RECORDS = 8; const int NUM_TUNNEL_BUILD_RECORDS = 8;
// DatabaseLookup flags // DatabaseLookup flags
const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01; const uint8_t DATABASE_LOOKUP_DELIVERY_FLAG = 0x01;
const uint8_t DATABASE_LOOKUP_ENCRYPTION_FLAG = 0x02; const uint8_t DATABASE_LOOKUP_ENCRYPTION_FLAG = 0x02;
const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C; const uint8_t DATABASE_LOOKUP_TYPE_FLAGS_MASK = 0x0C;
const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0; const uint8_t DATABASE_LOOKUP_TYPE_NORMAL_LOOKUP = 0;
const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100 const uint8_t DATABASE_LOOKUP_TYPE_LEASESET_LOOKUP = 0x04; // 0100
const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000 const uint8_t DATABASE_LOOKUP_TYPE_ROUTERINFO_LOOKUP = 0x08; // 1000
const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100 const uint8_t DATABASE_LOOKUP_TYPE_EXPLORATORY_LOOKUP = 0x0C; // 1100
namespace tunnel namespace tunnel
{ {
class InboundTunnel; class InboundTunnel;
class TunnelPool; class TunnelPool;
} }
const size_t I2NP_MAX_MESSAGE_SIZE = 32768; const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096; const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT) const unsigned int I2NP_MESSAGE_EXPIRATION_TIMEOUT = 8000; // in milliseconds (as initial RTT)
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
struct I2NPMessage struct I2NPMessage
{ {
uint8_t * buf; uint8_t * buf;
size_t len, offset, maxLen; size_t len, offset, maxLen;
std::shared_ptr<i2p::tunnel::InboundTunnel> from; std::shared_ptr<i2p::tunnel::InboundTunnel> from;
I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2), I2NPMessage (): buf (nullptr),len (I2NP_HEADER_SIZE + 2),
offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header offset(2), maxLen (0), from (nullptr) {}; // reserve 2 bytes for NTCP header
// header accessors // header accessors
uint8_t * GetHeader () { return GetBuffer (); }; uint8_t * GetHeader () { return GetBuffer (); };
const uint8_t * GetHeader () const { return GetBuffer (); }; const uint8_t * GetHeader () const { return GetBuffer (); };
@ -128,24 +128,24 @@ namespace tunnel
uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); }; uint64_t GetExpiration () const { return bufbe64toh (GetHeader () + I2NP_HEADER_EXPIRATION_OFFSET); };
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); }; void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); }; uint16_t GetSize () const { return bufbe16toh (GetHeader () + I2NP_HEADER_SIZE_OFFSET); };
void UpdateSize () { SetSize (GetPayloadLength ()); }; void UpdateSize () { SetSize (GetPayloadLength ()); };
void SetChks (uint8_t chks) { GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = chks; }; void SetChks (uint8_t chks) { GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = chks; };
void UpdateChks () void UpdateChks ()
{ {
uint8_t hash[32]; uint8_t hash[32];
SHA256(GetPayload (), GetPayloadLength (), hash); SHA256(GetPayload (), GetPayloadLength (), hash);
GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0]; GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
} }
// payload // payload
uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; }; uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; };
const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; }; const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; };
uint8_t * GetBuffer () { return buf + offset; }; uint8_t * GetBuffer () { return buf + offset; };
const uint8_t * GetBuffer () const { return buf + offset; }; const uint8_t * GetBuffer () const { return buf + offset; };
size_t GetLength () const { return len - offset; }; size_t GetLength () const { return len - offset; };
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; }; size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
void Align (size_t alignment) void Align (size_t alignment)
{ {
if (len + alignment > maxLen) return; if (len + alignment > maxLen) return;
size_t rem = ((size_t)GetBuffer ()) % alignment; size_t rem = ((size_t)GetBuffer ()) % alignment;
@ -153,7 +153,7 @@ namespace tunnel
{ {
offset += (alignment - rem); offset += (alignment - rem);
len += (alignment - rem); len += (alignment - rem);
} }
} }
size_t Concat (const uint8_t * buf1, size_t len1) size_t Concat (const uint8_t * buf1, size_t len1)
@ -171,10 +171,10 @@ namespace tunnel
len = offset + other.GetLength (); len = offset + other.GetLength ();
from = other.from; from = other.from;
return *this; return *this;
} }
// for SSU only // for SSU only
uint8_t * GetSSUHeader () { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; }; uint8_t * GetSSUHeader () { return buf + offset + I2NP_HEADER_SIZE - I2NP_SHORT_HEADER_SIZE; };
void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular void FromSSU (uint32_t msgID) // we have received SSU message and convert it to regular
{ {
const uint8_t * ssu = GetSSUHeader (); const uint8_t * ssu = GetSSUHeader ();
@ -193,12 +193,12 @@ namespace tunnel
htobe32buf (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET, bufbe64toh (header + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL); htobe32buf (ssu + I2NP_SHORT_HEADER_EXPIRATION_OFFSET, bufbe64toh (header + I2NP_HEADER_EXPIRATION_OFFSET)/1000LL);
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET); len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET); return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
} }
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0); void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0);
void RenewI2NPMessageHeader (); void RenewI2NPMessageHeader ();
bool IsExpired () const; bool IsExpired () const;
}; };
template<int sz> template<int sz>
struct I2NPMessageBuffer: public I2NPMessage struct I2NPMessageBuffer: public I2NPMessage
@ -211,35 +211,35 @@ namespace tunnel
std::shared_ptr<I2NPMessage> NewI2NPShortMessage (); std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage (); std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage ();
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len); std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0); std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr); std::shared_ptr<I2NPMessage> CreateI2NPMessage (const uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from = nullptr);
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg);
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID); std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID);
std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, std::shared_ptr<I2NPMessage> CreateRouterInfoDatabaseLookupMsg (const uint8_t * key, const uint8_t * from,
uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr); uint32_t replyTunnelID, bool exploratory = false, std::set<i2p::data::IdentHash> * excludedPeers = nullptr);
std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest, std::shared_ptr<I2NPMessage> CreateLeaseSetDatabaseLookupMsg (const i2p::data::IdentHash& dest,
const std::set<i2p::data::IdentHash>& excludedFloodfills, const std::set<i2p::data::IdentHash>& excludedFloodfills,
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag); std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag);
std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers); std::shared_ptr<I2NPMessage> CreateDatabaseSearchReply (const i2p::data::IdentHash& ident, std::vector<i2p::data::IdentHash> routers);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0); std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, uint32_t replyToken = 0);
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet); // for floodfill only
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr); std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg); bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText); bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len); void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len);
void HandleTunnelBuildMsg (uint8_t * buf, size_t len); void HandleTunnelBuildMsg (uint8_t * buf, size_t len);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf); std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (const uint8_t * buf);
std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload); std::shared_ptr<I2NPMessage> CreateTunnelDataMsg (uint32_t tunnelID, const uint8_t * payload);
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg (); std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ();
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType, std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessageType msgType,
const uint8_t * buf, size_t len, uint32_t replyMsgID = 0); const uint8_t * buf, size_t len, uint32_t replyMsgID = 0);
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg); std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
@ -254,7 +254,7 @@ namespace tunnel
~I2NPMessagesHandler (); ~I2NPMessagesHandler ();
void PutNextMessage (std::shared_ptr<I2NPMessage> msg); void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
void Flush (); void Flush ();
private: private:
std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs; std::vector<std::shared_ptr<I2NPMessage> > m_TunnelMsgs, m_TunnelGatewayMsgs;
@ -262,6 +262,6 @@ namespace tunnel
const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500; const uint16_t DEFAULT_MAX_NUM_TRANSIT_TUNNELS = 2500;
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels); void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
} }
#endif #endif

View file

@ -41,7 +41,7 @@ namespace data
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType): IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType):
m_IsVerifierCreated (false) m_IsVerifierCreated (false)
{ {
memcpy (m_StandardIdentity.publicKey, publicKey, 256); // publicKey in awlays assumed 256 regardless actual size, padding must be taken care of memcpy (m_StandardIdentity.publicKey, publicKey, 256); // publicKey in awlays assumed 256 regardless actual size, padding must be taken care of
if (type != SIGNING_KEY_TYPE_DSA_SHA1) if (type != SIGNING_KEY_TYPE_DSA_SHA1)
{ {
@ -450,7 +450,7 @@ namespace data
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (const uint8_t * key) const std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> IdentityEx::CreateEncryptor (const uint8_t * key) const
{ {
if (!key) key = GetEncryptionPublicKey (); // use publicKey if (!key) key = GetEncryptionPublicKey (); // use publicKey
switch (GetCryptoKeyType ()) switch (GetCryptoKeyType ())
{ {
case CRYPTO_KEY_TYPE_ELGAMAL: case CRYPTO_KEY_TYPE_ELGAMAL:
@ -542,7 +542,7 @@ namespace data
void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const void PrivateKeys::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
if (!m_Signer) if (!m_Signer)
CreateSigner(); CreateSigner();
m_Signer->Sign (buf, len, signature); m_Signer->Sign (buf, len, signature);
} }
@ -596,12 +596,12 @@ namespace data
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (const uint8_t * key) const std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (const uint8_t * key) const
{ {
if (!key) key = m_PrivateKey; // use privateKey if (!key) key = m_PrivateKey; // use privateKey
return CreateDecryptor (m_Public->GetCryptoKeyType (), key); return CreateDecryptor (m_Public->GetCryptoKeyType (), key);
} }
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key) std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key)
{ {
if (!key) return nullptr; if (!key) return nullptr;
switch (cryptoType) switch (cryptoType)
{ {
@ -618,7 +618,7 @@ namespace data
default: default:
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType); LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
}; };
return nullptr; return nullptr;
} }
PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType) PrivateKeys PrivateKeys::CreateRandomKeys (SigningKeyType type, CryptoKeyType cryptoType)
@ -643,7 +643,7 @@ namespace data
case SIGNING_KEY_TYPE_RSA_SHA384_3072: case SIGNING_KEY_TYPE_RSA_SHA384_3072:
case SIGNING_KEY_TYPE_RSA_SHA512_4096: case SIGNING_KEY_TYPE_RSA_SHA512_4096:
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Create EdDSA"); LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Create EdDSA");
// no break here // no break here
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519: case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey); i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
break; break;
@ -685,7 +685,7 @@ namespace data
break; break;
default: default:
LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported"); LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported");
} }
} }
Keys CreateRandomKeys () Keys CreateRandomKeys ()

View file

@ -91,12 +91,12 @@ namespace data
size_t ToBuffer (uint8_t * buf, size_t len) const; size_t ToBuffer (uint8_t * buf, size_t len) const;
size_t FromBase64(const std::string& s); size_t FromBase64(const std::string& s);
std::string ToBase64 () const; std::string ToBase64 () const;
const Identity& GetStandardIdentity () const { return m_StandardIdentity; }; const Identity& GetStandardIdentity () const { return m_StandardIdentity; };
const IdentHash& GetIdentHash () const { return m_IdentHash; }; const IdentHash& GetIdentHash () const { return m_IdentHash; };
const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; }; const uint8_t * GetEncryptionPublicKey () const { return m_StandardIdentity.publicKey; };
uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; }; uint8_t * GetEncryptionPublicKeyBuffer () { return m_StandardIdentity.publicKey; };
std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const; std::shared_ptr<i2p::crypto::CryptoKeyEncryptor> CreateEncryptor (const uint8_t * key) const;
size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; }; size_t GetFullLen () const { return m_ExtendedLen + DEFAULT_IDENTITY_SIZE; };
size_t GetSigningPublicKeyLen () const; size_t GetSigningPublicKeyLen () const;
size_t GetSigningPrivateKeyLen () const; size_t GetSigningPrivateKeyLen () const;
@ -141,7 +141,7 @@ namespace data
const uint8_t * GetPrivateKey () const { return m_PrivateKey; }; const uint8_t * GetPrivateKey () const { return m_PrivateKey; };
const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_SigningPrivateKey; };
uint8_t * GetPadding(); uint8_t * GetPadding();
void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); } void RecalculateIdentHash(uint8_t * buf=nullptr) { m_Public->RecalculateIdentHash(buf); }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); }; size_t GetFullLen () const { return m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); };

View file

@ -11,7 +11,7 @@ namespace i2p
{ {
namespace data namespace data
{ {
LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases): LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases):
m_IsValid (true), m_StoreLeases (storeLeases), m_ExpirationTime (0) m_IsValid (true), m_StoreLeases (storeLeases), m_ExpirationTime (0)
{ {
@ -22,13 +22,13 @@ namespace data
} }
void LeaseSet::Update (const uint8_t * buf, size_t len) void LeaseSet::Update (const uint8_t * buf, size_t len)
{ {
if (len > m_BufferLen) if (len > m_BufferLen)
{ {
auto oldBuffer = m_Buffer; auto oldBuffer = m_Buffer;
m_Buffer = new uint8_t[len]; m_Buffer = new uint8_t[len];
delete[] oldBuffer; delete[] oldBuffer;
} }
memcpy (m_Buffer, buf, len); memcpy (m_Buffer, buf, len);
m_BufferLen = len; m_BufferLen = len;
ReadFromBuffer (false); ReadFromBuffer (false);
@ -38,10 +38,10 @@ namespace data
{ {
m_StoreLeases = true; m_StoreLeases = true;
ReadFromBuffer (false); ReadFromBuffer (false);
} }
void LeaseSet::ReadFromBuffer (bool readIdentity) void LeaseSet::ReadFromBuffer (bool readIdentity)
{ {
if (readIdentity || !m_Identity) if (readIdentity || !m_Identity)
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen); m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
size_t size = m_Identity->GetFullLen (); size_t size = m_Identity->GetFullLen ();
@ -58,17 +58,17 @@ namespace data
size++; // num size++; // num
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num); LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
if (!num || num > MAX_NUM_LEASES) if (!num || num > MAX_NUM_LEASES)
{ {
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num); LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num);
m_IsValid = false; m_IsValid = false;
return; return;
} }
// reset existing leases // reset existing leases
if (m_StoreLeases) if (m_StoreLeases)
for (auto& it: m_Leases) for (auto& it: m_Leases)
it->isUpdated = false; it->isUpdated = false;
else else
m_Leases.clear (); m_Leases.clear ();
// process leases // process leases
@ -82,14 +82,14 @@ namespace data
leases += 32; // gateway leases += 32; // gateway
lease.tunnelID = bufbe32toh (leases); lease.tunnelID = bufbe32toh (leases);
leases += 4; // tunnel ID leases += 4; // tunnel ID
lease.endDate = bufbe64toh (leases); lease.endDate = bufbe64toh (leases);
leases += 8; // end date leases += 8; // end date
if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD) if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD)
{ {
if (lease.endDate > m_ExpirationTime) if (lease.endDate > m_ExpirationTime)
m_ExpirationTime = lease.endDate; m_ExpirationTime = lease.endDate;
if (m_StoreLeases) if (m_StoreLeases)
{ {
auto ret = m_Leases.insert (std::make_shared<Lease>(lease)); auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
(*ret.first)->isUpdated = true; (*ret.first)->isUpdated = true;
@ -100,28 +100,28 @@ namespace data
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting"); LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
netdb.RequestDestination (lease.tunnelGateway); netdb.RequestDestination (lease.tunnelGateway);
} }
} }
} }
else else
LogPrint (eLogWarning, "LeaseSet: Lease is expired already "); LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
} }
if (!m_ExpirationTime) if (!m_ExpirationTime)
{ {
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped"); LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
m_IsValid = false; m_IsValid = false;
return; return;
} }
m_ExpirationTime += LEASE_ENDDATE_THRESHOLD; m_ExpirationTime += LEASE_ENDDATE_THRESHOLD;
// delete old leases // delete old leases
if (m_StoreLeases) if (m_StoreLeases)
{ {
for (auto it = m_Leases.begin (); it != m_Leases.end ();) for (auto it = m_Leases.begin (); it != m_Leases.end ();)
{ {
if (!(*it)->isUpdated) if (!(*it)->isUpdated)
{ {
(*it)->endDate = 0; // somebody might still hold it (*it)->endDate = 0; // somebody might still hold it
m_Leases.erase (it++); m_Leases.erase (it++);
} }
else else
++it; ++it;
} }
@ -133,9 +133,9 @@ namespace data
LogPrint (eLogWarning, "LeaseSet: verification failed"); LogPrint (eLogWarning, "LeaseSet: verification failed");
m_IsValid = false; m_IsValid = false;
} }
} }
uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const uint64_t LeaseSet::ExtractTimestamp (const uint8_t * buf, size_t len) const
{ {
if (!m_Identity) return 0; if (!m_Identity) return 0;
size_t size = m_Identity->GetFullLen (); size_t size = m_Identity->GetFullLen ();
@ -150,18 +150,18 @@ namespace data
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
{ {
size += 36; // gateway (32) + tunnelId(4) size += 36; // gateway (32) + tunnelId(4)
auto endDate = bufbe64toh (buf + size); auto endDate = bufbe64toh (buf + size);
size += 8; // end date size += 8; // end date
if (!timestamp || endDate < timestamp) if (!timestamp || endDate < timestamp)
timestamp = endDate; timestamp = endDate;
} }
return timestamp; return timestamp;
} }
bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const
{ {
return ExtractTimestamp (buf, len) > ExtractTimestamp (m_Buffer, m_BufferLen); return ExtractTimestamp (buf, len) > ExtractTimestamp (m_Buffer, m_BufferLen);
} }
bool LeaseSet::ExpiresSoon(const uint64_t dlt, const uint64_t fudge) const bool LeaseSet::ExpiresSoon(const uint64_t dlt, const uint64_t fudge) const
{ {
@ -175,7 +175,7 @@ namespace data
{ {
return GetNonExpiredLeasesExcluding( [] (const Lease & l) -> bool { return false; }, withThreshold); return GetNonExpiredLeasesExcluding( [] (const Lease & l) -> bool { return false; }, withThreshold);
} }
const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
@ -189,17 +189,17 @@ namespace data
endDate -= LEASE_ENDDATE_THRESHOLD; endDate -= LEASE_ENDDATE_THRESHOLD;
if (ts < endDate && !exclude(*it)) if (ts < endDate && !exclude(*it))
leases.push_back (it); leases.push_back (it);
} }
return leases; return leases;
} }
bool LeaseSet::HasExpiredLeases () const bool LeaseSet::HasExpiredLeases () const
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
for (const auto& it: m_Leases) for (const auto& it: m_Leases)
if (ts >= it->endDate) return true; if (ts >= it->endDate) return true;
return false; return false;
} }
bool LeaseSet::IsExpired () const bool LeaseSet::IsExpired () const
{ {
@ -222,15 +222,15 @@ namespace data
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES; if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
// identity // identity
auto signingKeyLen = m_Identity->GetSigningPublicKeyLen (); auto signingKeyLen = m_Identity->GetSigningPublicKeyLen ();
m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen (); m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen ();
m_Buffer = new uint8_t[m_BufferLen]; m_Buffer = new uint8_t[m_BufferLen];
auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen); auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen);
memcpy (m_Buffer + offset, encryptionPublicKey, 256); memcpy (m_Buffer + offset, encryptionPublicKey, 256);
offset += 256; offset += 256;
memset (m_Buffer + offset, 0, signingKeyLen); memset (m_Buffer + offset, 0, signingKeyLen);
offset += signingKeyLen; offset += signingKeyLen;
// num leases // num leases
m_Buffer[offset] = num; m_Buffer[offset] = num;
offset++; offset++;
// leases // leases
m_Leases = m_Buffer + offset; m_Leases = m_Buffer + offset;
@ -257,13 +257,13 @@ namespace data
{ {
m_BufferLen = len; m_BufferLen = len;
m_Buffer = new uint8_t[m_BufferLen]; m_Buffer = new uint8_t[m_BufferLen];
memcpy (m_Buffer, buf, len); memcpy (m_Buffer, buf, len);
} }
bool LocalLeaseSet::IsExpired () const bool LocalLeaseSet::IsExpired () const
{ {
auto ts = i2p::util::GetMillisecondsSinceEpoch (); auto ts = i2p::util::GetMillisecondsSinceEpoch ();
return ts > m_ExpirationTime; return ts > m_ExpirationTime;
} }
} }
} }

View file

@ -14,11 +14,11 @@ namespace i2p
namespace tunnel namespace tunnel
{ {
class InboundTunnel; class InboundTunnel;
} }
namespace data namespace data
{ {
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
struct Lease struct Lease
{ {
@ -33,24 +33,24 @@ namespace data
if (endDate < expire) return true; if (endDate < expire) return true;
return (endDate - expire) < t; return (endDate - expire) < t;
} }
}; };
struct LeaseCmp struct LeaseCmp
{ {
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
{ {
if (l1->tunnelID != l2->tunnelID) if (l1->tunnelID != l2->tunnelID)
return l1->tunnelID < l2->tunnelID; return l1->tunnelID < l2->tunnelID;
else else
return l1->tunnelGateway < l2->tunnelGateway; return l1->tunnelGateway < l2->tunnelGateway;
}; };
}; };
typedef std::function<bool(const Lease & l)> LeaseInspectFunc; typedef std::function<bool(const Lease & l)> LeaseInspectFunc;
const size_t MAX_LS_BUFFER_SIZE = 3072; const size_t MAX_LS_BUFFER_SIZE = 3072;
const size_t LEASE_SIZE = 44; // 32 + 4 + 8 const size_t LEASE_SIZE = 44; // 32 + 4 + 8
const uint8_t MAX_NUM_LEASES = 16; const uint8_t MAX_NUM_LEASES = 16;
class LeaseSet: public RoutingDestination class LeaseSet: public RoutingDestination
{ {
public: public:
@ -59,10 +59,10 @@ namespace data
~LeaseSet () { delete[] m_Buffer; }; ~LeaseSet () { delete[] m_Buffer; };
void Update (const uint8_t * buf, size_t len); void Update (const uint8_t * buf, size_t len);
bool IsNewer (const uint8_t * buf, size_t len) const; bool IsNewer (const uint8_t * buf, size_t len) const;
void PopulateLeases (); // from buffer void PopulateLeases (); // from buffer
const uint8_t * GetBuffer () const { return m_Buffer; }; const uint8_t * GetBuffer () const { return m_Buffer; };
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
bool IsValid () const { return m_IsValid; }; bool IsValid () const { return m_IsValid; };
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeases (bool withThreshold = true) const; const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeases (bool withThreshold = true) const;
const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold = true) const; const std::vector<std::shared_ptr<const Lease> > GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold = true) const;
@ -71,8 +71,8 @@ namespace data
bool IsEmpty () const { return m_Leases.empty (); }; bool IsEmpty () const { return m_Leases.empty (); };
uint64_t GetExpirationTime () const { return m_ExpirationTime; }; uint64_t GetExpirationTime () const { return m_ExpirationTime; };
bool ExpiresSoon(const uint64_t dlt=1000 * 5, const uint64_t fudge = 0) const ; bool ExpiresSoon(const uint64_t dlt=1000 * 5, const uint64_t fudge = 0) const ;
bool operator== (const LeaseSet& other) const bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); }; { return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
// implements RoutingDestination // implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; }; std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
@ -83,7 +83,7 @@ namespace data
void ReadFromBuffer (bool readIdentity = true); void ReadFromBuffer (bool readIdentity = true);
uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // min expiration time uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // min expiration time
private: private:
bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill bool m_IsValid, m_StoreLeases; // we don't need to store leases for floodfill
@ -93,7 +93,7 @@ namespace data
uint8_t m_EncryptionKey[256]; uint8_t m_EncryptionKey[256];
uint8_t * m_Buffer; uint8_t * m_Buffer;
size_t m_BufferLen; size_t m_BufferLen;
}; };
class LocalLeaseSet class LocalLeaseSet
{ {
@ -104,27 +104,27 @@ namespace data
~LocalLeaseSet () { delete[] m_Buffer; }; ~LocalLeaseSet () { delete[] m_Buffer; };
const uint8_t * GetBuffer () const { return m_Buffer; }; const uint8_t * GetBuffer () const { return m_Buffer; };
uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); }; uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); };
size_t GetBufferLen () const { return m_BufferLen; }; size_t GetBufferLen () const { return m_BufferLen; };
size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); }; size_t GetSignatureLen () const { return m_Identity->GetSignatureLen (); };
uint8_t * GetLeases () { return m_Leases; }; uint8_t * GetLeases () { return m_Leases; };
const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); }; const IdentHash& GetIdentHash () const { return m_Identity->GetIdentHash (); };
bool IsExpired () const; bool IsExpired () const;
uint64_t GetExpirationTime () const { return m_ExpirationTime; }; uint64_t GetExpirationTime () const { return m_ExpirationTime; };
void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; }; void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
bool operator== (const LeaseSet& other) const bool operator== (const LeaseSet& other) const
{ return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); }; { return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); };
private: private:
uint64_t m_ExpirationTime; // in milliseconds uint64_t m_ExpirationTime; // in milliseconds
std::shared_ptr<const IdentityEx> m_Identity; std::shared_ptr<const IdentityEx> m_Identity;
uint8_t * m_Buffer, * m_Leases; uint8_t * m_Buffer, * m_Leases;
size_t m_BufferLen; size_t m_BufferLen;
}; };
} }
} }
#endif #endif

View file

@ -44,7 +44,7 @@ enum LogType {
namespace i2p { namespace i2p {
namespace log { namespace log {
struct LogMsg; /* forward declaration */ struct LogMsg; /* forward declaration */
class Log class Log
@ -146,7 +146,7 @@ namespace log {
std::string text; /**< message text as single string */ std::string text; /**< message text as single string */
LogLevel level; /**< message level */ LogLevel level; /**< message level */
std::thread::id tid; /**< id of thread that generated message */ std::thread::id tid; /**< id of thread that generated message */
LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {}; LogMsg (LogLevel lvl, std::time_t ts, const std::string & txt): timestamp(ts), text(txt), level(lvl) {};
}; };
@ -185,7 +185,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
std::stringstream ss(""); std::stringstream ss("");
LogPrint (ss, std::forward<TArgs>(args)...); LogPrint (ss, std::forward<TArgs>(args)...);
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str()); auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
msg->tid = std::this_thread::get_id(); msg->tid = std::this_thread::get_id();
log.Append(msg); log.Append(msg);

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@
namespace i2p namespace i2p
{ {
namespace data namespace data
{ {
const int NETDB_MIN_ROUTERS = 90; const int NETDB_MIN_ROUTERS = 90;
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60*60; // 1 hour, in seconds const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60*60; // 1 hour, in seconds
const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65*60; const int NETDB_INTRODUCEE_EXPIRATION_TIMEOUT = 65*60;
@ -37,11 +37,11 @@ namespace data
typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor; typedef std::function<void(const IdentHash, std::shared_ptr<LeaseSet>)> LeaseSetVisitor;
/** function for visiting a router info we have locally */ /** function for visiting a router info we have locally */
typedef std::function<void(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoVisitor; typedef std::function<void(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoVisitor;
/** function for visiting a router info and determining if we want to use it */ /** function for visiting a router info and determining if we want to use it */
typedef std::function<bool(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoFilter; typedef std::function<bool(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoFilter;
class NetDb class NetDb
{ {
public: public:
@ -51,7 +51,7 @@ namespace data
void Start (); void Start ();
void Stop (); void Stop ();
bool AddRouterInfo (const uint8_t * buf, int len); bool AddRouterInfo (const uint8_t * buf, int len);
bool AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len); bool AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len);
bool AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from); bool AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
@ -59,12 +59,12 @@ namespace data
std::shared_ptr<LeaseSet> FindLeaseSet (const IdentHash& destination) const; std::shared_ptr<LeaseSet> FindLeaseSet (const IdentHash& destination) const;
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const; std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr); void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr);
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
@ -76,13 +76,13 @@ namespace data
std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const; std::set<IdentHash>& excluded, bool closeThanUsOnly = false) const;
std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const; std::shared_ptr<const RouterInfo> GetClosestNonFloodfill (const IdentHash& destination, const std::set<IdentHash>& excluded) const;
std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const; std::shared_ptr<const RouterInfo> GetRandomRouterInFamily(const std::string & fam) const;
void SetUnreachable (const IdentHash& ident, bool unreachable); void SetUnreachable (const IdentHash& ident, bool unreachable);
void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg); void PostI2NPMsg (std::shared_ptr<const I2NPMessage> msg);
/** set hidden mode, aka don't publish our RI to netdb and don't explore */ /** set hidden mode, aka don't publish our RI to netdb and don't explore */
void SetHidden(bool hide); void SetHidden(bool hide);
void Reseed (); void Reseed ();
Families& GetFamilies () { return m_Families; }; Families& GetFamilies () { return m_Families; };
@ -108,28 +108,28 @@ namespace data
bool LoadRouterInfo (const std::string & path); bool LoadRouterInfo (const std::string & path);
void SaveUpdated (); void SaveUpdated ();
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
void Publish (); void Publish ();
void ManageLeaseSets (); void ManageLeaseSets ();
void ManageRequests (); void ManageRequests ();
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
template<typename Filter> template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const; std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
private: private:
mutable std::mutex m_LeaseSetsMutex; mutable std::mutex m_LeaseSetsMutex;
std::map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets; std::map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets;
mutable std::mutex m_RouterInfosMutex; mutable std::mutex m_RouterInfosMutex;
std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos; std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
mutable std::mutex m_FloodfillsMutex; mutable std::mutex m_FloodfillsMutex;
std::list<std::shared_ptr<RouterInfo> > m_Floodfills; std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
bool m_IsRunning; bool m_IsRunning;
uint64_t m_LastLoad; uint64_t m_LastLoad;
std::thread * m_Thread; std::thread * m_Thread;
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
GzipInflator m_Inflator; GzipInflator m_Inflator;
@ -137,12 +137,12 @@ namespace data
Families m_Families; Families m_Families;
i2p::fs::HashedStorage m_Storage; i2p::fs::HashedStorage m_Storage;
friend class NetDbRequests; friend class NetDbRequests;
NetDbRequests m_Requests; NetDbRequests m_Requests;
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/ /** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap; std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
/** true if in hidden mode */ /** true if in hidden mode */
bool m_HiddenMode; bool m_HiddenMode;

View file

@ -13,8 +13,8 @@ namespace data
{ {
std::shared_ptr<I2NPMessage> msg; std::shared_ptr<I2NPMessage> msg;
if(replyTunnel) if(replyTunnel)
msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
&m_ExcludedPeers); &m_ExcludedPeers);
else else
msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers);
@ -22,22 +22,22 @@ namespace data
m_ExcludedPeers.insert (router->GetIdentHash ()); m_ExcludedPeers.insert (router->GetIdentHash ());
m_CreationTime = i2p::util::GetSecondsSinceEpoch (); m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return msg; return msg;
} }
std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (const IdentHash& floodfill) std::shared_ptr<I2NPMessage> RequestedDestination::CreateRequestMessage (const IdentHash& floodfill)
{ {
auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers); i2p::context.GetRouterInfo ().GetIdentHash () , 0, false, &m_ExcludedPeers);
m_ExcludedPeers.insert (floodfill); m_ExcludedPeers.insert (floodfill);
m_CreationTime = i2p::util::GetSecondsSinceEpoch (); m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
return msg; return msg;
} }
void RequestedDestination::ClearExcludedPeers () void RequestedDestination::ClearExcludedPeers ()
{ {
m_ExcludedPeers.clear (); m_ExcludedPeers.clear ();
} }
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r) void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
{ {
if (m_RequestComplete) if (m_RequestComplete)
@ -69,15 +69,15 @@ namespace data
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete) std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
{ {
// request RouterInfo directly // request RouterInfo directly
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory); auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
dest->SetRequestComplete (requestComplete); dest->SetRequestComplete (requestComplete);
{ {
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted
return nullptr; return nullptr;
} }
return dest; return dest;
} }
void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r) void NetDbRequests::RequestComplete (const IdentHash& ident, std::shared_ptr<RouterInfo> r)
{ {
@ -86,18 +86,18 @@ namespace data
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
auto it = m_RequestedDestinations.find (ident); auto it = m_RequestedDestinations.find (ident);
if (it != m_RequestedDestinations.end ()) if (it != m_RequestedDestinations.end ())
{ {
request = it->second; request = it->second;
m_RequestedDestinations.erase (it); m_RequestedDestinations.erase (it);
} }
} }
if (request) if (request)
{ {
if (r) if (r)
request->Success (r); request->Success (r);
else else
request->Fail (); request->Fail ();
} }
} }
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
@ -107,12 +107,12 @@ namespace data
if (it != m_RequestedDestinations.end ()) if (it != m_RequestedDestinations.end ())
return it->second; return it->second;
return nullptr; return nullptr;
} }
void NetDbRequests::ManageRequests () void NetDbRequests::ManageRequests ()
{ {
uint64_t ts = i2p::util::GetSecondsSinceEpoch (); uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex); std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();) for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
{ {
auto& dest = it->second; auto& dest = it->second;
@ -126,7 +126,7 @@ namespace data
{ {
auto pool = i2p::tunnel::tunnels.GetExploratoryPool (); auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
auto outbound = pool->GetNextOutboundTunnel (); auto outbound = pool->GetNextOutboundTunnel ();
auto inbound = pool->GetNextInboundTunnel (); auto inbound = pool->GetNextInboundTunnel ();
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ()); auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
if (nextFloodfill && outbound && inbound) if (nextFloodfill && outbound && inbound)
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0, outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
@ -138,15 +138,15 @@ namespace data
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels"); if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills"); if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
} }
} }
else else
{ {
if (!dest->IsExploratory ()) if (!dest->IsExploratory ())
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts"); LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
done = true; done = true;
} }
} }
} }
else // delete obsolete request else // delete obsolete request
done = true; done = true;
@ -154,7 +154,7 @@ namespace data
it = m_RequestedDestinations.erase (it); it = m_RequestedDestinations.erase (it);
else else
++it; ++it;
} }
} }
} }
} }

View file

@ -12,14 +12,14 @@ namespace i2p
namespace data namespace data
{ {
class RequestedDestination class RequestedDestination
{ {
public: public:
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete; typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
RequestedDestination (const IdentHash& destination, bool isExploratory = false): RequestedDestination (const IdentHash& destination, bool isExploratory = false):
m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {}; m_Destination (destination), m_IsExploratory (isExploratory), m_CreationTime (0) {};
~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); }; ~RequestedDestination () { if (m_RequestComplete) m_RequestComplete (nullptr); };
const IdentHash& GetDestination () const { return m_Destination; }; const IdentHash& GetDestination () const { return m_Destination; };
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
@ -30,12 +30,12 @@ namespace data
uint64_t GetCreationTime () const { return m_CreationTime; }; uint64_t GetCreationTime () const { return m_CreationTime; };
std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel); std::shared_ptr<I2NPMessage> CreateRequestMessage (std::shared_ptr<const RouterInfo>, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel);
std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill); std::shared_ptr<I2NPMessage> CreateRequestMessage (const IdentHash& floodfill);
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; }; void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
bool IsRequestComplete () const { return m_RequestComplete != nullptr; }; bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
void Success (std::shared_ptr<RouterInfo> r); void Success (std::shared_ptr<RouterInfo> r);
void Fail (); void Fail ();
private: private:
IdentHash m_Destination; IdentHash m_Destination;
@ -43,7 +43,7 @@ namespace data
std::set<IdentHash> m_ExcludedPeers; std::set<IdentHash> m_ExcludedPeers;
uint64_t m_CreationTime; uint64_t m_CreationTime;
RequestComplete m_RequestComplete; RequestComplete m_RequestComplete;
}; };
class NetDbRequests class NetDbRequests
{ {

View file

@ -15,20 +15,20 @@ namespace data
RouterProfile::RouterProfile (): RouterProfile::RouterProfile ():
m_LastUpdateTime (boost::posix_time::second_clock::local_time()), m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0), m_NumTunnelsAgreed (0), m_NumTunnelsDeclined (0), m_NumTunnelsNonReplied (0),
m_NumTimesTaken (0), m_NumTimesRejected (0) m_NumTimesTaken (0), m_NumTimesRejected (0)
{ {
} }
boost::posix_time::ptime RouterProfile::GetTime () const boost::posix_time::ptime RouterProfile::GetTime () const
{ {
return boost::posix_time::second_clock::local_time(); return boost::posix_time::second_clock::local_time();
} }
void RouterProfile::UpdateTime () void RouterProfile::UpdateTime ()
{ {
m_LastUpdateTime = GetTime (); m_LastUpdateTime = GetTime ();
} }
void RouterProfile::Save (const IdentHash& identHash) void RouterProfile::Save (const IdentHash& identHash)
{ {
// fill sections // fill sections
@ -63,57 +63,57 @@ namespace data
std::string path = m_ProfilesStorage.Path(ident); std::string path = m_ProfilesStorage.Path(ident);
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
if (!i2p::fs::Exists(path)) if (!i2p::fs::Exists(path))
{ {
LogPrint(eLogWarning, "Profiling: no profile yet for ", ident); LogPrint(eLogWarning, "Profiling: no profile yet for ", ident);
return; return;
} }
try try
{ {
boost::property_tree::read_ini (path, pt); boost::property_tree::read_ini (path, pt);
} catch (std::exception& ex) } catch (std::exception& ex)
{ {
/* boost exception verbose enough */ /* boost exception verbose enough */
LogPrint (eLogError, "Profiling: ", ex.what ()); LogPrint (eLogError, "Profiling: ", ex.what ());
return; return;
} }
try try
{ {
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, ""); auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
if (t.length () > 0) if (t.length () > 0)
m_LastUpdateTime = boost::posix_time::time_from_string (t); m_LastUpdateTime = boost::posix_time::time_from_string (t);
if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT) if ((GetTime () - m_LastUpdateTime).hours () < PEER_PROFILE_EXPIRATION_TIMEOUT)
{ {
try try
{ {
// read participations // read participations
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION); auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0); m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0); m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 0);
m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0); m_NumTunnelsNonReplied = participations.get (PEER_PROFILE_PARTICIPATION_NON_REPLIED, 0);
} }
catch (boost::property_tree::ptree_bad_path& ex) catch (boost::property_tree::ptree_bad_path& ex)
{ {
LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident); LogPrint (eLogWarning, "Profiling: Missing section ", PEER_PROFILE_SECTION_PARTICIPATION, " in profile for ", ident);
} }
try try
{ {
// read usage // read usage
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE); auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0); m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 0);
m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0); m_NumTimesRejected = usage.get (PEER_PROFILE_USAGE_REJECTED, 0);
} }
catch (boost::property_tree::ptree_bad_path& ex) catch (boost::property_tree::ptree_bad_path& ex)
{ {
LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident); LogPrint (eLogWarning, "Missing section ", PEER_PROFILE_SECTION_USAGE, " in profile for ", ident);
} }
} }
else else
*this = RouterProfile (); *this = RouterProfile ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ()); LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ());
} }
@ -126,46 +126,46 @@ namespace data
m_NumTunnelsDeclined++; m_NumTunnelsDeclined++;
else else
m_NumTunnelsAgreed++; m_NumTunnelsAgreed++;
} }
void RouterProfile::TunnelNonReplied () void RouterProfile::TunnelNonReplied ()
{ {
m_NumTunnelsNonReplied++; m_NumTunnelsNonReplied++;
UpdateTime (); UpdateTime ();
} }
bool RouterProfile::IsLowPartcipationRate () const bool RouterProfile::IsLowPartcipationRate () const
{ {
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
} }
bool RouterProfile::IsLowReplyRate () const bool RouterProfile::IsLowReplyRate () const
{ {
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined; auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
return m_NumTunnelsNonReplied > 10*(total + 1); return m_NumTunnelsNonReplied > 10*(total + 1);
} }
bool RouterProfile::IsBad () bool RouterProfile::IsBad ()
{ {
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/; auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1)) if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
{ {
// reset profile // reset profile
m_NumTunnelsAgreed = 0; m_NumTunnelsAgreed = 0;
m_NumTunnelsDeclined = 0; m_NumTunnelsDeclined = 0;
m_NumTunnelsNonReplied = 0; m_NumTunnelsNonReplied = 0;
isBad = false; isBad = false;
} }
if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++; if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++;
return isBad; return isBad;
} }
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash) std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
{ {
auto profile = std::make_shared<RouterProfile> (); auto profile = std::make_shared<RouterProfile> ();
profile->Load (identHash); // if possible profile->Load (identHash); // if possible
return profile; return profile;
} }
void InitProfilesStorage () void InitProfilesStorage ()
{ {
@ -191,5 +191,5 @@ namespace data
} }
} }
} }
} }
} }

View file

@ -8,32 +8,32 @@
namespace i2p namespace i2p
{ {
namespace data namespace data
{ {
// sections // sections
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation"; const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
const char PEER_PROFILE_SECTION_USAGE[] = "usage"; const char PEER_PROFILE_SECTION_USAGE[] = "usage";
// params // params
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime"; const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed"; const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined"; const char PEER_PROFILE_PARTICIPATION_DECLINED[] = "declined";
const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied"; const char PEER_PROFILE_PARTICIPATION_NON_REPLIED[] = "nonreplied";
const char PEER_PROFILE_USAGE_TAKEN[] = "taken"; const char PEER_PROFILE_USAGE_TAKEN[] = "taken";
const char PEER_PROFILE_USAGE_REJECTED[] = "rejected"; const char PEER_PROFILE_USAGE_REJECTED[] = "rejected";
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days) const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
class RouterProfile class RouterProfile
{ {
public: public:
RouterProfile (); RouterProfile ();
RouterProfile& operator= (const RouterProfile& ) = default; RouterProfile& operator= (const RouterProfile& ) = default;
void Save (const IdentHash& identHash); void Save (const IdentHash& identHash);
void Load (const IdentHash& identHash); void Load (const IdentHash& identHash);
bool IsBad (); bool IsBad ();
void TunnelBuildResponse (uint8_t ret); void TunnelBuildResponse (uint8_t ret);
void TunnelNonReplied (); void TunnelNonReplied ();
@ -45,23 +45,23 @@ namespace data
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; }; bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
bool IsLowPartcipationRate () const; bool IsLowPartcipationRate () const;
bool IsLowReplyRate () const; bool IsLowReplyRate () const;
private: private:
boost::posix_time::ptime m_LastUpdateTime; boost::posix_time::ptime m_LastUpdateTime;
// participation // participation
uint32_t m_NumTunnelsAgreed; uint32_t m_NumTunnelsAgreed;
uint32_t m_NumTunnelsDeclined; uint32_t m_NumTunnelsDeclined;
uint32_t m_NumTunnelsNonReplied; uint32_t m_NumTunnelsNonReplied;
// usage // usage
uint32_t m_NumTimesTaken; uint32_t m_NumTimesTaken;
uint32_t m_NumTimesRejected; uint32_t m_NumTimesRejected;
}; };
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash); std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash);
void InitProfilesStorage (); void InitProfilesStorage ();
void DeleteObsoleteProfiles (); void DeleteObsoleteProfiles ();
} }
} }
#endif #endif

View file

@ -15,7 +15,7 @@ namespace util
{ {
template<typename Element> template<typename Element>
class Queue class Queue
{ {
public: public:
void Put (Element e) void Put (Element e)
@ -29,14 +29,14 @@ namespace util
void Put (const Container<Element, R...>& vec) void Put (const Container<Element, R...>& vec)
{ {
if (!vec.empty ()) if (!vec.empty ())
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
for (const auto& it: vec) for (const auto& it: vec)
m_Queue.push (it); m_Queue.push (it);
m_NonEmpty.notify_one (); m_NonEmpty.notify_one ();
} }
} }
Element GetNext () Element GetNext ()
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
@ -45,7 +45,7 @@ namespace util
{ {
m_NonEmpty.wait (l); m_NonEmpty.wait (l);
el = GetNonThreadSafe (); el = GetNonThreadSafe ();
} }
return el; return el;
} }
@ -57,7 +57,7 @@ namespace util
{ {
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec)); m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
el = GetNonThreadSafe (); el = GetNonThreadSafe ();
} }
return el; return el;
} }
@ -73,17 +73,17 @@ namespace util
return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout; return m_NonEmpty.wait_for (l, std::chrono::seconds (sec) + std::chrono::milliseconds (usec)) != std::cv_status::timeout;
} }
bool IsEmpty () bool IsEmpty ()
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.empty (); return m_Queue.empty ();
} }
int GetSize () int GetSize ()
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
return m_Queue.size (); return m_Queue.size ();
} }
void WakeUp () { m_NonEmpty.notify_all (); }; void WakeUp () { m_NonEmpty.notify_all (); };
@ -91,14 +91,14 @@ namespace util
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe (); return GetNonThreadSafe ();
} }
Element Peek () Element Peek ()
{ {
std::unique_lock<std::mutex> l(m_QueueMutex); std::unique_lock<std::mutex> l(m_QueueMutex);
return GetNonThreadSafe (true); return GetNonThreadSafe (true);
} }
private: private:
Element GetNonThreadSafe (bool peek = false) Element GetNonThreadSafe (bool peek = false)
@ -109,17 +109,17 @@ namespace util
if (!peek) if (!peek)
m_Queue.pop (); m_Queue.pop ();
return el; return el;
} }
return nullptr; return nullptr;
} }
private: private:
std::queue<Element> m_Queue; std::queue<Element> m_Queue;
std::mutex m_QueueMutex; std::mutex m_QueueMutex;
std::condition_variable m_NonEmpty; std::condition_variable m_NonEmpty;
}; };
} }
} }
#endif #endif

View file

@ -2,7 +2,7 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/asio/ssl.hpp> #include <boost/asio/ssl.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
@ -23,7 +23,7 @@ namespace i2p
{ {
namespace data namespace data
{ {
Reseeder::Reseeder() Reseeder::Reseeder()
{ {
} }
@ -114,11 +114,11 @@ namespace data
return 0; return 0;
} }
} }
int Reseeder::ProcessSU3File (const char * filename) int Reseeder::ProcessSU3File (const char * filename)
{ {
std::ifstream s(filename, std::ifstream::binary); std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
return ProcessSU3Stream (s); return ProcessSU3Stream (s);
else else
{ {
@ -130,21 +130,21 @@ namespace data
int Reseeder::ProcessZIPFile (const char * filename) int Reseeder::ProcessZIPFile (const char * filename)
{ {
std::ifstream s(filename, std::ifstream::binary); std::ifstream s(filename, std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
{ {
s.seekg (0, std::ios::end); s.seekg (0, std::ios::end);
auto len = s.tellg (); auto len = s.tellg ();
s.seekg (0, std::ios::beg); s.seekg (0, std::ios::beg);
return ProcessZIPStream (s, len); return ProcessZIPStream (s, len);
} }
else else
{ {
LogPrint (eLogError, "Reseed: Can't open file ", filename); LogPrint (eLogError, "Reseed: Can't open file ", filename);
return 0; return 0;
} }
} }
const char SU3_MAGIC_NUMBER[]="I2Psu3"; const char SU3_MAGIC_NUMBER[]="I2Psu3";
int Reseeder::ProcessSU3Stream (std::istream& s) int Reseeder::ProcessSU3Stream (std::istream& s)
{ {
char magicNumber[7]; char magicNumber[7];
@ -153,7 +153,7 @@ namespace data
{ {
LogPrint (eLogError, "Reseed: Unexpected SU3 magic number"); LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
return 0; return 0;
} }
s.seekg (1, std::ios::cur); // su3 file format version s.seekg (1, std::ios::cur); // su3 file format version
SigningKeyType signatureType; SigningKeyType signatureType;
s.read ((char *)&signatureType, 2); // signature type s.read ((char *)&signatureType, 2); // signature type
@ -163,16 +163,16 @@ namespace data
signatureLength = be16toh (signatureLength); signatureLength = be16toh (signatureLength);
s.seekg (1, std::ios::cur); // unused s.seekg (1, std::ios::cur); // unused
uint8_t versionLength; uint8_t versionLength;
s.read ((char *)&versionLength, 1); // version length s.read ((char *)&versionLength, 1); // version length
s.seekg (1, std::ios::cur); // unused s.seekg (1, std::ios::cur); // unused
uint8_t signerIDLength; uint8_t signerIDLength;
s.read ((char *)&signerIDLength, 1); // signer ID length s.read ((char *)&signerIDLength, 1); // signer ID length
uint64_t contentLength; uint64_t contentLength;
s.read ((char *)&contentLength, 8); // content length s.read ((char *)&contentLength, 8); // content length
contentLength = be64toh (contentLength); contentLength = be64toh (contentLength);
s.seekg (1, std::ios::cur); // unused s.seekg (1, std::ios::cur); // unused
uint8_t fileType; uint8_t fileType;
s.read ((char *)&fileType, 1); // file type s.read ((char *)&fileType, 1); // file type
if (fileType != 0x00) // zip file if (fileType != 0x00) // zip file
{ {
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType); LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
@ -180,7 +180,7 @@ namespace data
} }
s.seekg (1, std::ios::cur); // unused s.seekg (1, std::ios::cur); // unused
uint8_t contentType; uint8_t contentType;
s.read ((char *)&contentType, 1); // content type s.read ((char *)&contentType, 1); // content type
if (contentType != 0x03) // reseed data if (contentType != 0x03) // reseed data
{ {
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType); LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
@ -192,10 +192,10 @@ namespace data
char signerID[256]; char signerID[256];
s.read (signerID, signerIDLength); // signerID s.read (signerID, signerIDLength); // signerID
signerID[signerIDLength] = 0; signerID[signerIDLength] = 0;
bool verify; i2p::config::GetOption("reseed.verify", verify); bool verify; i2p::config::GetOption("reseed.verify", verify);
if (verify) if (verify)
{ {
//try to verify signature //try to verify signature
auto it = m_SigningKeys.find (signerID); auto it = m_SigningKeys.find (signerID);
if (it != m_SigningKeys.end ()) if (it != m_SigningKeys.end ())
@ -220,7 +220,7 @@ namespace data
BIGNUM * s = BN_new (), * n = BN_new (); BIGNUM * s = BN_new (), * n = BN_new ();
BN_bin2bn (signature, signatureLength, s); BN_bin2bn (signature, signatureLength, s);
BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n); BN_bin2bn (it->second, i2p::crypto::RSASHA5124096_KEY_LENGTH, n);
BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n BN_mod_exp (s, s, i2p::crypto::GetRSAE (), n, bnctx); // s = s^e mod n
uint8_t * enSigBuf = new uint8_t[signatureLength]; uint8_t * enSigBuf = new uint8_t[signatureLength];
i2p::crypto::bn2buf (s, enSigBuf, signatureLength); i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
// digest is right aligned // digest is right aligned
@ -232,8 +232,8 @@ namespace data
delete[] enSigBuf; delete[] enSigBuf;
BN_free (s); BN_free (n); BN_free (s); BN_free (n);
BN_CTX_free (bnctx); BN_CTX_free (bnctx);
} }
delete[] signature; delete[] signature;
delete[] tbs; delete[] tbs;
s.seekg (pos, std::ios::beg); s.seekg (pos, std::ios::beg);
@ -249,21 +249,21 @@ namespace data
{ {
LogPrint (eLogError, "Reseed: SU3 verification failed"); LogPrint (eLogError, "Reseed: SU3 verification failed");
return 0; return 0;
} }
// handle content // handle content
return ProcessZIPStream (s, contentLength); return ProcessZIPStream (s, contentLength);
} }
const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50; const uint32_t ZIP_HEADER_SIGNATURE = 0x04034B50;
const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50; const uint32_t ZIP_CENTRAL_DIRECTORY_HEADER_SIGNATURE = 0x02014B50;
const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008; const uint16_t ZIP_BIT_FLAG_DATA_DESCRIPTOR = 0x0008;
int Reseeder::ProcessZIPStream (std::istream& s, uint64_t contentLength) int Reseeder::ProcessZIPStream (std::istream& s, uint64_t contentLength)
{ {
int numFiles = 0; int numFiles = 0;
size_t contentPos = s.tellg (); size_t contentPos = s.tellg ();
while (!s.eof ()) while (!s.eof ())
{ {
uint32_t signature; uint32_t signature;
s.read ((char *)&signature, 4); s.read ((char *)&signature, 4);
signature = le32toh (signature); signature = le32toh (signature);
@ -272,22 +272,22 @@ namespace data
// next local file // next local file
s.seekg (2, std::ios::cur); // version s.seekg (2, std::ios::cur); // version
uint16_t bitFlag; uint16_t bitFlag;
s.read ((char *)&bitFlag, 2); s.read ((char *)&bitFlag, 2);
bitFlag = le16toh (bitFlag); bitFlag = le16toh (bitFlag);
uint16_t compressionMethod; uint16_t compressionMethod;
s.read ((char *)&compressionMethod, 2); s.read ((char *)&compressionMethod, 2);
compressionMethod = le16toh (compressionMethod); compressionMethod = le16toh (compressionMethod);
s.seekg (4, std::ios::cur); // skip fields we don't care about s.seekg (4, std::ios::cur); // skip fields we don't care about
uint32_t compressedSize, uncompressedSize; uint32_t compressedSize, uncompressedSize;
uint32_t crc_32; uint32_t crc_32;
s.read ((char *)&crc_32, 4); s.read ((char *)&crc_32, 4);
crc_32 = le32toh (crc_32); crc_32 = le32toh (crc_32);
s.read ((char *)&compressedSize, 4); s.read ((char *)&compressedSize, 4);
compressedSize = le32toh (compressedSize); compressedSize = le32toh (compressedSize);
s.read ((char *)&uncompressedSize, 4); s.read ((char *)&uncompressedSize, 4);
uncompressedSize = le32toh (uncompressedSize); uncompressedSize = le32toh (uncompressedSize);
uint16_t fileNameLength, extraFieldLength; uint16_t fileNameLength, extraFieldLength;
s.read ((char *)&fileNameLength, 2); s.read ((char *)&fileNameLength, 2);
fileNameLength = le16toh (fileNameLength); fileNameLength = le16toh (fileNameLength);
if ( fileNameLength > 255 ) { if ( fileNameLength > 255 ) {
// too big // too big
@ -308,13 +308,13 @@ namespace data
{ {
LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found"); LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
return numFiles; return numFiles;
} }
s.read ((char *)&crc_32, 4); s.read ((char *)&crc_32, 4);
crc_32 = le32toh (crc_32); crc_32 = le32toh (crc_32);
s.read ((char *)&compressedSize, 4); s.read ((char *)&compressedSize, 4);
compressedSize = le32toh (compressedSize) + 4; // ??? we must consider signature as part of compressed data compressedSize = le32toh (compressedSize) + 4; // ??? we must consider signature as part of compressed data
s.read ((char *)&uncompressedSize, 4); s.read ((char *)&uncompressedSize, 4);
uncompressedSize = le32toh (uncompressedSize); uncompressedSize = le32toh (uncompressedSize);
// now we know compressed and uncompressed size // now we know compressed and uncompressed size
s.seekg (pos, std::ios::beg); // back to compressed data s.seekg (pos, std::ios::beg); // back to compressed data
@ -325,8 +325,8 @@ namespace data
{ {
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped"); LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
continue; continue;
} }
uint8_t * compressed = new uint8_t[compressedSize]; uint8_t * compressed = new uint8_t[compressedSize];
s.read ((char *)compressed, compressedSize); s.read ((char *)compressed, compressedSize);
if (compressionMethod) // we assume Deflate if (compressionMethod) // we assume Deflate
@ -338,29 +338,29 @@ namespace data
inflator.next_in = compressed; inflator.next_in = compressed;
inflator.avail_in = compressedSize; inflator.avail_in = compressedSize;
inflator.next_out = uncompressed; inflator.next_out = uncompressed;
inflator.avail_out = uncompressedSize; inflator.avail_out = uncompressedSize;
int err; int err;
if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0) if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0)
{ {
uncompressedSize -= inflator.avail_out; uncompressedSize -= inflator.avail_out;
if (crc32 (0, uncompressed, uncompressedSize) == crc_32) if (crc32 (0, uncompressed, uncompressedSize) == crc_32)
{ {
i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize); i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize);
numFiles++; numFiles++;
} }
else else
LogPrint (eLogError, "Reseed: CRC32 verification failed"); LogPrint (eLogError, "Reseed: CRC32 verification failed");
} }
else else
LogPrint (eLogError, "Reseed: SU3 decompression error ", err); LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
delete[] uncompressed; delete[] uncompressed;
inflateEnd (&inflator); inflateEnd (&inflator);
} }
else // no compression else // no compression
{ {
i2p::data::netdb.AddRouterInfo (compressed, compressedSize); i2p::data::netdb.AddRouterInfo (compressed, compressedSize);
numFiles++; numFiles++;
} }
delete[] compressed; delete[] compressed;
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR) if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
s.seekg (12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4) s.seekg (12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
@ -406,15 +406,15 @@ namespace data
return numFiles; return numFiles;
} }
const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 }; const uint8_t ZIP_DATA_DESCRIPTOR_SIGNATURE[] = { 0x50, 0x4B, 0x07, 0x08 };
bool Reseeder::FindZipDataDescriptor (std::istream& s) bool Reseeder::FindZipDataDescriptor (std::istream& s)
{ {
size_t nextInd = 0; size_t nextInd = 0;
while (!s.eof ()) while (!s.eof ())
{ {
uint8_t nextByte; uint8_t nextByte;
s.read ((char *)&nextByte, 1); s.read ((char *)&nextByte, 1);
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd]) if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
{ {
nextInd++; nextInd++;
if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE)) if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE))
@ -429,24 +429,24 @@ namespace data
void Reseeder::LoadCertificate (const std::string& filename) void Reseeder::LoadCertificate (const std::string& filename)
{ {
SSL_CTX * ctx = SSL_CTX_new (TLS_method ()); SSL_CTX * ctx = SSL_CTX_new (TLS_method ());
int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM); int ret = SSL_CTX_use_certificate_file (ctx, filename.c_str (), SSL_FILETYPE_PEM);
if (ret) if (ret)
{ {
SSL * ssl = SSL_new (ctx); SSL * ssl = SSL_new (ctx);
X509 * cert = SSL_get_certificate (ssl); X509 * cert = SSL_get_certificate (ssl);
// verify // verify
if (cert) if (cert)
{ {
// extract issuer name // extract issuer name
char name[100]; char name[100];
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100); X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
char * cn = strstr (name, "CN="); char * cn = strstr (name, "CN=");
if (cn) if (cn)
{ {
cn += 3; cn += 3;
char * terminator = strchr (cn, '/'); char * terminator = strchr (cn, '/');
if (terminator) terminator[0] = 0; if (terminator) terminator[0] = 0;
} }
// extract RSA key (we need n only, e = 65537) // extract RSA key (we need n only, e = 65537)
RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert)); RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
const BIGNUM * n, * e, * d; const BIGNUM * n, * e, * d;
@ -457,12 +457,12 @@ namespace data
m_SigningKeys[cn] = value; m_SigningKeys[cn] = value;
else else
LogPrint (eLogError, "Reseed: Can't find CN field in ", filename); LogPrint (eLogError, "Reseed: Can't find CN field in ", filename);
} }
SSL_free (ssl); SSL_free (ssl);
} }
else else
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename); LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
SSL_CTX_free (ctx); SSL_CTX_free (ctx);
} }
void Reseeder::LoadCertificates () void Reseeder::LoadCertificates ()
@ -483,9 +483,9 @@ namespace data
} }
LoadCertificate (file); LoadCertificate (file);
numCertificates++; numCertificates++;
} }
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded"); LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
} }
std::string Reseeder::HttpsRequest (const std::string& address) std::string Reseeder::HttpsRequest (const std::string& address)
{ {

View file

@ -15,10 +15,10 @@ namespace data
class Reseeder class Reseeder
{ {
typedef Tag<512> PublicKey; typedef Tag<512> PublicKey;
public: public:
Reseeder(); Reseeder();
~Reseeder(); ~Reseeder();
void Bootstrap (); void Bootstrap ();
@ -28,19 +28,19 @@ namespace data
int ProcessZIPFile (const char * filename); int ProcessZIPFile (const char * filename);
void LoadCertificates (); void LoadCertificates ();
private: private:
void LoadCertificate (const std::string& filename); void LoadCertificate (const std::string& filename);
int ProcessSU3Stream (std::istream& s); int ProcessSU3Stream (std::istream& s);
int ProcessZIPStream (std::istream& s, uint64_t contentLength); int ProcessZIPStream (std::istream& s, uint64_t contentLength);
bool FindZipDataDescriptor (std::istream& s); bool FindZipDataDescriptor (std::istream& s);
std::string HttpsRequest (const std::string& address); std::string HttpsRequest (const std::string& address);
private: private:
std::map<std::string, PublicKey> m_SigningKeys; std::map<std::string, PublicKey> m_SigningKeys;
}; };

View file

@ -28,7 +28,7 @@ namespace i2p
m_StartupTime = i2p::util::GetSecondsSinceEpoch (); m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
if (!Load ()) if (!Load ())
CreateNewRouter (); CreateNewRouter ();
m_Decryptor = m_Keys.CreateDecryptor (nullptr); m_Decryptor = m_Keys.CreateDecryptor (nullptr);
UpdateRouterInfo (); UpdateRouterInfo ();
} }
@ -204,7 +204,7 @@ namespace i2p
} }
} }
void RouterContext::SetBandwidth (char L) void RouterContext::SetBandwidth (char L)
{ {
uint32_t limit = 0; uint32_t limit = 0;
enum { low, high, extra, unlim } type = high; enum { low, high, extra, unlim } type = high;

View file

@ -13,7 +13,7 @@
namespace i2p namespace i2p
{ {
const char ROUTER_INFO[] = "router.info"; const char ROUTER_INFO[] = "router.info";
const char ROUTER_KEYS[] = "router.keys"; const char ROUTER_KEYS[] = "router.keys";
const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes const int ROUTER_INFO_UPDATE_INTERVAL = 1800; // 30 minutes
enum RouterStatus enum RouterStatus
@ -21,16 +21,16 @@ namespace i2p
eRouterStatusOK = 0, eRouterStatusOK = 0,
eRouterStatusTesting = 1, eRouterStatusTesting = 1,
eRouterStatusFirewalled = 2, eRouterStatusFirewalled = 2,
eRouterStatusError = 3 eRouterStatusError = 3
}; };
enum RouterError enum RouterError
{ {
eRouterErrorNone = 0, eRouterErrorNone = 0,
eRouterErrorClockSkew = 1 eRouterErrorClockSkew = 1
}; };
class RouterContext: public i2p::garlic::GarlicDestination class RouterContext: public i2p::garlic::GarlicDestination
{ {
public: public:
@ -39,17 +39,17 @@ namespace i2p
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; }; const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; }; i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
{ {
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo, return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
[](const i2p::data::RouterInfo *) {}); [](const i2p::data::RouterInfo *) {});
} }
std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination () std::shared_ptr<i2p::garlic::GarlicDestination> GetSharedDestination ()
{ {
return std::shared_ptr<i2p::garlic::GarlicDestination> (this, return std::shared_ptr<i2p::garlic::GarlicDestination> (this,
[](i2p::garlic::GarlicDestination *) {}); [](i2p::garlic::GarlicDestination *) {});
} }
uint32_t GetUptime () const; uint32_t GetUptime () const;
uint32_t GetStartupTime () const { return m_StartupTime; }; uint32_t GetStartupTime () const { return m_StartupTime; };
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; }; uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
@ -60,17 +60,17 @@ namespace i2p
RouterError GetError () const { return m_Error; }; RouterError GetError () const { return m_Error; };
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; }; void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
int GetNetID () const { return m_NetID; }; int GetNetID () const { return m_NetID; };
void SetNetID (int netID) { m_NetID = netID; }; void SetNetID (int netID) { m_NetID = netID; };
void UpdatePort (int port); // called from Daemon void UpdatePort (int port); // called from Daemon
void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer); bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e); void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
bool IsUnreachable () const; bool IsUnreachable () const;
void SetUnreachable (); void SetUnreachable ();
void SetReachable (); void SetReachable ();
bool IsFloodfill () const { return m_IsFloodfill; }; bool IsFloodfill () const { return m_IsFloodfill; };
void SetFloodfill (bool floodfill); void SetFloodfill (bool floodfill);
void SetFamily (const std::string& family); void SetFamily (const std::string& family);
std::string GetFamily () const; std::string GetFamily () const;
void SetBandwidth (int limit); /* in kilobytes */ void SetBandwidth (int limit); /* in kilobytes */
@ -83,14 +83,14 @@ namespace i2p
void SetSupportsV6 (bool supportsV6); void SetSupportsV6 (bool supportsV6);
void SetSupportsV4 (bool supportsV4); void SetSupportsV4 (bool supportsV4);
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
void UpdateStats (); void UpdateStats ();
void CleanupDestination (); // garlic destination void CleanupDestination (); // garlic destination
// implements LocalDestination // implements LocalDestination
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 Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; bool Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const;
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); }; void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
void SetLeaseSetUpdated () {}; void SetLeaseSetUpdated () {};
// implements GarlicDestination // implements GarlicDestination
@ -100,8 +100,8 @@ namespace i2p
// override GarlicDestination // override GarlicDestination
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg); void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg); void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
private: private:
void CreateNewRouter (); void CreateNewRouter ();
@ -109,11 +109,11 @@ namespace i2p
void UpdateRouterInfo (); void UpdateRouterInfo ();
bool Load (); bool Load ();
void SaveKeys (); void SaveKeys ();
private: private:
i2p::data::RouterInfo m_RouterInfo; i2p::data::RouterInfo m_RouterInfo;
i2p::data::PrivateKeys m_Keys; i2p::data::PrivateKeys m_Keys;
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor; std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
uint64_t m_LastUpdateTime; uint64_t m_LastUpdateTime;
bool m_AcceptsTunnels, m_IsFloodfill; bool m_AcceptsTunnels, m_IsFloodfill;
@ -127,6 +127,6 @@ namespace i2p
}; };
extern RouterContext context; extern RouterContext context;
} }
#endif #endif

View file

@ -19,20 +19,20 @@
namespace i2p namespace i2p
{ {
namespace data namespace data
{ {
RouterInfo::RouterInfo (): m_Buffer (nullptr) RouterInfo::RouterInfo (): m_Buffer (nullptr)
{ {
m_Addresses = boost::make_shared<Addresses>(); // create empty list m_Addresses = boost::make_shared<Addresses>(); // create empty list
} }
RouterInfo::RouterInfo (const std::string& fullPath): RouterInfo::RouterInfo (const std::string& fullPath):
m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false), m_FullPath (fullPath), m_IsUpdated (false), m_IsUnreachable (false),
m_SupportedTransports (0), m_Caps (0) m_SupportedTransports (0), m_Caps (0)
{ {
m_Addresses = boost::make_shared<Addresses>(); // create empty list m_Addresses = boost::make_shared<Addresses>(); // create empty list
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
ReadFromFile (); ReadFromFile ();
} }
RouterInfo::RouterInfo (const uint8_t * buf, int len): RouterInfo::RouterInfo (const uint8_t * buf, int len):
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0) m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0)
@ -42,13 +42,13 @@ namespace data
memcpy (m_Buffer, buf, len); memcpy (m_Buffer, buf, len);
m_BufferLen = len; m_BufferLen = len;
ReadFromBuffer (true); ReadFromBuffer (true);
} }
RouterInfo::~RouterInfo () RouterInfo::~RouterInfo ()
{ {
delete[] m_Buffer; delete[] m_Buffer;
} }
void RouterInfo::Update (const uint8_t * buf, int len) void RouterInfo::Update (const uint8_t * buf, int len)
{ {
// verify signature since we have indentity already // verify signature since we have indentity already
@ -63,35 +63,35 @@ namespace data
// don't clean up m_Addresses, it will be replaced in ReadFromStream // don't clean up m_Addresses, it will be replaced in ReadFromStream
m_Properties.clear (); m_Properties.clear ();
// copy buffer // copy buffer
if (!m_Buffer) if (!m_Buffer)
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
memcpy (m_Buffer, buf, len); memcpy (m_Buffer, buf, len);
m_BufferLen = len; m_BufferLen = len;
// skip identity // skip identity
size_t identityLen = m_RouterIdentity->GetFullLen (); size_t identityLen = m_RouterIdentity->GetFullLen ();
// read new RI // read new RI
std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen)); std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
ReadFromStream (str); ReadFromStream (str);
// don't delete buffer until saved to the file // don't delete buffer until saved to the file
} }
else else
{ {
LogPrint (eLogError, "RouterInfo: signature verification failed"); LogPrint (eLogError, "RouterInfo: signature verification failed");
m_IsUnreachable = true; m_IsUnreachable = true;
} }
} }
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity) void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
{ {
m_RouterIdentity = identity; m_RouterIdentity = identity;
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
} }
bool RouterInfo::LoadFile () bool RouterInfo::LoadFile ()
{ {
std::ifstream s(m_FullPath, std::ifstream::binary); std::ifstream s(m_FullPath, std::ifstream::binary);
if (s.is_open ()) if (s.is_open ())
{ {
s.seekg (0,std::ios::end); s.seekg (0,std::ios::end);
m_BufferLen = s.tellg (); m_BufferLen = s.tellg ();
if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE) if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
@ -103,22 +103,22 @@ namespace data
if (!m_Buffer) if (!m_Buffer)
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE]; m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
s.read((char *)m_Buffer, m_BufferLen); s.read((char *)m_Buffer, m_BufferLen);
} }
else else
{ {
LogPrint (eLogError, "RouterInfo: Can't open file ", m_FullPath); LogPrint (eLogError, "RouterInfo: Can't open file ", m_FullPath);
return false; return false;
} }
return true; return true;
} }
void RouterInfo::ReadFromFile () void RouterInfo::ReadFromFile ()
{ {
if (LoadFile ()) if (LoadFile ())
ReadFromBuffer (false); ReadFromBuffer (false);
else else
m_IsUnreachable = true; m_IsUnreachable = true;
} }
void RouterInfo::ReadFromBuffer (bool verifySignature) void RouterInfo::ReadFromBuffer (bool verifySignature)
{ {
@ -131,7 +131,7 @@ namespace data
return; return;
} }
if (verifySignature) if (verifySignature)
{ {
// reject RSA signatures // reject RSA signatures
if (m_RouterIdentity->IsRSA ()) if (m_RouterIdentity->IsRSA ())
{ {
@ -140,15 +140,15 @@ namespace data
return; return;
} }
// verify signature // verify signature
int l = m_BufferLen - m_RouterIdentity->GetSignatureLen (); int l = m_BufferLen - m_RouterIdentity->GetSignatureLen ();
if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l)) if (l < 0 || !m_RouterIdentity->Verify ((uint8_t *)m_Buffer, l, (uint8_t *)m_Buffer + l))
{ {
LogPrint (eLogError, "RouterInfo: signature verification failed"); LogPrint (eLogError, "RouterInfo: signature verification failed");
m_IsUnreachable = true; m_IsUnreachable = true;
return; return;
} }
m_RouterIdentity->DropVerifier (); m_RouterIdentity->DropVerifier ();
} }
// parse RI // parse RI
std::stringstream str; std::stringstream str;
str.write ((const char *)m_Buffer + identityLen, m_BufferLen - identityLen); str.write ((const char *)m_Buffer + identityLen, m_BufferLen - identityLen);
@ -158,17 +158,17 @@ namespace data
LogPrint (eLogError, "RouterInfo: malformed message"); LogPrint (eLogError, "RouterInfo: malformed message");
m_IsUnreachable = true; m_IsUnreachable = true;
} }
} }
void RouterInfo::ReadFromStream (std::istream& s) void RouterInfo::ReadFromStream (std::istream& s)
{ {
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp)); s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
m_Timestamp = be64toh (m_Timestamp); m_Timestamp = be64toh (m_Timestamp);
// read addresses // read addresses
auto addresses = boost::make_shared<Addresses>(); auto addresses = boost::make_shared<Addresses>();
uint8_t numAddresses; uint8_t numAddresses;
s.read ((char *)&numAddresses, sizeof (numAddresses)); if (!s) return; s.read ((char *)&numAddresses, sizeof (numAddresses)); if (!s) return;
bool introducers = false; bool introducers = false;
for (int i = 0; i < numAddresses; i++) for (int i = 0; i < numAddresses; i++)
{ {
@ -181,11 +181,11 @@ namespace data
if (!strcmp (transportStyle, "NTCP")) if (!strcmp (transportStyle, "NTCP"))
address->transportStyle = eTransportNTCP; address->transportStyle = eTransportNTCP;
else if (!strcmp (transportStyle, "SSU")) else if (!strcmp (transportStyle, "SSU"))
{ {
address->transportStyle = eTransportSSU; address->transportStyle = eTransportSSU;
address->ssu.reset (new SSUExt ()); address->ssu.reset (new SSUExt ());
address->ssu->mtu = 0; address->ssu->mtu = 0;
} }
else else
address->transportStyle = eTransportUnknown; address->transportStyle = eTransportUnknown;
address->port = 0; address->port = 0;
@ -197,35 +197,35 @@ namespace data
char key[255], value[255]; char key[255], value[255];
r += ReadString (key, 255, s); r += ReadString (key, 255, s);
s.seekg (1, std::ios_base::cur); r++; // = s.seekg (1, std::ios_base::cur); r++; // =
r += ReadString (value, 255, s); r += ReadString (value, 255, s);
s.seekg (1, std::ios_base::cur); r++; // ; s.seekg (1, std::ios_base::cur); r++; // ;
if (!s) return; if (!s) return;
if (!strcmp (key, "host")) if (!strcmp (key, "host"))
{ {
boost::system::error_code ecode; boost::system::error_code ecode;
address->host = boost::asio::ip::address::from_string (value, ecode); address->host = boost::asio::ip::address::from_string (value, ecode);
if (ecode) if (ecode)
{ {
if (address->transportStyle == eTransportNTCP) if (address->transportStyle == eTransportNTCP)
{ {
supportedTransports |= eNTCPV4; // TODO: supportedTransports |= eNTCPV4; // TODO:
address->addressString = value; address->addressString = value;
} }
else else
{ {
supportedTransports |= eSSUV4; // TODO: supportedTransports |= eSSUV4; // TODO:
address->addressString = value; address->addressString = value;
} }
} }
else else
{ {
// add supported protocol // add supported protocol
if (address->host.is_v4 ()) if (address->host.is_v4 ())
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4; supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
else else
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6; supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
} }
} }
else if (!strcmp (key, "port")) else if (!strcmp (key, "port"))
address->port = boost::lexical_cast<int>(value); address->port = boost::lexical_cast<int>(value);
else if (!strcmp (key, "mtu")) else if (!strcmp (key, "mtu"))
@ -234,21 +234,21 @@ namespace data
address->ssu->mtu = boost::lexical_cast<int>(value); address->ssu->mtu = boost::lexical_cast<int>(value);
else else
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP"); LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
} }
else if (!strcmp (key, "key")) else if (!strcmp (key, "key"))
{ {
if (address->ssu) if (address->ssu)
Base64ToByteStream (value, strlen (value), address->ssu->key, 32); Base64ToByteStream (value, strlen (value), address->ssu->key, 32);
else else
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP"); LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
} }
else if (!strcmp (key, "caps")) else if (!strcmp (key, "caps"))
ExtractCaps (value); ExtractCaps (value);
else if (key[0] == 'i') else if (key[0] == 'i')
{ {
// introducers // introducers
introducers = true; introducers = true;
size_t l = strlen(key); size_t l = strlen(key);
unsigned char index = key[l-1] - '0'; // TODO: unsigned char index = key[l-1] - '0'; // TODO:
key[l-1] = 0; key[l-1] = 0;
if (index > 9) if (index > 9)
@ -257,13 +257,13 @@ namespace data
if (s) continue; else return; if (s) continue; else return;
} }
if (index >= address->ssu->introducers.size ()) if (index >= address->ssu->introducers.size ())
address->ssu->introducers.resize (index + 1); address->ssu->introducers.resize (index + 1);
Introducer& introducer = address->ssu->introducers.at (index); Introducer& introducer = address->ssu->introducers.at (index);
if (!strcmp (key, "ihost")) if (!strcmp (key, "ihost"))
{ {
boost::system::error_code ecode; boost::system::error_code ecode;
introducer.iHost = boost::asio::ip::address::from_string (value, ecode); introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
} }
else if (!strcmp (key, "iport")) else if (!strcmp (key, "iport"))
introducer.iPort = boost::lexical_cast<int>(value); introducer.iPort = boost::lexical_cast<int>(value);
else if (!strcmp (key, "itag")) else if (!strcmp (key, "itag"))
@ -274,19 +274,19 @@ namespace data
introducer.iExp = boost::lexical_cast<uint32_t>(value); introducer.iExp = boost::lexical_cast<uint32_t>(value);
} }
if (!s) return; if (!s) return;
} }
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
if (supportedTransports) if (supportedTransports)
{ {
addresses->push_back(address); addresses->push_back(address);
m_SupportedTransports |= supportedTransports; m_SupportedTransports |= supportedTransports;
} }
} }
#if (BOOST_VERSION >= 105300) #if (BOOST_VERSION >= 105300)
boost::atomic_store (&m_Addresses, addresses); boost::atomic_store (&m_Addresses, addresses);
#else #else
m_Addresses = addresses; // race condition m_Addresses = addresses; // race condition
#endif #endif
// read peers // read peers
uint8_t numPeers; uint8_t numPeers;
s.read ((char *)&numPeers, sizeof (numPeers)); if (!s) return; s.read ((char *)&numPeers, sizeof (numPeers)); if (!s) return;
@ -297,23 +297,23 @@ namespace data
size = be16toh (size); size = be16toh (size);
while (r < size) while (r < size)
{ {
char key[255], value[255]; char key[255], value[255];
r += ReadString (key, 255, s); r += ReadString (key, 255, s);
s.seekg (1, std::ios_base::cur); r++; // = s.seekg (1, std::ios_base::cur); r++; // =
r += ReadString (value, 255, s); r += ReadString (value, 255, s);
s.seekg (1, std::ios_base::cur); r++; // ; s.seekg (1, std::ios_base::cur); r++; // ;
if (!s) return; if (!s) return;
m_Properties[key] = value; m_Properties[key] = value;
// extract caps // extract caps
if (!strcmp (key, "caps")) if (!strcmp (key, "caps"))
ExtractCaps (value); ExtractCaps (value);
// check netId // check netId
else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ()) else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ())
{ {
LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value); LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value);
m_IsUnreachable = true; m_IsUnreachable = true;
} }
// family // family
else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY)) else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY))
{ {
@ -327,10 +327,10 @@ namespace data
LogPrint (eLogWarning, "RouterInfo: family signature verification failed"); LogPrint (eLogWarning, "RouterInfo: family signature verification failed");
m_Family.clear (); m_Family.clear ();
} }
} }
if (!s) return; if (!s) return;
} }
if (!m_SupportedTransports || !m_Addresses->size() || (UsesIntroducer () && !introducers)) if (!m_SupportedTransports || !m_Addresses->size() || (UsesIntroducer () && !introducers))
SetUnreachable (true); SetUnreachable (true);
@ -358,56 +358,56 @@ namespace data
case CAPS_FLAG_EXTRA_BANDWIDTH1: case CAPS_FLAG_EXTRA_BANDWIDTH1:
case CAPS_FLAG_EXTRA_BANDWIDTH2: case CAPS_FLAG_EXTRA_BANDWIDTH2:
m_Caps |= Caps::eExtraBandwidth; m_Caps |= Caps::eExtraBandwidth;
break; break;
case CAPS_FLAG_HIDDEN: case CAPS_FLAG_HIDDEN:
m_Caps |= Caps::eHidden; m_Caps |= Caps::eHidden;
break; break;
case CAPS_FLAG_REACHABLE: case CAPS_FLAG_REACHABLE:
m_Caps |= Caps::eReachable; m_Caps |= Caps::eReachable;
break; break;
case CAPS_FLAG_UNREACHABLE: case CAPS_FLAG_UNREACHABLE:
m_Caps |= Caps::eUnreachable; m_Caps |= Caps::eUnreachable;
break; break;
case CAPS_FLAG_SSU_TESTING: case CAPS_FLAG_SSU_TESTING:
m_Caps |= Caps::eSSUTesting; m_Caps |= Caps::eSSUTesting;
break; break;
case CAPS_FLAG_SSU_INTRODUCER: case CAPS_FLAG_SSU_INTRODUCER:
m_Caps |= Caps::eSSUIntroducer; m_Caps |= Caps::eSSUIntroducer;
break; break;
default: ; default: ;
} }
cap++; cap++;
} }
} }
void RouterInfo::UpdateCapsProperty () void RouterInfo::UpdateCapsProperty ()
{ {
std::string caps; std::string caps;
if (m_Caps & eFloodfill) if (m_Caps & eFloodfill)
{ {
if (m_Caps & eExtraBandwidth) caps += (m_Caps & eHighBandwidth) ? if (m_Caps & eExtraBandwidth) caps += (m_Caps & eHighBandwidth) ?
CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X' CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X'
CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P' CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O' caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
caps += CAPS_FLAG_FLOODFILL; // floodfill caps += CAPS_FLAG_FLOODFILL; // floodfill
} }
else else
{ {
if (m_Caps & eExtraBandwidth) if (m_Caps & eExtraBandwidth)
{ {
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */ caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O' caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
} }
else else
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
} }
if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden if (m_Caps & eHidden) caps += CAPS_FLAG_HIDDEN; // hidden
if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable if (m_Caps & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
SetProperty ("caps", caps); SetProperty ("caps", caps);
} }
void RouterInfo::WriteToStream (std::ostream& s) const void RouterInfo::WriteToStream (std::ostream& s) const
{ {
uint64_t ts = htobe64 (m_Timestamp); uint64_t ts = htobe64 (m_Timestamp);
@ -425,7 +425,7 @@ namespace data
if (address.transportStyle == eTransportNTCP) if (address.transportStyle == eTransportNTCP)
WriteString ("NTCP", s); WriteString ("NTCP", s);
else if (address.transportStyle == eTransportSSU) else if (address.transportStyle == eTransportSSU)
{ {
WriteString ("SSU", s); WriteString ("SSU", s);
// caps // caps
WriteString ("caps", properties); WriteString ("caps", properties);
@ -435,7 +435,7 @@ namespace data
if (IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER; if (IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
WriteString (caps, properties); WriteString (caps, properties);
properties << ';'; properties << ';';
} }
else else
WriteString ("", s); WriteString ("", s);
@ -447,7 +447,7 @@ namespace data
{ {
// write introducers if any // write introducers if any
if (address.ssu->introducers.size () > 0) if (address.ssu->introducers.size () > 0)
{ {
int i = 0; int i = 0;
for (const auto& introducer: address.ssu->introducers) for (const auto& introducer: address.ssu->introducers)
{ {
@ -456,7 +456,7 @@ namespace data
WriteString (introducer.iHost.to_string (), properties); WriteString (introducer.iHost.to_string (), properties);
properties << ';'; properties << ';';
i++; i++;
} }
i = 0; i = 0;
for (const auto& introducer: address.ssu->introducers) for (const auto& introducer: address.ssu->introducers)
{ {
@ -468,7 +468,7 @@ namespace data
WriteString (value, properties); WriteString (value, properties);
properties << ';'; properties << ';';
i++; i++;
} }
i = 0; i = 0;
for (const auto& introducer: address.ssu->introducers) for (const auto& introducer: address.ssu->introducers)
{ {
@ -477,7 +477,7 @@ namespace data
WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties); WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
properties << ';'; properties << ';';
i++; i++;
} }
i = 0; i = 0;
for (const auto& introducer: address.ssu->introducers) for (const auto& introducer: address.ssu->introducers)
{ {
@ -486,7 +486,7 @@ namespace data
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties); WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
properties << ';'; properties << ';';
i++; i++;
} }
i = 0; i = 0;
for (const auto& introducer: address.ssu->introducers) for (const auto& introducer: address.ssu->introducers)
{ {
@ -498,8 +498,8 @@ namespace data
properties << ';'; properties << ';';
} }
i++; i++;
} }
} }
// write intro key // write intro key
WriteString ("key", properties); WriteString ("key", properties);
properties << '='; properties << '=';
@ -515,17 +515,17 @@ namespace data
properties << '='; properties << '=';
WriteString (boost::lexical_cast<std::string>(address.ssu->mtu), properties); WriteString (boost::lexical_cast<std::string>(address.ssu->mtu), properties);
properties << ';'; properties << ';';
} }
} }
WriteString ("port", properties); WriteString ("port", properties);
properties << '='; properties << '=';
WriteString (boost::lexical_cast<std::string>(address.port), properties); WriteString (boost::lexical_cast<std::string>(address.port), properties);
properties << ';'; properties << ';';
uint16_t size = htobe16 (properties.str ().size ()); uint16_t size = htobe16 (properties.str ().size ());
s.write ((char *)&size, sizeof (size)); s.write ((char *)&size, sizeof (size));
s.write (properties.str ().c_str (), properties.str ().size ()); s.write (properties.str ().c_str (), properties.str ().size ());
} }
// peers // peers
uint8_t numPeers = 0; uint8_t numPeers = 0;
@ -539,18 +539,18 @@ namespace data
properties << '='; properties << '=';
WriteString (p.second, properties); WriteString (p.second, properties);
properties << ';'; properties << ';';
} }
uint16_t size = htobe16 (properties.str ().size ()); uint16_t size = htobe16 (properties.str ().size ());
s.write ((char *)&size, sizeof (size)); s.write ((char *)&size, sizeof (size));
s.write (properties.str ().c_str (), properties.str ().size ()); s.write (properties.str ().c_str (), properties.str ().size ());
} }
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
{ {
if (!m_RouterIdentity) return false; if (!m_RouterIdentity) return false;
size_t size = m_RouterIdentity->GetFullLen (); size_t size = m_RouterIdentity->GetFullLen ();
if (size + 8 > len) return false; if (size + 8 > len) return false;
return bufbe64toh (buf + size) > m_Timestamp; return bufbe64toh (buf + size) > m_Timestamp;
} }
const uint8_t * RouterInfo::LoadBuffer () const uint8_t * RouterInfo::LoadBuffer ()
@ -559,8 +559,8 @@ namespace data
{ {
if (LoadFile ()) if (LoadFile ())
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file"); LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
} }
return m_Buffer; return m_Buffer;
} }
void RouterInfo::CreateBuffer (const PrivateKeys& privateKeys) void RouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
@ -569,7 +569,7 @@ namespace data
std::stringstream s; std::stringstream s;
uint8_t ident[1024]; uint8_t ident[1024];
auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024); auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024);
s.write ((char *)ident, identLen); s.write ((char *)ident, identLen);
WriteToStream (s); WriteToStream (s);
m_BufferLen = s.str ().size (); m_BufferLen = s.str ().size ();
if (!m_Buffer) if (!m_Buffer)
@ -578,7 +578,7 @@ namespace data
// signature // signature
privateKeys.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen); privateKeys.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen);
m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen (); m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen ();
} }
bool RouterInfo::SaveToFile (const std::string& fullPath) bool RouterInfo::SaveToFile (const std::string& fullPath)
{ {
@ -595,13 +595,13 @@ namespace data
f.write ((char *)m_Buffer, m_BufferLen); f.write ((char *)m_Buffer, m_BufferLen);
return true; return true;
} }
size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const
{ {
uint8_t l; uint8_t l;
s.read ((char *)&l, 1); s.read ((char *)&l, 1);
if (l < len) if (l < len)
{ {
s.read (str, l); s.read (str, l);
if (!s) l = 0; // failed, return empty string if (!s) l = 0; // failed, return empty string
str[l] = 0; str[l] = 0;
@ -611,16 +611,16 @@ namespace data
LogPrint (eLogWarning, "RouterInfo: string length ", (int)l, " exceeds buffer size ", len); LogPrint (eLogWarning, "RouterInfo: string length ", (int)l, " exceeds buffer size ", len);
s.seekg (l, std::ios::cur); // skip s.seekg (l, std::ios::cur); // skip
str[0] = 0; str[0] = 0;
} }
return l+1; return l+1;
} }
void RouterInfo::WriteString (const std::string& str, std::ostream& s) const void RouterInfo::WriteString (const std::string& str, std::ostream& s) const
{ {
uint8_t len = str.size (); uint8_t len = str.size ();
s.write ((char *)&len, 1); s.write ((char *)&len, 1);
s.write (str.c_str (), len); s.write (str.c_str (), len);
} }
void RouterInfo::AddNTCPAddress (const char * host, int port) void RouterInfo::AddNTCPAddress (const char * host, int port)
{ {
@ -634,7 +634,7 @@ namespace data
if (*it == *addr) return; if (*it == *addr) return;
m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4; m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4;
m_Addresses->push_back(std::move(addr)); m_Addresses->push_back(std::move(addr));
} }
void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu) void RouterInfo::AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu)
{ {
@ -645,7 +645,7 @@ namespace data
addr->cost = 10; // NTCP should have priority over SSU addr->cost = 10; // NTCP should have priority over SSU
addr->date = 0; addr->date = 0;
addr->ssu.reset (new SSUExt ()); addr->ssu.reset (new SSUExt ());
addr->ssu->mtu = mtu; addr->ssu->mtu = mtu;
memcpy (addr->ssu->key, key, 32); memcpy (addr->ssu->key, key, 32);
for (const auto& it: *m_Addresses) // don't insert same address twice for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return; if (*it == *addr) return;
@ -654,37 +654,37 @@ namespace data
m_Caps |= eSSUTesting; m_Caps |= eSSUTesting;
m_Caps |= eSSUIntroducer; m_Caps |= eSSUIntroducer;
} }
bool RouterInfo::AddIntroducer (const Introducer& introducer) bool RouterInfo::AddIntroducer (const Introducer& introducer)
{ {
for (auto& addr : *m_Addresses) for (auto& addr : *m_Addresses)
{ {
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{ {
for (auto& intro: addr->ssu->introducers) for (auto& intro: addr->ssu->introducers)
if (intro.iTag == introducer.iTag) return false; // already presented if (intro.iTag == introducer.iTag) return false; // already presented
addr->ssu->introducers.push_back (introducer); addr->ssu->introducers.push_back (introducer);
return true; return true;
} }
} }
return false; return false;
} }
bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e) bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
{ {
for (auto& addr: *m_Addresses) for (auto& addr: *m_Addresses)
{ {
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ()) if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
{ {
for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it) for (auto it = addr->ssu->introducers.begin (); it != addr->ssu->introducers.end (); ++it)
if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e) if ( boost::asio::ip::udp::endpoint (it->iHost, it->iPort) == e)
{ {
addr->ssu->introducers.erase (it); addr->ssu->introducers.erase (it);
return true; return true;
} }
} }
} }
return false; return false;
} }
@ -693,39 +693,39 @@ namespace data
m_Caps = caps; m_Caps = caps;
UpdateCapsProperty (); UpdateCapsProperty ();
} }
void RouterInfo::SetCaps (const char * caps) void RouterInfo::SetCaps (const char * caps)
{ {
SetProperty ("caps", caps); SetProperty ("caps", caps);
m_Caps = 0; m_Caps = 0;
ExtractCaps (caps); ExtractCaps (caps);
} }
void RouterInfo::SetProperty (const std::string& key, const std::string& value) void RouterInfo::SetProperty (const std::string& key, const std::string& value)
{ {
m_Properties[key] = value; m_Properties[key] = value;
} }
void RouterInfo::DeleteProperty (const std::string& key) void RouterInfo::DeleteProperty (const std::string& key)
{ {
m_Properties.erase (key); m_Properties.erase (key);
} }
std::string RouterInfo::GetProperty (const std::string& key) const std::string RouterInfo::GetProperty (const std::string& key) const
{ {
auto it = m_Properties.find (key); auto it = m_Properties.find (key);
if (it != m_Properties.end ()) if (it != m_Properties.end ())
return it->second; return it->second;
return ""; return "";
} }
bool RouterInfo::IsNTCP (bool v4only) const bool RouterInfo::IsNTCP (bool v4only) const
{ {
if (v4only) if (v4only)
return m_SupportedTransports & eNTCPV4; return m_SupportedTransports & eNTCPV4;
else else
return m_SupportedTransports & (eNTCPV4 | eNTCPV6); return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
} }
bool RouterInfo::IsSSU (bool v4only) const bool RouterInfo::IsSSU (bool v4only) const
{ {
@ -744,7 +744,7 @@ namespace data
{ {
return m_SupportedTransports & (eNTCPV4 | eSSUV4); return m_SupportedTransports & (eNTCPV4 | eSSUV4);
} }
void RouterInfo::EnableV6 () void RouterInfo::EnableV6 ()
{ {
if (!IsV6 ()) if (!IsV6 ())
@ -756,13 +756,13 @@ namespace data
if (!IsV4 ()) if (!IsV4 ())
m_SupportedTransports |= eNTCPV4 | eSSUV4; m_SupportedTransports |= eNTCPV4 | eSSUV4;
} }
void RouterInfo::DisableV6 () void RouterInfo::DisableV6 ()
{ {
if (IsV6 ()) if (IsV6 ())
{ {
m_SupportedTransports &= ~(eNTCPV6 | eSSUV6); m_SupportedTransports &= ~(eNTCPV6 | eSSUV6);
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
{ {
auto addr = *it; auto addr = *it;
@ -770,15 +770,15 @@ namespace data
it = m_Addresses->erase (it); it = m_Addresses->erase (it);
else else
++it; ++it;
} }
} }
} }
void RouterInfo::DisableV4 () void RouterInfo::DisableV4 ()
{ {
if (IsV4 ()) if (IsV4 ())
{ {
m_SupportedTransports &= ~(eNTCPV4 | eSSUV4); m_SupportedTransports &= ~(eNTCPV4 | eSSUV4);
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();) for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
{ {
auto addr = *it; auto addr = *it;
@ -786,55 +786,55 @@ namespace data
it = m_Addresses->erase (it); it = m_Addresses->erase (it);
else else
++it; ++it;
} }
} }
} }
bool RouterInfo::UsesIntroducer () const bool RouterInfo::UsesIntroducer () const
{ {
return m_Caps & Caps::eUnreachable; // non-reachable return m_Caps & Caps::eUnreachable; // non-reachable
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCPAddress (bool v4only) const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCPAddress (bool v4only) const
{ {
return GetAddress (eTransportNTCP, v4only); return GetAddress (eTransportNTCP, v4only);
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUAddress (bool v4only) const
{ {
return GetAddress (eTransportSSU, v4only); return GetAddress (eTransportSSU, v4only);
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
{ {
return GetAddress (eTransportSSU, false, true); return GetAddress (eTransportSSU, false, true);
} }
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
{ {
#if (BOOST_VERSION >= 105300) #if (BOOST_VERSION >= 105300)
auto addresses = boost::atomic_load (&m_Addresses); auto addresses = boost::atomic_load (&m_Addresses);
#else #else
auto addresses = m_Addresses; auto addresses = m_Addresses;
#endif #endif
for (const auto& address : *addresses) for (const auto& address : *addresses)
{ {
if (address->transportStyle == s) if (address->transportStyle == s)
{ {
if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ())) if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ()))
return address; return address;
} }
} }
return nullptr; return nullptr;
} }
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
{ {
if (!m_Profile) if (!m_Profile)
m_Profile = GetRouterProfile (GetIdentHash ()); m_Profile = GetRouterProfile (GetIdentHash ());
return m_Profile; return m_Profile;
} }
void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
{ {

View file

@ -8,7 +8,7 @@
#include <list> #include <list>
#include <iostream> #include <iostream>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include "Identity.h" #include "Identity.h"
#include "Profiling.h" #include "Profiling.h"
@ -17,15 +17,15 @@ namespace i2p
namespace data namespace data
{ {
const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets"; const char ROUTER_INFO_PROPERTY_LEASESETS[] = "netdb.knownLeaseSets";
const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters"; const char ROUTER_INFO_PROPERTY_ROUTERS[] = "netdb.knownRouters";
const char ROUTER_INFO_PROPERTY_NETID[] = "netId"; const char ROUTER_INFO_PROPERTY_NETID[] = "netId";
const char ROUTER_INFO_PROPERTY_FAMILY[] = "family"; const char ROUTER_INFO_PROPERTY_FAMILY[] = "family";
const char ROUTER_INFO_PROPERTY_FAMILY_SIG[] = "family.sig"; const char ROUTER_INFO_PROPERTY_FAMILY_SIG[] = "family.sig";
const char CAPS_FLAG_FLOODFILL = 'f'; const char CAPS_FLAG_FLOODFILL = 'f';
const char CAPS_FLAG_HIDDEN = 'H'; const char CAPS_FLAG_HIDDEN = 'H';
const char CAPS_FLAG_REACHABLE = 'R'; const char CAPS_FLAG_REACHABLE = 'R';
const char CAPS_FLAG_UNREACHABLE = 'U'; const char CAPS_FLAG_UNREACHABLE = 'U';
/* bandwidth flags */ /* bandwidth flags */
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */ const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 KBps */
const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */ const char CAPS_FLAG_LOW_BANDWIDTH2 = 'L'; /* 12-48 KBps */
@ -34,7 +34,7 @@ namespace data
const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */ const char CAPS_FLAG_HIGH_BANDWIDTH3 = 'O'; /* 128-256 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */ const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
const char CAPS_FLAG_SSU_TESTING = 'B'; const char CAPS_FLAG_SSU_TESTING = 'B';
const char CAPS_FLAG_SSU_INTRODUCER = 'C'; const char CAPS_FLAG_SSU_INTRODUCER = 'C';
@ -44,13 +44,13 @@ namespace data
public: public:
enum SupportedTranports enum SupportedTranports
{ {
eNTCPV4 = 0x01, eNTCPV4 = 0x01,
eNTCPV6 = 0x02, eNTCPV6 = 0x02,
eSSUV4 = 0x04, eSSUV4 = 0x04,
eSSUV6 = 0x08 eSSUV6 = 0x08
}; };
enum Caps enum Caps
{ {
eFloodfill = 0x01, eFloodfill = 0x01,
@ -71,7 +71,7 @@ namespace data
}; };
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
struct Introducer struct Introducer
{ {
Introducer (): iExp (0) {}; Introducer (): iExp (0) {};
boost::asio::ip::address iHost; boost::asio::ip::address iHost;
@ -85,9 +85,9 @@ namespace data
{ {
int mtu; int mtu;
IntroKey key; // intro key for SSU IntroKey key; // intro key for SSU
std::vector<Introducer> introducers; std::vector<Introducer> introducers;
}; };
struct Address struct Address
{ {
TransportStyle transportStyle; TransportStyle transportStyle;
@ -98,23 +98,23 @@ namespace data
uint8_t cost; uint8_t cost;
std::unique_ptr<SSUExt> ssu; // not null for SSU std::unique_ptr<SSUExt> ssu; // not null for SSU
bool IsCompatible (const boost::asio::ip::address& other) const bool IsCompatible (const boost::asio::ip::address& other) const
{ {
return (host.is_v4 () && other.is_v4 ()) || return (host.is_v4 () && other.is_v4 ()) ||
(host.is_v6 () && other.is_v6 ()); (host.is_v6 () && other.is_v6 ());
} }
bool operator==(const Address& other) const bool operator==(const Address& other) const
{ {
return transportStyle == other.transportStyle && host == other.host && port == other.port; return transportStyle == other.transportStyle && host == other.host && port == other.port;
} }
bool operator!=(const Address& other) const bool operator!=(const Address& other) const
{ {
return !(*this == other); return !(*this == other);
} }
}; };
typedef std::list<std::shared_ptr<Address> > Addresses; typedef std::list<std::shared_ptr<Address> > Addresses;
RouterInfo (); RouterInfo ();
RouterInfo (const std::string& fullPath); RouterInfo (const std::string& fullPath);
@ -122,7 +122,7 @@ namespace data
RouterInfo& operator=(const RouterInfo& ) = default; RouterInfo& operator=(const RouterInfo& ) = default;
RouterInfo (const uint8_t * buf, int len); RouterInfo (const uint8_t * buf, int len);
~RouterInfo (); ~RouterInfo ();
std::shared_ptr<const IdentityEx> GetRouterIdentity () const { return m_RouterIdentity; }; std::shared_ptr<const IdentityEx> GetRouterIdentity () const { return m_RouterIdentity; };
void SetRouterIdentity (std::shared_ptr<const IdentityEx> identity); void SetRouterIdentity (std::shared_ptr<const IdentityEx> identity);
std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); }; std::string GetIdentHashBase64 () const { return GetIdentHash ().ToBase64 (); };
@ -131,7 +131,7 @@ namespace data
std::shared_ptr<const Address> GetNTCPAddress (bool v4only = true) const; std::shared_ptr<const Address> GetNTCPAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const; std::shared_ptr<const Address> GetSSUAddress (bool v4only = true) const;
std::shared_ptr<const Address> GetSSUV6Address () const; std::shared_ptr<const Address> GetSSUV6Address () const;
void AddNTCPAddress (const char * host, int port); void AddNTCPAddress (const char * host, int port);
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0); void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
bool AddIntroducer (const Introducer& introducer); bool AddIntroducer (const Introducer& introducer);
@ -156,37 +156,37 @@ namespace data
bool IsPeerTesting () const { return m_Caps & eSSUTesting; }; bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
bool IsHidden () const { return m_Caps & eHidden; }; bool IsHidden () const { return m_Caps & eHidden; };
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
uint8_t GetCaps () const { return m_Caps; }; uint8_t GetCaps () const { return m_Caps; };
void SetCaps (uint8_t caps); void SetCaps (uint8_t caps);
void SetCaps (const char * caps); void SetCaps (const char * caps);
void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; };
bool IsUnreachable () const { return m_IsUnreachable; }; bool IsUnreachable () const { return m_IsUnreachable; };
const uint8_t * GetBuffer () const { return m_Buffer; }; const uint8_t * GetBuffer () const { return m_Buffer; };
const uint8_t * LoadBuffer (); // load if necessary const uint8_t * LoadBuffer (); // load if necessary
int GetBufferLen () const { return m_BufferLen; }; int GetBufferLen () const { return m_BufferLen; };
void CreateBuffer (const PrivateKeys& privateKeys); void CreateBuffer (const PrivateKeys& privateKeys);
bool IsUpdated () const { return m_IsUpdated; }; bool IsUpdated () const { return m_IsUpdated; };
void SetUpdated (bool updated) { m_IsUpdated = updated; }; void SetUpdated (bool updated) { m_IsUpdated = updated; };
bool SaveToFile (const std::string& fullPath); bool SaveToFile (const std::string& fullPath);
std::shared_ptr<RouterProfile> GetProfile () const; std::shared_ptr<RouterProfile> GetProfile () const;
void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); }; void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
void Update (const uint8_t * buf, int len); void Update (const uint8_t * buf, int len);
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; }; void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
bool IsNewer (const uint8_t * buf, size_t len) const; bool IsNewer (const uint8_t * buf, size_t len) const;
/** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const;
/** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const;
// implements RoutingDestination // implements RoutingDestination
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; }; std::shared_ptr<const IdentityEx> GetIdentity () const { return m_RouterIdentity; };
void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const; void Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const;
bool IsDestination () const { return false; }; bool IsDestination () const { return false; };
@ -201,7 +201,7 @@ namespace data
void WriteString (const std::string& str, std::ostream& s) const; void WriteString (const std::string& str, std::ostream& s) const;
void ExtractCaps (const char * value); void ExtractCaps (const char * value);
std::shared_ptr<const Address> GetAddress (TransportStyle s, bool v4only, bool v6only = false) const; std::shared_ptr<const Address> GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
void UpdateCapsProperty (); void UpdateCapsProperty ();
private: private:
@ -210,13 +210,13 @@ namespace data
uint8_t * m_Buffer; uint8_t * m_Buffer;
size_t m_BufferLen; size_t m_BufferLen;
uint64_t m_Timestamp; uint64_t m_Timestamp;
boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9 boost::shared_ptr<Addresses> m_Addresses; // TODO: use std::shared_ptr and std::atomic_store for gcc >= 4.9
std::map<std::string, std::string> m_Properties; std::map<std::string, std::string> m_Properties;
bool m_IsUpdated, m_IsUnreachable; bool m_IsUpdated, m_IsUnreachable;
uint8_t m_SupportedTransports, m_Caps; uint8_t m_SupportedTransports, m_Caps;
mutable std::shared_ptr<RouterProfile> m_Profile; mutable std::shared_ptr<RouterProfile> m_Profile;
}; };
} }
} }
#endif #endif

View file

@ -13,32 +13,32 @@ namespace transport
SSUServer::SSUServer (const boost::asio::ip::address & addr, int port): SSUServer::SSUServer (const boost::asio::ip::address & addr, int port):
m_OnlyV6(true), m_IsRunning(false), m_OnlyV6(true), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr), m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint), m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service), m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service), m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
m_TerminationTimerV6 (m_ServiceV6) m_TerminationTimerV6 (m_ServiceV6)
{ {
OpenSocketV6 (); OpenSocketV6 ();
} }
SSUServer::SSUServer (int port): SSUServer::SSUServer (int port):
m_OnlyV6(false), m_IsRunning(false), m_OnlyV6(false), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr), m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6), m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6), m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port), m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6), m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service), m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service),
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6) m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6)
{ {
OpenSocket (); OpenSocket ();
if (context.SupportsV6 ()) if (context.SupportsV6 ())
OpenSocketV6 (); OpenSocketV6 ();
} }
SSUServer::~SSUServer () SSUServer::~SSUServer ()
{ {
} }
@ -46,11 +46,11 @@ namespace transport
void SSUServer::OpenSocket () void SSUServer::OpenSocket ()
{ {
m_Socket.open (boost::asio::ip::udp::v4()); m_Socket.open (boost::asio::ip::udp::v4());
m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE)); m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
m_Socket.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE)); m_Socket.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
m_Socket.bind (m_Endpoint); m_Socket.bind (m_Endpoint);
} }
void SSUServer::OpenSocketV6 () void SSUServer::OpenSocketV6 ()
{ {
m_SocketV6.open (boost::asio::ip::udp::v6()); m_SocketV6.open (boost::asio::ip::udp::v6());
@ -58,8 +58,8 @@ namespace transport
m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE)); m_SocketV6.set_option (boost::asio::socket_base::receive_buffer_size (SSU_SOCKET_RECEIVE_BUFFER_SIZE));
m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE)); m_SocketV6.set_option (boost::asio::socket_base::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
m_SocketV6.bind (m_EndpointV6); m_SocketV6.bind (m_EndpointV6);
} }
void SSUServer::Start () void SSUServer::Start ()
{ {
m_IsRunning = true; m_IsRunning = true;
@ -68,16 +68,16 @@ namespace transport
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this)); m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
m_Thread = new std::thread (std::bind (&SSUServer::Run, this)); m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
m_ReceiversService.post (std::bind (&SSUServer::Receive, this)); m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
ScheduleTermination (); ScheduleTermination ();
} }
if (context.SupportsV6 ()) if (context.SupportsV6 ())
{ {
m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this)); m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this)); m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this));
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this)); m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
ScheduleTerminationV6 (); ScheduleTerminationV6 ();
} }
SchedulePeerTestsCleanupTimer (); SchedulePeerTestsCleanupTimer ();
ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers
} }
@ -86,7 +86,7 @@ namespace transport
DeleteAllSessions (); DeleteAllSessions ();
m_IsRunning = false; m_IsRunning = false;
m_TerminationTimer.cancel (); m_TerminationTimer.cancel ();
m_TerminationTimerV6.cancel (); m_TerminationTimerV6.cancel ();
m_Service.stop (); m_Service.stop ();
m_Socket.close (); m_Socket.close ();
m_ServiceV6.stop (); m_ServiceV6.stop ();
@ -94,135 +94,135 @@ namespace transport
m_ReceiversService.stop (); m_ReceiversService.stop ();
m_ReceiversServiceV6.stop (); m_ReceiversServiceV6.stop ();
if (m_ReceiversThread) if (m_ReceiversThread)
{ {
m_ReceiversThread->join (); m_ReceiversThread->join ();
delete m_ReceiversThread; delete m_ReceiversThread;
m_ReceiversThread = nullptr; m_ReceiversThread = nullptr;
} }
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = nullptr; m_Thread = nullptr;
} }
if (m_ReceiversThreadV6) if (m_ReceiversThreadV6)
{ {
m_ReceiversThreadV6->join (); m_ReceiversThreadV6->join ();
delete m_ReceiversThreadV6; delete m_ReceiversThreadV6;
m_ReceiversThreadV6 = nullptr; m_ReceiversThreadV6 = nullptr;
} }
if (m_ThreadV6) if (m_ThreadV6)
{ {
m_ThreadV6->join (); m_ThreadV6->join ();
delete m_ThreadV6; delete m_ThreadV6;
m_ThreadV6 = nullptr; m_ThreadV6 = nullptr;
} }
} }
void SSUServer::Run () void SSUServer::Run ()
{ {
while (m_IsRunning) while (m_IsRunning)
{ {
try try
{ {
m_Service.run (); m_Service.run ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "SSU: server runtime exception: ", ex.what ()); LogPrint (eLogError, "SSU: server runtime exception: ", ex.what ());
} }
} }
} }
void SSUServer::RunV6 () void SSUServer::RunV6 ()
{ {
while (m_IsRunning) while (m_IsRunning)
{ {
try try
{ {
m_ServiceV6.run (); m_ServiceV6.run ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "SSU: v6 server runtime exception: ", ex.what ()); LogPrint (eLogError, "SSU: v6 server runtime exception: ", ex.what ());
} }
} }
} }
void SSUServer::RunReceivers () void SSUServer::RunReceivers ()
{ {
while (m_IsRunning) while (m_IsRunning)
{ {
try try
{ {
m_ReceiversService.run (); m_ReceiversService.run ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ()); LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
} }
} }
} }
void SSUServer::RunReceiversV6 () void SSUServer::RunReceiversV6 ()
{ {
while (m_IsRunning) while (m_IsRunning)
{ {
try try
{ {
m_ReceiversServiceV6.run (); m_ReceiversServiceV6.run ();
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ()); LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
} }
} }
} }
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay) void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
{ {
m_Relays[tag] = relay; m_Relays[tag] = relay;
} }
void SSUServer::RemoveRelay (uint32_t tag) void SSUServer::RemoveRelay (uint32_t tag)
{ {
m_Relays.erase (tag); m_Relays.erase (tag);
} }
std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag) std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
{ {
auto it = m_Relays.find (tag); auto it = m_Relays.find (tag);
if (it != m_Relays.end ()) if (it != m_Relays.end ())
{ {
if (it->second->GetState () == eSessionStateEstablished) if (it->second->GetState () == eSessionStateEstablished)
return it->second; return it->second;
else else
m_Relays.erase (it); m_Relays.erase (it);
} }
return nullptr; return nullptr;
} }
void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to) void SSUServer::Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to)
{ {
if (to.protocol () == boost::asio::ip::udp::v4()) if (to.protocol () == boost::asio::ip::udp::v4())
m_Socket.send_to (boost::asio::buffer (buf, len), to); m_Socket.send_to (boost::asio::buffer (buf, len), to);
else else
m_SocketV6.send_to (boost::asio::buffer (buf, len), to); m_SocketV6.send_to (boost::asio::buffer (buf, len), to);
} }
void SSUServer::Receive () void SSUServer::Receive ()
{ {
SSUPacket * packet = new SSUPacket (); SSUPacket * packet = new SSUPacket ();
m_Socket.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, m_Socket.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from,
std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet)); std::bind (&SSUServer::HandleReceivedFrom, this, std::placeholders::_1, std::placeholders::_2, packet));
} }
void SSUServer::ReceiveV6 () void SSUServer::ReceiveV6 ()
{ {
SSUPacket * packet = new SSUPacket (); SSUPacket * packet = new SSUPacket ();
m_SocketV6.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from, m_SocketV6.async_receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V6), packet->from,
std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet)); std::bind (&SSUServer::HandleReceivedFromV6, this, std::placeholders::_1, std::placeholders::_2, packet));
} }
void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet) void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
{ {
@ -235,13 +235,13 @@ namespace transport
boost::system::error_code ec; boost::system::error_code ec;
size_t moreBytes = m_Socket.available(ec); size_t moreBytes = m_Socket.available(ec);
if (!ec) if (!ec)
{ {
while (moreBytes && packets.size () < 25) while (moreBytes && packets.size () < 25)
{ {
packet = new SSUPacket (); packet = new SSUPacket ();
packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, 0, ec); packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, 0, ec);
if (!ec) if (!ec)
{ {
packets.push_back (packet); packets.push_back (packet);
moreBytes = m_Socket.available(ec); moreBytes = m_Socket.available(ec);
if (ec) break; if (ec) break;
@ -251,15 +251,15 @@ namespace transport
LogPrint (eLogError, "SSU: receive_from error: ", ec.message ()); LogPrint (eLogError, "SSU: receive_from error: ", ec.message ());
delete packet; delete packet;
break; break;
} }
} }
} }
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions)); m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions));
Receive (); Receive ();
} }
else else
{ {
delete packet; delete packet;
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
@ -268,7 +268,7 @@ namespace transport
OpenSocket (); OpenSocket ();
Receive (); Receive ();
} }
} }
} }
void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet) void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet)
@ -298,15 +298,15 @@ namespace transport
LogPrint (eLogError, "SSU: v6 receive_from error: ", ec.message ()); LogPrint (eLogError, "SSU: v6 receive_from error: ", ec.message ());
delete packet; delete packet;
break; break;
} }
} }
} }
m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6)); m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
ReceiveV6 (); ReceiveV6 ();
} }
else else
{ {
delete packet; delete packet;
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
@ -315,17 +315,17 @@ namespace transport
OpenSocketV6 (); OpenSocketV6 ();
ReceiveV6 (); ReceiveV6 ();
} }
} }
} }
void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets, void SSUServer::HandleReceivedPackets (std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions) std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > * sessions)
{ {
std::shared_ptr<SSUSession> session; std::shared_ptr<SSUSession> session;
for (auto& packet: packets) for (auto& packet: packets)
{ {
try try
{ {
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
{ {
if (session) session->FlushData (); if (session) session->FlushData ();
@ -341,13 +341,13 @@ namespace transport
} }
} }
session->ProcessNextMessage (packet->buf, packet->len, packet->from); session->ProcessNextMessage (packet->buf, packet->len, packet->from);
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ()); LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ());
if (session) session->FlushData (); if (session) session->FlushData ();
session = nullptr; session = nullptr;
} }
delete packet; delete packet;
} }
if (session) session->FlushData (); if (session) session->FlushData ();
@ -357,26 +357,26 @@ namespace transport
{ {
if (!router) return nullptr; if (!router) return nullptr;
auto address = router->GetSSUAddress (true); // v4 only auto address = router->GetSSUAddress (true); // v4 only
if (!address) return nullptr; if (!address) return nullptr;
auto session = FindSession (boost::asio::ip::udp::endpoint (address->host, address->port)); auto session = FindSession (boost::asio::ip::udp::endpoint (address->host, address->port));
if (session || !context.SupportsV6 ()) if (session || !context.SupportsV6 ())
return session; return session;
// try v6 // try v6
address = router->GetSSUV6Address (); address = router->GetSSUV6Address ();
if (!address) return nullptr; if (!address) return nullptr;
return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port)); return FindSession (boost::asio::ip::udp::endpoint (address->host, address->port));
} }
std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const std::shared_ptr<SSUSession> SSUServer::FindSession (const boost::asio::ip::udp::endpoint& e) const
{ {
auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions; auto& sessions = e.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto it = sessions.find (e); auto it = sessions.find (e);
if (it != sessions.end ()) if (it != sessions.end ())
return it->second; return it->second;
else else
return nullptr; return nullptr;
} }
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest, bool v4only) void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest, bool v4only)
{ {
auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ()); auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ());
@ -385,7 +385,7 @@ namespace transport
else else
LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address"); LogPrint (eLogWarning, "SSU: Router ", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), " doesn't have SSU address");
} }
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
const boost::asio::ip::address& addr, int port, bool peerTest) const boost::asio::ip::address& addr, int port, bool peerTest)
{ {
@ -403,27 +403,27 @@ namespace transport
} }
void SSUServer::CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest) void SSUServer::CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest)
{ {
auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions; auto& sessions = remoteEndpoint.address ().is_v6 () ? m_SessionsV6 : m_Sessions;
auto it = sessions.find (remoteEndpoint); auto it = sessions.find (remoteEndpoint);
if (it != sessions.end ()) if (it != sessions.end ())
{ {
auto session = it->second; auto session = it->second;
if (peerTest && session->GetState () == eSessionStateEstablished) if (peerTest && session->GetState () == eSessionStateEstablished)
session->SendPeerTest (); session->SendPeerTest ();
} }
else else
{ {
// otherwise create new session // otherwise create new session
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest); auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
sessions[remoteEndpoint] = session; sessions[remoteEndpoint] = session;
// connect // connect
LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ", LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ()); remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
session->Connect (); session->Connect ();
} }
} }
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest) void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
{ {
if (router && router->UsesIntroducer ()) if (router && router->UsesIntroducer ())
@ -435,13 +435,13 @@ namespace transport
auto it = m_Sessions.find (remoteEndpoint); auto it = m_Sessions.find (remoteEndpoint);
// check if session is presented already // check if session is presented already
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
{ {
auto session = it->second; auto session = it->second;
if (peerTest && session->GetState () == eSessionStateEstablished) if (peerTest && session->GetState () == eSessionStateEstablished)
session->SendPeerTest (); session->SendPeerTest ();
return; return;
} }
// create new session // create new session
int numIntroducers = address->ssu->introducers.size (); int numIntroducers = address->ssu->introducers.size ();
if (numIntroducers > 0) if (numIntroducers > 0)
{ {
@ -455,52 +455,52 @@ namespace transport
if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort); boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
if (ep.address ().is_v4 ()) // ipv4 only if (ep.address ().is_v4 ()) // ipv4 only
{ {
if (!introducer) introducer = intr; // we pick first one for now if (!introducer) introducer = intr; // we pick first one for now
it = m_Sessions.find (ep); it = m_Sessions.find (ep);
if (it != m_Sessions.end ()) if (it != m_Sessions.end ())
{ {
introducerSession = it->second; introducerSession = it->second;
break; break;
} }
} }
} }
if (!introducer) if (!introducer)
{ {
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented"); LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented");
return; return;
} }
if (introducerSession) // session found if (introducerSession) // session found
LogPrint (eLogWarning, "SSU: Session to introducer already exists"); LogPrint (eLogWarning, "SSU: Session to introducer already exists");
else // create new else // create new
{ {
LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost); LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost);
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort); boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router); introducerSession = std::make_shared<SSUSession> (*this, introducerEndpoint, router);
m_Sessions[introducerEndpoint] = introducerSession; m_Sessions[introducerEndpoint] = introducerSession;
} }
#if BOOST_VERSION >= 104900 #if BOOST_VERSION >= 104900
if (!address->host.is_unspecified () && address->port) if (!address->host.is_unspecified () && address->port)
#endif #endif
{ {
// create session // create session
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest); auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
m_Sessions[remoteEndpoint] = session; m_Sessions[remoteEndpoint] = session;
// introduce // introduce
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
"] through introducer ", introducer->iHost, ":", introducer->iPort); "] through introducer ", introducer->iHost, ":", introducer->iPort);
session->WaitForIntroduction (); session->WaitForIntroduction ();
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
{ {
uint8_t buf[1]; uint8_t buf[1];
Send (buf, 0, remoteEndpoint); // send HolePunch Send (buf, 0, remoteEndpoint); // send HolePunch
} }
} }
introducerSession->Introduce (*introducer, router); introducerSession->Introduce (*introducer, router);
} }
else else
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present"); LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
} }
else else
@ -518,8 +518,8 @@ namespace transport
m_SessionsV6.erase (ep); m_SessionsV6.erase (ep);
else else
m_Sessions.erase (ep); m_Sessions.erase (ep);
} }
} }
void SSUServer::DeleteAllSessions () void SSUServer::DeleteAllSessions ()
{ {
@ -543,15 +543,15 @@ namespace transport
auto ind = rand () % filteredSessions.size (); auto ind = rand () % filteredSessions.size ();
return filteredSessions[ind]; return filteredSessions[ind];
} }
return nullptr; return nullptr;
} }
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only
{ {
return GetRandomV4Session ( return GetRandomV4Session (
[excluded](std::shared_ptr<SSUSession> session)->bool [excluded](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetState () == eSessionStateEstablished && session != excluded; return session->GetState () == eSessionStateEstablished && session != excluded;
} }
); );
} }
@ -567,15 +567,15 @@ namespace transport
auto ind = rand () % filteredSessions.size (); auto ind = rand () % filteredSessions.size ();
return filteredSessions[ind]; return filteredSessions[ind];
} }
return nullptr; return nullptr;
} }
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded) // v6 only std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded) // v6 only
{ {
return GetRandomV6Session ( return GetRandomV6Session (
[excluded](std::shared_ptr<SSUSession> session)->bool [excluded](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetState () == eSessionStateEstablished && session != excluded; return session->GetState () == eSessionStateEstablished && session != excluded;
} }
); );
} }
@ -587,18 +587,18 @@ namespace transport
for (int i = 0; i < maxNumIntroducers; i++) for (int i = 0; i < maxNumIntroducers; i++)
{ {
auto session = GetRandomV4Session ( auto session = GetRandomV4Session (
[&ret, ts](std::shared_ptr<SSUSession> session)->bool [&ret, ts](std::shared_ptr<SSUSession> session)->bool
{ {
return session->GetRelayTag () && !ret.count (session.get ()) && return session->GetRelayTag () && !ret.count (session.get ()) &&
session->GetState () == eSessionStateEstablished && session->GetState () == eSessionStateEstablished &&
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION; ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
} }
); );
if (session) if (session)
{ {
ret.insert (session.get ()); ret.insert (session.get ());
break; break;
} }
} }
return ret; return ret;
} }
@ -607,7 +607,7 @@ namespace transport
{ {
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL)); m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer, m_IntroducersUpdateTimer.async_wait (std::bind (&SSUServer::HandleIntroducersUpdateTimer,
this, std::placeholders::_1)); this, std::placeholders::_1));
} }
void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode) void SSUServer::HandleIntroducersUpdateTimer (const boost::system::error_code& ecode)
@ -620,7 +620,7 @@ namespace transport
// we still don't know if we need introducers // we still don't know if we need introducers
ScheduleIntroducersUpdateTimer (); ScheduleIntroducersUpdateTimer ();
return; return;
} }
if (i2p::context.GetStatus () == eRouterStatusOK) return; // we don't need introducers anymore if (i2p::context.GetStatus () == eRouterStatusOK) return; // we don't need introducers anymore
// we are firewalled // we are firewalled
if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable (); if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable ();
@ -628,7 +628,7 @@ namespace transport
size_t numIntroducers = 0; size_t numIntroducers = 0;
uint32_t ts = i2p::util::GetSecondsSinceEpoch (); uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
for (const auto& it : m_Introducers) for (const auto& it : m_Introducers)
{ {
auto session = FindSession (it); auto session = FindSession (it);
if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION) if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION)
{ {
@ -636,7 +636,7 @@ namespace transport
newList.push_back (it); newList.push_back (it);
numIntroducers++; numIntroducers++;
} }
else else
i2p::context.RemoveIntroducer (it); i2p::context.RemoveIntroducer (it);
} }
@ -658,16 +658,16 @@ namespace transport
if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break; if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break;
} }
} }
} }
m_Introducers = newList; m_Introducers = newList;
if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS) if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS)
{ {
auto introducer = i2p::data::netdb.GetRandomIntroducer (); auto introducer = i2p::data::netdb.GetRandomIntroducer ();
if (introducer) if (introducer)
CreateSession (introducer); CreateSession (introducer);
} }
ScheduleIntroducersUpdateTimer (); ScheduleIntroducersUpdateTimer ();
} }
} }
void SSUServer::NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session) void SSUServer::NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session)
@ -682,7 +682,7 @@ namespace transport
return it->second.role; return it->second.role;
else else
return ePeerTestParticipantUnknown; return ePeerTestParticipantUnknown;
} }
std::shared_ptr<SSUSession> SSUServer::GetPeerTestSession (uint32_t nonce) std::shared_ptr<SSUSession> SSUServer::GetPeerTestSession (uint32_t nonce)
{ {
@ -698,26 +698,26 @@ namespace transport
auto it = m_PeerTests.find (nonce); auto it = m_PeerTests.find (nonce);
if (it != m_PeerTests.end ()) if (it != m_PeerTests.end ())
it->second.role = role; it->second.role = role;
} }
void SSUServer::RemovePeerTest (uint32_t nonce) void SSUServer::RemovePeerTest (uint32_t nonce)
{ {
m_PeerTests.erase (nonce); m_PeerTests.erase (nonce);
} }
void SSUServer::SchedulePeerTestsCleanupTimer () void SSUServer::SchedulePeerTestsCleanupTimer ()
{ {
m_PeerTestsCleanupTimer.expires_from_now (boost::posix_time::seconds(SSU_PEER_TEST_TIMEOUT)); m_PeerTestsCleanupTimer.expires_from_now (boost::posix_time::seconds(SSU_PEER_TEST_TIMEOUT));
m_PeerTestsCleanupTimer.async_wait (std::bind (&SSUServer::HandlePeerTestsCleanupTimer, m_PeerTestsCleanupTimer.async_wait (std::bind (&SSUServer::HandlePeerTestsCleanupTimer,
this, std::placeholders::_1)); this, std::placeholders::_1));
} }
void SSUServer::HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode) void SSUServer::HandlePeerTestsCleanupTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
int numDeleted = 0; int numDeleted = 0;
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();) for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();)
{ {
if (ts > it->second.creationTime + SSU_PEER_TEST_TIMEOUT*1000LL) if (ts > it->second.creationTime + SSU_PEER_TEST_TIMEOUT*1000LL)
@ -744,21 +744,21 @@ namespace transport
void SSUServer::HandleTerminationTimer (const boost::system::error_code& ecode) void SSUServer::HandleTerminationTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto& it: m_Sessions) for (auto& it: m_Sessions)
if (it.second->IsTerminationTimeoutExpired (ts)) if (it.second->IsTerminationTimeoutExpired (ts))
{ {
auto session = it.second; auto session = it.second;
m_Service.post ([session] m_Service.post ([session]
{ {
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds"); LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
session->Failed (); session->Failed ();
}); });
} }
ScheduleTermination (); ScheduleTermination ();
} }
} }
void SSUServer::ScheduleTerminationV6 () void SSUServer::ScheduleTerminationV6 ()
{ {
@ -770,21 +770,21 @@ namespace transport
void SSUServer::HandleTerminationTimerV6 (const boost::system::error_code& ecode) void SSUServer::HandleTerminationTimerV6 (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
{ {
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto& it: m_SessionsV6) for (auto& it: m_SessionsV6)
if (it.second->IsTerminationTimeoutExpired (ts)) if (it.second->IsTerminationTimeoutExpired (ts))
{ {
auto session = it.second; auto session = it.second;
m_ServiceV6.post ([session] m_ServiceV6.post ([session]
{ {
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds"); LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
session->Failed (); session->Failed ();
}); });
} }
ScheduleTerminationV6 (); ScheduleTerminationV6 ();
} }
} }
} }
} }

View file

@ -20,8 +20,8 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
const int SSU_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds const int SSU_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
const size_t SSU_MAX_NUM_INTRODUCERS = 3; const size_t SSU_MAX_NUM_INTRODUCERS = 3;
@ -33,8 +33,8 @@ namespace transport
i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size i2p::crypto::AESAlignedBuffer<SSU_MTU_V6 + 18> buf; // max MTU + iv + size
boost::asio::ip::udp::endpoint from; boost::asio::ip::udp::endpoint from;
size_t len; size_t len;
}; };
class SSUServer class SSUServer
{ {
public: public:
@ -45,7 +45,7 @@ namespace transport
void Start (); void Start ();
void Stop (); void Stop ();
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false); void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false, bool v4only = false);
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
const boost::asio::ip::address& addr, int port, bool peerTest = false); const boost::asio::ip::address& addr, int port, bool peerTest = false);
void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest); void CreateDirectSession (std::shared_ptr<const i2p::data::RouterInfo> router, boost::asio::ip::udp::endpoint remoteEndpoint, bool peerTest);
std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const; std::shared_ptr<SSUSession> FindSession (std::shared_ptr<const i2p::data::RouterInfo> router) const;
@ -53,11 +53,11 @@ namespace transport
std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded); std::shared_ptr<SSUSession> GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded);
std::shared_ptr<SSUSession> GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded); std::shared_ptr<SSUSession> GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded);
void DeleteSession (std::shared_ptr<SSUSession> session); void DeleteSession (std::shared_ptr<SSUSession> session);
void DeleteAllSessions (); void DeleteAllSessions ();
boost::asio::io_service& GetService () { return m_Service; }; boost::asio::io_service& GetService () { return m_Service; };
boost::asio::io_service& GetServiceV6 () { return m_ServiceV6; }; boost::asio::io_service& GetServiceV6 () { return m_ServiceV6; };
const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; };
void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); void Send (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to);
void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay); void AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
void RemoveRelay (uint32_t tag); void RemoveRelay (uint32_t tag);
@ -68,7 +68,7 @@ namespace transport
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce); std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role); void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
void RemovePeerTest (uint32_t nonce); void RemovePeerTest (uint32_t nonce);
private: private:
void OpenSocket (); void OpenSocket ();
@ -84,13 +84,13 @@ namespace transport
void HandleReceivedPackets (std::vector<SSUPacket *> packets, void HandleReceivedPackets (std::vector<SSUPacket *> packets,
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions); std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> >* sessions);
void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false); void CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest = false);
template<typename Filter> template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter); std::shared_ptr<SSUSession> GetRandomV4Session (Filter filter);
template<typename Filter> template<typename Filter>
std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter); std::shared_ptr<SSUSession> GetRandomV6Session (Filter filter);
std::set<SSUSession *> FindIntroducers (int maxNumIntroducers); std::set<SSUSession *> FindIntroducers (int maxNumIntroducers);
void ScheduleIntroducersUpdateTimer (); void ScheduleIntroducersUpdateTimer ();
void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode); void HandleIntroducersUpdateTimer (const boost::system::error_code& ecode);
@ -111,10 +111,10 @@ namespace transport
PeerTestParticipant role; PeerTestParticipant role;
std::shared_ptr<SSUSession> session; // for Bob to Alice std::shared_ptr<SSUSession> session; // for Bob to Alice
}; };
bool m_OnlyV6; bool m_OnlyV6;
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread, * m_ReceiversThreadV6; std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread, * m_ReceiversThreadV6;
boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService, m_ReceiversServiceV6; boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService, m_ReceiversServiceV6;
boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork, m_ReceiversWorkV6; boost::asio::io_service::work m_Work, m_WorkV6, m_ReceiversWork, m_ReceiversWorkV6;
boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6; boost::asio::ip::udp::endpoint m_Endpoint, m_EndpointV6;
@ -125,7 +125,7 @@ namespace transport
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6; std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSUSession> > m_Sessions, m_SessionsV6;
std::map<uint32_t, std::shared_ptr<SSUSession> > m_Relays; // we are introducer std::map<uint32_t, std::shared_ptr<SSUSession> > m_Relays; // we are introducer
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
public: public:
// for HTTP only // for HTTP only
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; }; const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };

View file

@ -28,9 +28,9 @@ namespace transport
} }
SSUData::SSUData (SSUSession& session): SSUData::SSUData (SSUSession& session):
m_Session (session), m_ResendTimer (session.GetService ()), m_Session (session), m_ResendTimer (session.GetService ()),
m_IncompleteMessagesCleanupTimer (session.GetService ()), m_IncompleteMessagesCleanupTimer (session.GetService ()),
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE), m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0) m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0)
{ {
} }
@ -42,8 +42,8 @@ namespace transport
void SSUData::Start () void SSUData::Start ()
{ {
ScheduleIncompleteMessagesCleanup (); ScheduleIncompleteMessagesCleanup ();
} }
void SSUData::Stop () void SSUData::Stop ()
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
@ -51,8 +51,8 @@ namespace transport
m_IncompleteMessages.clear (); m_IncompleteMessages.clear ();
m_SentMessages.clear (); m_SentMessages.clear ();
m_ReceivedMessages.clear (); m_ReceivedMessages.clear ();
} }
void SSUData::AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter) void SSUData::AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter)
{ {
if (!remoteRouter) return; if (!remoteRouter) return;
@ -72,16 +72,16 @@ namespace transport
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize); LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
} }
else else
{ {
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu); LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
m_PacketSize = m_MaxPacketSize; m_PacketSize = m_MaxPacketSize;
} }
} }
} }
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent) void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
{ {
auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent); auto routerInfo = i2p::data::netdb.FindRouter (remoteIdent);
if (routerInfo) if (routerInfo)
AdjustPacketSize (routerInfo); AdjustPacketSize (routerInfo);
} }
@ -91,11 +91,11 @@ namespace transport
auto it = m_SentMessages.find (msgID); auto it = m_SentMessages.find (msgID);
if (it != m_SentMessages.end ()) if (it != m_SentMessages.end ())
{ {
m_SentMessages.erase (it); m_SentMessages.erase (it);
if (m_SentMessages.empty ()) if (m_SentMessages.empty ())
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
} }
} }
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag) void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
{ {
@ -117,7 +117,7 @@ namespace transport
{ {
uint32_t msgID = bufbe32toh (buf); uint32_t msgID = bufbe32toh (buf);
buf += 4; // msgID buf += 4; // msgID
auto it = m_SentMessages.find (msgID); auto it = m_SentMessages.find (msgID);
// process individual Ack bitfields // process individual Ack bitfields
bool isNonLast = false; bool isNonLast = false;
int fragment = 0; int fragment = 0;
@ -127,26 +127,26 @@ namespace transport
isNonLast = bitfield & 0x80; isNonLast = bitfield & 0x80;
bitfield &= 0x7F; // clear MSB bitfield &= 0x7F; // clear MSB
if (bitfield && it != m_SentMessages.end ()) if (bitfield && it != m_SentMessages.end ())
{ {
int numSentFragments = it->second->fragments.size (); int numSentFragments = it->second->fragments.size ();
// process bits // process bits
uint8_t mask = 0x01; uint8_t mask = 0x01;
for (int j = 0; j < 7; j++) for (int j = 0; j < 7; j++)
{ {
if (bitfield & mask) if (bitfield & mask)
{ {
if (fragment < numSentFragments) if (fragment < numSentFragments)
it->second->fragments[fragment].reset (nullptr); it->second->fragments[fragment].reset (nullptr);
} }
fragment++; fragment++;
mask <<= 1; mask <<= 1;
} }
} }
buf++; buf++;
} }
while (isNonLast); while (isNonLast);
} }
} }
} }
void SSUData::ProcessFragments (uint8_t * buf) void SSUData::ProcessFragments (uint8_t * buf)
@ -154,7 +154,7 @@ namespace transport
uint8_t numFragments = *buf; // number of fragments uint8_t numFragments = *buf; // number of fragments
buf++; buf++;
for (int i = 0; i < numFragments; i++) for (int i = 0; i < numFragments; i++)
{ {
uint32_t msgID = bufbe32toh (buf); // message ID uint32_t msgID = bufbe32toh (buf); // message ID
buf += 4; buf += 4;
uint8_t frag[4] = {0}; uint8_t frag[4] = {0};
@ -162,8 +162,8 @@ namespace transport
buf += 3; buf += 3;
uint32_t fragmentInfo = bufbe32toh (frag); // fragment info uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13 uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13
bool isLast = fragmentInfo & 0x010000; // bit 16 bool isLast = fragmentInfo & 0x010000; // bit 16
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17 uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE) if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
{ {
LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size"); LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
@ -172,12 +172,12 @@ namespace transport
// find message with msgID // find message with msgID
auto it = m_IncompleteMessages.find (msgID); auto it = m_IncompleteMessages.find (msgID);
if (it == m_IncompleteMessages.end ()) if (it == m_IncompleteMessages.end ())
{ {
// create new message // create new message
auto msg = NewI2NPShortMessage (); auto msg = NewI2NPShortMessage ();
msg->len -= I2NP_SHORT_HEADER_SIZE; msg->len -= I2NP_SHORT_HEADER_SIZE;
it = m_IncompleteMessages.insert (std::make_pair (msgID, it = m_IncompleteMessages.insert (std::make_pair (msgID,
std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first; std::unique_ptr<IncompleteMessage>(new IncompleteMessage (msg)))).first;
} }
std::unique_ptr<IncompleteMessage>& incompleteMessage = it->second; std::unique_ptr<IncompleteMessage>& incompleteMessage = it->second;
@ -204,10 +204,10 @@ namespace transport
} }
if (isLast) if (isLast)
LogPrint (eLogDebug, "SSU: Message ", msgID, " complete"); LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
} }
} }
else else
{ {
if (fragmentNum < incompleteMessage->nextFragmentNum) if (fragmentNum < incompleteMessage->nextFragmentNum)
// duplicate fragment // duplicate fragment
LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored"); LogPrint (eLogWarning, "SSU: Duplicate fragment ", (int)fragmentNum, " of message ", msgID, ", ignored");
@ -218,28 +218,28 @@ namespace transport
auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast); auto savedFragment = new Fragment (fragmentNum, buf, fragmentSize, isLast);
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second) if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch (); incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
else else
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved"); LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
} }
isLast = false; isLast = false;
} }
if (isLast) if (isLast)
{ {
// delete incomplete message // delete incomplete message
auto msg = incompleteMessage->msg; auto msg = incompleteMessage->msg;
incompleteMessage->msg = nullptr; incompleteMessage->msg = nullptr;
m_IncompleteMessages.erase (msgID); m_IncompleteMessages.erase (msgID);
// process message // process message
SendMsgAck (msgID); SendMsgAck (msgID);
msg->FromSSU (msgID); msg->FromSSU (msgID);
if (m_Session.GetState () == eSessionStateEstablished) if (m_Session.GetState () == eSessionStateEstablished)
{ {
if (!m_ReceivedMessages.count (msgID)) if (!m_ReceivedMessages.count (msgID))
{ {
m_ReceivedMessages.insert (msgID); m_ReceivedMessages.insert (msgID);
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch (); m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
if (!msg->IsExpired ()) if (!msg->IsExpired ())
{ {
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
QueueIntEvent("transport.recvmsg", m_Session.GetIdentHashBase64(), 1); QueueIntEvent("transport.recvmsg", m_Session.GetIdentHashBase64(), 1);
@ -248,10 +248,10 @@ namespace transport
} }
else else
LogPrint (eLogDebug, "SSU: message expired"); LogPrint (eLogDebug, "SSU: message expired");
} }
else else
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received"); LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
} }
else else
{ {
// we expect DeliveryStatus // we expect DeliveryStatus
@ -259,22 +259,22 @@ namespace transport
{ {
LogPrint (eLogDebug, "SSU: session established"); LogPrint (eLogDebug, "SSU: session established");
m_Session.Established (); m_Session.Established ();
} }
else else
LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ()); LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
} }
} }
else else
SendFragmentAck (msgID, fragmentNum); SendFragmentAck (msgID, fragmentNum);
buf += fragmentSize; buf += fragmentSize;
} }
} }
void SSUData::FlushReceivedMessage () void SSUData::FlushReceivedMessage ()
{ {
m_Handler.Flush (); m_Handler.Flush ();
} }
void SSUData::ProcessMessage (uint8_t * buf, size_t len) void SSUData::ProcessMessage (uint8_t * buf, size_t len)
{ {
//uint8_t * start = buf; //uint8_t * start = buf;
@ -303,25 +303,25 @@ namespace transport
{ {
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent"); LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
return; return;
} }
if (m_SentMessages.empty ()) // schedule resend at first message only if (m_SentMessages.empty ()) // schedule resend at first message only
ScheduleResend (); ScheduleResend ();
auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr<SentMessage>(new SentMessage))); auto ret = m_SentMessages.insert (std::make_pair (msgID, std::unique_ptr<SentMessage>(new SentMessage)));
std::unique_ptr<SentMessage>& sentMessage = ret.first->second; std::unique_ptr<SentMessage>& sentMessage = ret.first->second;
if (ret.second) if (ret.second)
{ {
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL; sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
sentMessage->numResends = 0; sentMessage->numResends = 0;
} }
auto& fragments = sentMessage->fragments; auto& fragments = sentMessage->fragments;
size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3) size_t payloadSize = m_PacketSize - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3)
size_t len = msg->GetLength (); size_t len = msg->GetLength ();
uint8_t * msgBuf = msg->GetSSUHeader (); uint8_t * msgBuf = msg->GetSSUHeader ();
uint32_t fragmentNum = 0; uint32_t fragmentNum = 0;
while (len > 0) while (len > 0)
{ {
Fragment * fragment = new Fragment; Fragment * fragment = new Fragment;
fragment->fragmentNum = fragmentNum; fragment->fragmentNum = fragmentNum;
uint8_t * buf = fragment->buf; uint8_t * buf = fragment->buf;
@ -337,39 +337,39 @@ namespace transport
uint32_t fragmentInfo = (fragmentNum << 17); uint32_t fragmentInfo = (fragmentNum << 17);
if (isLast) if (isLast)
fragmentInfo |= 0x010000; fragmentInfo |= 0x010000;
fragmentInfo |= size; fragmentInfo |= size;
fragmentInfo = htobe32 (fragmentInfo); fragmentInfo = htobe32 (fragmentInfo);
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3); memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
payload += 3; payload += 3;
memcpy (payload, msgBuf, size); memcpy (payload, msgBuf, size);
size += payload - buf; size += payload - buf;
if (size & 0x0F) // make sure 16 bytes boundary if (size & 0x0F) // make sure 16 bytes boundary
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16 size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
fragment->len = size; fragment->len = size;
fragments.push_back (std::unique_ptr<Fragment> (fragment)); fragments.push_back (std::unique_ptr<Fragment> (fragment));
// encrypt message with session key // encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size); m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
try try
{ {
m_Session.Send (buf, size); m_Session.Send (buf, size);
} }
catch (boost::system::system_error& ec) catch (boost::system::system_error& ec)
{ {
LogPrint (eLogWarning, "SSU: Can't send data fragment ", ec.what ()); LogPrint (eLogWarning, "SSU: Can't send data fragment ", ec.what ());
} }
if (!isLast) if (!isLast)
{ {
len -= payloadSize; len -= payloadSize;
msgBuf += payloadSize; msgBuf += payloadSize;
} }
else else
len = 0; len = 0;
fragmentNum++; fragmentNum++;
} }
} }
void SSUData::SendMsgAck (uint32_t msgID) void SSUData::SendMsgAck (uint32_t msgID)
{ {
@ -398,27 +398,27 @@ namespace transport
uint8_t buf[64 + 18] = {0}; uint8_t buf[64 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag *payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
payload++; payload++;
*payload = 1; // number of ACK bitfields *payload = 1; // number of ACK bitfields
payload++; payload++;
// one ack // one ack
*(uint32_t *)(payload) = htobe32 (msgID); // msgID *(uint32_t *)(payload) = htobe32 (msgID); // msgID
payload += 4; payload += 4;
div_t d = div (fragmentNum, 7); div_t d = div (fragmentNum, 7);
memset (payload, 0x80, d.quot); // 0x80 means non-last memset (payload, 0x80, d.quot); // 0x80 means non-last
payload += d.quot; payload += d.quot;
*payload = 0x01 << d.rem; // set corresponding bit *payload = 0x01 << d.rem; // set corresponding bit
payload++; payload++;
*payload = 0; // number of fragments *payload = 0; // number of fragments
size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1) size_t len = d.quot < 4 ? 48 : 64; // 48 = 37 + 7 + 4 (3+1)
// encrypt message with session key // encrypt message with session key
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len); m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
m_Session.Send (buf, len); m_Session.Send (buf, len);
} }
void SSUData::ScheduleResend() void SSUData::ScheduleResend()
{ {
m_ResendTimer.cancel (); m_ResendTimer.cancel ();
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL)); m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
auto s = m_Session.shared_from_this(); auto s = m_Session.shared_from_this();
@ -435,7 +435,7 @@ namespace transport
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();) for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
{ {
if (ts >= it->second->nextResendTime) if (ts >= it->second->nextResendTime)
{ {
if (it->second->numResends < MAX_NUM_RESENDS) if (it->second->numResends < MAX_NUM_RESENDS)
{ {
for (auto& f: it->second->fragments) for (auto& f: it->second->fragments)
@ -455,13 +455,13 @@ namespace transport
it->second->numResends++; it->second->numResends++;
it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL; it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
++it; ++it;
} }
else else
{ {
LogPrint (eLogInfo, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted"); LogPrint (eLogInfo, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
it = m_SentMessages.erase (it); it = m_SentMessages.erase (it);
} }
} }
else else
++it; ++it;
} }
@ -472,9 +472,9 @@ namespace transport
{ {
LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated"); LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
m_Session.Close (); m_Session.Close ();
} }
} }
} }
void SSUData::ScheduleIncompleteMessagesCleanup () void SSUData::ScheduleIncompleteMessagesCleanup ()
{ {
@ -484,7 +484,7 @@ namespace transport
m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode) m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode)
{ s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); }); { s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); });
} }
void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode) void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
@ -496,18 +496,18 @@ namespace transport
{ {
LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted"); LogPrint (eLogWarning, "SSU: message ", it->first, " was not completed in ", INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
it = m_IncompleteMessages.erase (it); it = m_IncompleteMessages.erase (it);
} }
else else
++it; ++it;
} }
// decay // decay
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES || if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES ||
i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL) i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL)
m_ReceivedMessages.clear (); m_ReceivedMessages.clear ();
ScheduleIncompleteMessagesCleanup (); ScheduleIncompleteMessagesCleanup ();
} }
} }
} }
} }

View file

@ -24,7 +24,7 @@ namespace transport
const size_t SSU_MTU_V6 = 1488; const size_t SSU_MTU_V6 = 1488;
#endif #endif
const size_t IPV4_HEADER_SIZE = 20; const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40; const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8; const size_t UDP_HEADER_SIZE = 8;
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456 const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440 const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440
@ -40,7 +40,7 @@ namespace transport
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08; const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10; const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40; const uint8_t DATA_FLAG_ACK_BITFIELDS_INCLUDED = 0x40;
const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80; const uint8_t DATA_FLAG_EXPLICIT_ACKS_INCLUDED = 0x80;
struct Fragment struct Fragment
{ {
@ -50,27 +50,27 @@ namespace transport
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
Fragment () = default; Fragment () = default;
Fragment (int n, const uint8_t * b, int l, bool last): Fragment (int n, const uint8_t * b, int l, bool last):
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); }; fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
}; };
struct FragmentCmp struct FragmentCmp
{ {
bool operator() (const std::unique_ptr<Fragment>& f1, const std::unique_ptr<Fragment>& f2) const bool operator() (const std::unique_ptr<Fragment>& f1, const std::unique_ptr<Fragment>& f2) const
{ {
return f1->fragmentNum < f2->fragmentNum; return f1->fragmentNum < f2->fragmentNum;
}; };
}; };
struct IncompleteMessage struct IncompleteMessage
{ {
std::shared_ptr<I2NPMessage> msg; std::shared_ptr<I2NPMessage> msg;
int nextFragmentNum; int nextFragmentNum;
uint32_t lastFragmentInsertTime; // in seconds uint32_t lastFragmentInsertTime; // in seconds
std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments; std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments;
IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {}; IncompleteMessage (std::shared_ptr<I2NPMessage> m): msg (m), nextFragmentNum (0), lastFragmentInsertTime (0) {};
void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize);
}; };
struct SentMessage struct SentMessage
@ -78,24 +78,24 @@ namespace transport
std::vector<std::unique_ptr<Fragment> > fragments; std::vector<std::unique_ptr<Fragment> > fragments;
uint32_t nextResendTime; // in seconds uint32_t nextResendTime; // in seconds
int numResends; int numResends;
}; };
class SSUSession; class SSUSession;
class SSUData class SSUData
{ {
public: public:
SSUData (SSUSession& session); SSUData (SSUSession& session);
~SSUData (); ~SSUData ();
void Start (); void Start ();
void Stop (); void Stop ();
void ProcessMessage (uint8_t * buf, size_t len); void ProcessMessage (uint8_t * buf, size_t len);
void FlushReceivedMessage (); void FlushReceivedMessage ();
void Send (std::shared_ptr<i2p::I2NPMessage> msg); void Send (std::shared_ptr<i2p::I2NPMessage> msg);
void AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter); void AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter);
void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent); void UpdatePacketSize (const i2p::data::IdentHash& remoteIdent);
private: private:
@ -104,16 +104,16 @@ namespace transport
void SendFragmentAck (uint32_t msgID, int fragmentNum); void SendFragmentAck (uint32_t msgID, int fragmentNum);
void ProcessAcks (uint8_t *& buf, uint8_t flag); void ProcessAcks (uint8_t *& buf, uint8_t flag);
void ProcessFragments (uint8_t * buf); void ProcessFragments (uint8_t * buf);
void ProcessSentMessageAck (uint32_t msgID); void ProcessSentMessageAck (uint32_t msgID);
void ScheduleResend (); void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode); void HandleResendTimer (const boost::system::error_code& ecode);
void ScheduleIncompleteMessagesCleanup (); void ScheduleIncompleteMessagesCleanup ();
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode); void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
private: private:
SSUSession& m_Session; SSUSession& m_Session;
std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages; std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
@ -123,7 +123,7 @@ namespace transport
int m_MaxPacketSize, m_PacketSize; int m_MaxPacketSize, m_PacketSize;
i2p::I2NPMessagesHandler m_Handler; i2p::I2NPMessagesHandler m_Handler;
uint32_t m_LastMessageReceivedTime; // in second uint32_t m_LastMessageReceivedTime; // in second
}; };
} }
} }

View file

@ -13,12 +13,12 @@ namespace i2p
namespace transport namespace transport
{ {
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ): std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ):
TransportSession (router, SSU_TERMINATION_TIMEOUT), TransportSession (router, SSU_TERMINATION_TIMEOUT),
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_ConnectTimer (GetService ()), m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_ConnectTimer (GetService ()),
m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false), m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false),
m_RelayTag (0), m_SentRelayTag (0), m_Data (*this), m_IsDataReceived (false) m_RelayTag (0), m_SentRelayTag (0), m_Data (*this), m_IsDataReceived (false)
{ {
if (router) if (router)
{ {
// we are client // we are client
@ -36,14 +36,14 @@ namespace transport
} }
SSUSession::~SSUSession () SSUSession::~SSUSession ()
{ {
}
boost::asio::io_service& SSUSession::GetService ()
{
return IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService ();
} }
boost::asio::io_service& SSUSession::GetService ()
{
return IsV6 () ? m_Server.GetServiceV6 () : m_Server.GetService ();
}
void SSUSession::CreateAESandMacKey (const uint8_t * pubKey) void SSUSession::CreateAESandMacKey (const uint8_t * pubKey)
{ {
uint8_t sharedKey[256]; uint8_t sharedKey[256];
@ -55,14 +55,14 @@ namespace transport
sessionKey[0] = 0; sessionKey[0] = 0;
memcpy (sessionKey + 1, sharedKey, 31); memcpy (sessionKey + 1, sharedKey, 31);
memcpy (macKey, sharedKey + 31, 32); memcpy (macKey, sharedKey + 31, 32);
} }
else if (sharedKey[0]) else if (sharedKey[0])
{ {
memcpy (sessionKey, sharedKey, 32); memcpy (sessionKey, sharedKey, 32);
memcpy (macKey, sharedKey + 32, 32); memcpy (macKey, sharedKey + 32, 32);
} }
else else
{ {
// find first non-zero byte // find first non-zero byte
uint8_t * nonZero = sharedKey + 1; uint8_t * nonZero = sharedKey + 1;
while (!*nonZero) while (!*nonZero)
@ -72,16 +72,16 @@ namespace transport
{ {
LogPrint (eLogWarning, "SSU: first 32 bytes of shared key is all zeros. Ignored"); LogPrint (eLogWarning, "SSU: first 32 bytes of shared key is all zeros. Ignored");
return; return;
} }
} }
memcpy (sessionKey, nonZero, 32); memcpy (sessionKey, nonZero, 32);
SHA256(nonZero, 64 - (nonZero - sharedKey), macKey); SHA256(nonZero, 64 - (nonZero - sharedKey), macKey);
} }
m_IsSessionKey = true; m_IsSessionKey = true;
m_SessionKeyEncryption.SetKey (m_SessionKey); m_SessionKeyEncryption.SetKey (m_SessionKey);
m_SessionKeyDecryption.SetKey (m_SessionKey); m_SessionKeyDecryption.SetKey (m_SessionKey);
} }
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{ {
@ -96,40 +96,40 @@ namespace transport
} }
else else
{ {
if (!len) return; // ignore zero-length packets if (!len) return; // ignore zero-length packets
if (m_State == eSessionStateEstablished) if (m_State == eSessionStateEstablished)
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first if (m_IsSessionKey && Validate (buf, len, m_MacKey)) // try session key first
DecryptSessionKey (buf, len); DecryptSessionKey (buf, len);
else else
{ {
if (m_State == eSessionStateEstablished) Reset (); // new session key required if (m_State == eSessionStateEstablished) Reset (); // new session key required
// try intro key depending on side // try intro key depending on side
if (Validate (buf, len, m_IntroKey)) if (Validate (buf, len, m_IntroKey))
Decrypt (buf, len, m_IntroKey); Decrypt (buf, len, m_IntroKey);
else else
{ {
// try own intro key // try own intro key
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
if (!address) if (!address)
{ {
LogPrint (eLogInfo, "SSU is not supported"); LogPrint (eLogInfo, "SSU is not supported");
return; return;
} }
if (Validate (buf, len, address->ssu->key)) if (Validate (buf, len, address->ssu->key))
Decrypt (buf, len, address->ssu->key); Decrypt (buf, len, address->ssu->key);
else else
{ {
LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint); LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
m_Server.DeleteSession (shared_from_this ()); m_Server.DeleteSession (shared_from_this ());
return; return;
} }
} }
} }
// successfully decrypted // successfully decrypted
ProcessMessage (buf, len, senderEndpoint); ProcessMessage (buf, len, senderEndpoint);
} }
} }
size_t SSUSession::GetSSUHeaderSize (const uint8_t * buf) const size_t SSUSession::GetSSUHeaderSize (const uint8_t * buf) const
@ -158,14 +158,14 @@ namespace transport
ProcessData (buf + headerSize, len - headerSize); ProcessData (buf + headerSize, len - headerSize);
break; break;
case PAYLOAD_TYPE_SESSION_REQUEST: case PAYLOAD_TYPE_SESSION_REQUEST:
ProcessSessionRequest (buf, len, senderEndpoint); // buf with header ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
break; break;
case PAYLOAD_TYPE_SESSION_CREATED: case PAYLOAD_TYPE_SESSION_CREATED:
ProcessSessionCreated (buf, len); // buf with header ProcessSessionCreated (buf, len); // buf with header
break; break;
case PAYLOAD_TYPE_SESSION_CONFIRMED: case PAYLOAD_TYPE_SESSION_CONFIRMED:
ProcessSessionConfirmed (buf, len); // buf with header ProcessSessionConfirmed (buf, len); // buf with header
break; break;
case PAYLOAD_TYPE_PEER_TEST: case PAYLOAD_TYPE_PEER_TEST:
LogPrint (eLogDebug, "SSU: peer test received"); LogPrint (eLogDebug, "SSU: peer test received");
ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint); ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint);
@ -173,9 +173,9 @@ namespace transport
case PAYLOAD_TYPE_SESSION_DESTROYED: case PAYLOAD_TYPE_SESSION_DESTROYED:
{ {
LogPrint (eLogDebug, "SSU: session destroy received"); LogPrint (eLogDebug, "SSU: session destroy received");
m_Server.DeleteSession (shared_from_this ()); m_Server.DeleteSession (shared_from_this ());
break; break;
} }
case PAYLOAD_TYPE_RELAY_RESPONSE: case PAYLOAD_TYPE_RELAY_RESPONSE:
ProcessRelayResponse (buf + headerSize, len - headerSize); ProcessRelayResponse (buf + headerSize, len - headerSize);
if (m_State != eSessionStateEstablished) if (m_State != eSessionStateEstablished)
@ -197,7 +197,7 @@ namespace transport
void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) void SSUSession::ProcessSessionRequest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{ {
LogPrint (eLogDebug, "SSU message: session request"); LogPrint (eLogDebug, "SSU message: session request");
bool sendRelayTag = true; bool sendRelayTag = true;
auto headerSize = sizeof (SSUHeader); auto headerSize = sizeof (SSUHeader);
if (((SSUHeader *)buf)->IsExtendedOptions ()) if (((SSUHeader *)buf)->IsExtendedOptions ())
{ {
@ -206,14 +206,14 @@ namespace transport
if (extendedOptionsLen >= 3) // options are presented if (extendedOptionsLen >= 3) // options are presented
{ {
uint16_t flags = bufbe16toh (buf + headerSize); uint16_t flags = bufbe16toh (buf + headerSize);
sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG; sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
} }
headerSize += extendedOptionsLen; headerSize += extendedOptionsLen;
} }
if (headerSize >= len) if (headerSize >= len)
{ {
LogPrint (eLogError, "Session reaquest header size ", headerSize, " exceeds packet length ", len); LogPrint (eLogError, "Session reaquest header size ", headerSize, " exceeds packet length ", len);
return; return;
} }
m_RemoteEndpoint = senderEndpoint; m_RemoteEndpoint = senderEndpoint;
if (!m_DHKeysPair) if (!m_DHKeysPair)
@ -232,14 +232,14 @@ namespace transport
LogPrint (eLogDebug, "SSU message: session created"); LogPrint (eLogDebug, "SSU message: session created");
m_ConnectTimer.cancel (); // connect timer m_ConnectTimer.cancel (); // connect timer
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
auto headerSize = GetSSUHeaderSize (buf); auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len) if (headerSize >= len)
{ {
LogPrint (eLogError, "Session created header size ", headerSize, " exceeds packet length ", len); LogPrint (eLogError, "Session created header size ", headerSize, " exceeds packet length ", len);
return; return;
} }
uint8_t * payload = buf + headerSize; uint8_t * payload = buf + headerSize;
uint8_t * y = payload; uint8_t * y = payload;
CreateAESandMacKey (y); CreateAESandMacKey (y);
s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
@ -250,18 +250,18 @@ namespace transport
uint8_t * ourAddress = payload; uint8_t * ourAddress = payload;
boost::asio::ip::address ourIP; boost::asio::ip::address ourIP;
if (addressSize == 4) // v4 if (addressSize == 4) // v4
{ {
boost::asio::ip::address_v4::bytes_type bytes; boost::asio::ip::address_v4::bytes_type bytes;
memcpy (bytes.data (), ourAddress, 4); memcpy (bytes.data (), ourAddress, 4);
ourIP = boost::asio::ip::address_v4 (bytes); ourIP = boost::asio::ip::address_v4 (bytes);
} }
else // v6 else // v6
{ {
boost::asio::ip::address_v6::bytes_type bytes; boost::asio::ip::address_v6::bytes_type bytes;
memcpy (bytes.data (), ourAddress, 16); memcpy (bytes.data (), ourAddress, 16);
ourIP = boost::asio::ip::address_v6 (bytes); ourIP = boost::asio::ip::address_v6 (bytes);
} }
s.Insert (ourAddress, addressSize); // our IP s.Insert (ourAddress, addressSize); // our IP
payload += addressSize; // address payload += addressSize; // address
uint16_t ourPort = bufbe16toh (payload); uint16_t ourPort = bufbe16toh (payload);
s.Insert (payload, 2); // our port s.Insert (payload, 2); // our port
@ -271,19 +271,19 @@ namespace transport
else else
s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP v6 s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP v6
s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port
s.Insert (payload, 8); // relayTag and signed on time s.Insert (payload, 8); // relayTag and signed on time
m_RelayTag = bufbe32toh (payload); m_RelayTag = bufbe32toh (payload);
payload += 4; // relayTag payload += 4; // relayTag
if (i2p::context.GetStatus () == eRouterStatusTesting) if (i2p::context.GetStatus () == eRouterStatusTesting)
{ {
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
uint32_t signedOnTime = bufbe32toh(payload); uint32_t signedOnTime = bufbe32toh(payload);
if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW) if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW)
{ {
LogPrint (eLogError, "SSU: clock skew detected ", (int)ts - signedOnTime, ". Check your clock"); LogPrint (eLogError, "SSU: clock skew detected ", (int)ts - signedOnTime, ". Check your clock");
i2p::context.SetError (eRouterErrorClockSkew); i2p::context.SetError (eRouterErrorClockSkew);
} }
} }
payload += 4; // signed on time payload += 4; // signed on time
// decrypt signature // decrypt signature
size_t signatureLen = m_RemoteIdentity->GetSignatureLen (); size_t signatureLen = m_RemoteIdentity->GetSignatureLen ();
@ -304,34 +304,34 @@ namespace transport
LogPrint (eLogError, "SSU: message 'created' signature verification failed"); LogPrint (eLogError, "SSU: message 'created' signature verification failed");
Failed (); Failed ();
} }
} }
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len) void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
{ {
LogPrint (eLogDebug, "SSU: Session confirmed received"); LogPrint (eLogDebug, "SSU: Session confirmed received");
auto headerSize = GetSSUHeaderSize (buf); auto headerSize = GetSSUHeaderSize (buf);
if (headerSize >= len) if (headerSize >= len)
{ {
LogPrint (eLogError, "SSU: Session confirmed header size ", len, " exceeds packet length ", len); LogPrint (eLogError, "SSU: Session confirmed header size ", len, " exceeds packet length ", len);
return; return;
} }
const uint8_t * payload = buf + headerSize; const uint8_t * payload = buf + headerSize;
payload++; // identity fragment info payload++; // identity fragment info
uint16_t identitySize = bufbe16toh (payload); uint16_t identitySize = bufbe16toh (payload);
payload += 2; // size of identity fragment payload += 2; // size of identity fragment
auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize); auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize);
auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : identity); SetRemoteIdentity (existing ? existing->GetRouterIdentity () : identity);
m_Data.UpdatePacketSize (m_RemoteIdentity->GetIdentHash ()); m_Data.UpdatePacketSize (m_RemoteIdentity->GetIdentHash ());
payload += identitySize; // identity payload += identitySize; // identity
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
uint32_t signedOnTime = bufbe32toh(payload); uint32_t signedOnTime = bufbe32toh(payload);
if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW) if (signedOnTime < ts - SSU_CLOCK_SKEW || signedOnTime > ts + SSU_CLOCK_SKEW)
{ {
LogPrint (eLogError, "SSU message 'confirmed' time difference ", (int)ts - signedOnTime, " exceeds clock skew"); LogPrint (eLogError, "SSU message 'confirmed' time difference ", (int)ts - signedOnTime, " exceeds clock skew");
Failed (); Failed ();
return; return;
} }
if (m_SignedData) if (m_SignedData)
m_SignedData->Insert (payload, 4); // insert Alice's signed on time m_SignedData->Insert (payload, 4); // insert Alice's signed on time
payload += 4; // signed-on time payload += 4; // signed-on time
@ -345,7 +345,7 @@ namespace transport
m_Data.Send (CreateDeliveryStatusMsg (0)); m_Data.Send (CreateDeliveryStatusMsg (0));
Established (); Established ();
} }
else else
{ {
LogPrint (eLogError, "SSU message 'confirmed' signature verification failed"); LogPrint (eLogError, "SSU message 'confirmed' signature verification failed");
Failed (); Failed ();
@ -353,33 +353,33 @@ namespace transport
} }
void SSUSession::SendSessionRequest () void SSUSession::SendSessionRequest ()
{ {
uint8_t buf[320 + 18] = {0}; // 304 bytes for ipv4, 320 for ipv6 uint8_t buf[320 + 18] = {0}; // 304 bytes for ipv4, 320 for ipv6
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
uint8_t flag = 0; uint8_t flag = 0;
// fill extended options, 3 bytes extended options don't change message size // fill extended options, 3 bytes extended options don't change message size
if (i2p::context.GetStatus () == eRouterStatusOK) // we don't need relays if (i2p::context.GetStatus () == eRouterStatusOK) // we don't need relays
{ {
// tell out peer to now assign relay tag // tell out peer to now assign relay tag
flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED;
*payload = 2; payload++; // 1 byte length *payload = 2; payload++; // 1 byte length
uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG
htobe16buf (payload, flags); htobe16buf (payload, flags);
payload += 2; payload += 2;
} }
// fill payload // fill payload
memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x
bool isV4 = m_RemoteEndpoint.address ().is_v4 (); bool isV4 = m_RemoteEndpoint.address ().is_v4 ();
if (isV4) if (isV4)
{ {
payload[256] = 4; payload[256] = 4;
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4); memcpy (payload + 257, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
} }
else else
{ {
payload[256] = 16; payload[256] = 16;
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16); memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
} }
// encrypt and send // encrypt and send
uint8_t iv[16]; uint8_t iv[16];
RAND_bytes (iv, 16); // random iv RAND_bytes (iv, 16); // random iv
@ -395,7 +395,7 @@ namespace transport
LogPrint (eLogInfo, "SSU is not supported"); LogPrint (eLogInfo, "SSU is not supported");
return; return;
} }
uint8_t buf[96 + 18] = {0}; uint8_t buf[96 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
htobe32buf (payload, introducer.iTag); htobe32buf (payload, introducer.iTag);
@ -405,17 +405,17 @@ namespace transport
htobuf16(payload, 0); // port = 0 htobuf16(payload, 0); // port = 0
payload += 2; payload += 2;
*payload = 0; // challenge *payload = 0; // challenge
payload++; payload++;
memcpy (payload, (const uint8_t *)address->ssu->key, 32); memcpy (payload, (const uint8_t *)address->ssu->key, 32);
payload += 32; payload += 32;
htobe32buf (payload, nonce); // nonce htobe32buf (payload, nonce); // nonce
uint8_t iv[16]; uint8_t iv[16];
RAND_bytes (iv, 16); // random iv RAND_bytes (iv, 16); // random iv
if (m_State == eSessionStateEstablished) if (m_State == eSessionStateEstablished)
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, m_SessionKey, iv, m_MacKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, m_SessionKey, iv, m_MacKey);
else else
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey);
m_Server.Send (buf, 96, m_RemoteEndpoint); m_Server.Send (buf, 96, m_RemoteEndpoint);
} }
@ -428,7 +428,7 @@ namespace transport
LogPrint (eLogInfo, "SSU is not supported"); LogPrint (eLogInfo, "SSU is not supported");
return; return;
} }
SignedData s; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time SignedData s; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time
s.Insert (x, 256); // x s.Insert (x, 256); // x
uint8_t buf[384 + 18] = {0}; uint8_t buf[384 + 18] = {0};
@ -441,7 +441,7 @@ namespace transport
// ipv4 // ipv4
*payload = 4; *payload = 4;
payload++; payload++;
memcpy (payload, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4); memcpy (payload, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
s.Insert (payload, 4); // remote endpoint IP V4 s.Insert (payload, 4); // remote endpoint IP V4
payload += 4; payload += 4;
} }
@ -450,7 +450,7 @@ namespace transport
// ipv6 // ipv6
*payload = 16; *payload = 16;
payload++; payload++;
memcpy (payload, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16); memcpy (payload, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
s.Insert (payload, 16); // remote endpoint IP V6 s.Insert (payload, 16); // remote endpoint IP V6
payload += 16; payload += 16;
} }
@ -467,20 +467,20 @@ namespace transport
RAND_bytes((uint8_t *)&m_SentRelayTag, 4); RAND_bytes((uint8_t *)&m_SentRelayTag, 4);
if (!m_SentRelayTag) m_SentRelayTag = 1; if (!m_SentRelayTag) m_SentRelayTag = 1;
} }
htobe32buf (payload, m_SentRelayTag); htobe32buf (payload, m_SentRelayTag);
payload += 4; // relay tag payload += 4; // relay tag
htobe32buf (payload, i2p::util::GetSecondsSinceEpoch ()); // signed on time htobe32buf (payload, i2p::util::GetSecondsSinceEpoch ()); // signed on time
payload += 4; payload += 4;
s.Insert (payload - 8, 4); // relayTag s.Insert (payload - 8, 4); // relayTag
// we have to store this signed data for session confirmed // we have to store this signed data for session confirmed
// same data but signed on time, it will Alice's there // same data but signed on time, it will Alice's there
m_SignedData = std::unique_ptr<SignedData>(new SignedData (s)); m_SignedData = std::unique_ptr<SignedData>(new SignedData (s));
s.Insert (payload - 4, 4); // BOB's signed on time s.Insert (payload - 4, 4); // BOB's signed on time
s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
uint8_t iv[16]; uint8_t iv[16];
RAND_bytes (iv, 16); // random iv RAND_bytes (iv, 16); // random iv
// encrypt signature and padding with newly created session key // encrypt signature and padding with newly created session key
size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen (); size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen ();
size_t paddingSize = signatureLen & 0x0F; // %16 size_t paddingSize = signatureLen & 0x0F; // %16
if (paddingSize > 0) if (paddingSize > 0)
@ -493,9 +493,9 @@ namespace transport
m_SessionKeyEncryption.Encrypt (payload, signatureLen, payload); m_SessionKeyEncryption.Encrypt (payload, signatureLen, payload);
payload += signatureLen; payload += signatureLen;
size_t msgLen = payload - buf; size_t msgLen = payload - buf;
// encrypt message with intro key // encrypt message with intro key
FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, m_IntroKey, iv, m_IntroKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, msgLen, m_IntroKey, iv, m_IntroKey);
Send (buf, msgLen); Send (buf, msgLen);
} }
@ -518,21 +518,21 @@ namespace transport
if (paddingSize > 0) paddingSize = 16 - paddingSize; if (paddingSize > 0) paddingSize = 16 - paddingSize;
RAND_bytes(payload, paddingSize); // fill padding with random RAND_bytes(payload, paddingSize); // fill padding with random
payload += paddingSize; // padding size payload += paddingSize; // padding size
// signature // signature
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time
s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
s.Insert (y, 256); // y s.Insert (y, 256); // y
s.Insert (ourAddress, ourAddressLen); // our address/port as seem by party s.Insert (ourAddress, ourAddressLen); // our address/port as seem by party
if (m_RemoteEndpoint.address ().is_v4 ()) if (m_RemoteEndpoint.address ().is_v4 ())
s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP V4 s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP V4
else else
s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP V6 s.Insert (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), 16); // remote IP V6
s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port s.Insert<uint16_t> (htobe16 (m_RemoteEndpoint.port ())); // remote port
s.Insert (htobe32 (m_RelayTag)); // relay tag s.Insert (htobe32 (m_RelayTag)); // relay tag
s.Insert (htobe32 (signedOnTime)); // signed on time s.Insert (htobe32 (signedOnTime)); // signed on time
s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
payload += signatureLen; payload += signatureLen;
size_t msgLen = payload - buf; size_t msgLen = payload - buf;
uint8_t iv[16]; uint8_t iv[16];
RAND_bytes (iv, 16); // random iv RAND_bytes (iv, 16); // random iv
@ -547,7 +547,7 @@ namespace transport
auto session = m_Server.FindRelaySession (relayTag); auto session = m_Server.FindRelaySession (relayTag);
if (session) if (session)
{ {
buf += 4; // relay tag buf += 4; // relay tag
uint8_t size = *buf; uint8_t size = *buf;
buf++; // size buf++; // size
buf += size; // address buf += size; // address
@ -560,7 +560,7 @@ namespace transport
uint32_t nonce = bufbe32toh (buf); uint32_t nonce = bufbe32toh (buf);
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint); SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
SendRelayIntro (session, from); SendRelayIntro (session, from);
} }
} }
void SSUSession::SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from, void SSUSession::SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
@ -577,7 +577,7 @@ namespace transport
*payload = 4; *payload = 4;
payload++; // size payload++; // size
htobe32buf (payload, to.address ().to_v4 ().to_ulong ()); // Charlie's IP htobe32buf (payload, to.address ().to_v4 ().to_ulong ()); // Charlie's IP
payload += 4; // address payload += 4; // address
htobe16buf (payload, to.port ()); // Charlie's port htobe16buf (payload, to.port ()); // Charlie's port
payload += 2; // port payload += 2; // port
// Alice // Alice
@ -587,25 +587,25 @@ namespace transport
*payload = 4; *payload = 4;
payload++; // size payload++; // size
memcpy (payload, from.address ().to_v4 ().to_bytes ().data (), 4); // Alice's IP V4 memcpy (payload, from.address ().to_v4 ().to_bytes ().data (), 4); // Alice's IP V4
payload += 4; // address payload += 4; // address
} }
else else
{ {
*payload = 16; *payload = 16;
payload++; // size payload++; // size
memcpy (payload, from.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6 memcpy (payload, from.address ().to_v6 ().to_bytes ().data (), 16); // Alice's IP V6
payload += 16; // address payload += 16; // address
} }
htobe16buf (payload, from.port ()); // Alice's port htobe16buf (payload, from.port ()); // Alice's port
payload += 2; // port payload += 2; // port
htobe32buf (payload, nonce); htobe32buf (payload, nonce);
if (m_State == eSessionStateEstablished) if (m_State == eSessionStateEstablished)
{ {
// encrypt with session key // encrypt with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80); FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80);
Send (buf, isV4 ? 64 : 80); Send (buf, isV4 ? 64 : 80);
} }
else else
{ {
// ecrypt with Alice's intro key // ecrypt with Alice's intro key
@ -613,45 +613,45 @@ namespace transport
RAND_bytes (iv, 16); // random iv RAND_bytes (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey);
m_Server.Send (buf, isV4 ? 64 : 80, from); m_Server.Send (buf, isV4 ? 64 : 80, from);
} }
LogPrint (eLogDebug, "SSU: relay response sent"); LogPrint (eLogDebug, "SSU: relay response sent");
} }
void SSUSession::SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from) void SSUSession::SendRelayIntro (std::shared_ptr<SSUSession> session, const boost::asio::ip::udp::endpoint& from)
{ {
if (!session) return; if (!session) return;
// Alice's address always v4 // Alice's address always v4
if (!from.address ().is_v4 ()) if (!from.address ().is_v4 ())
{ {
LogPrint (eLogWarning, "SSU: Alice's IP must be v4"); LogPrint (eLogWarning, "SSU: Alice's IP must be v4");
return; return;
} }
uint8_t buf[48 + 18] = {0}; uint8_t buf[48 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
*payload = 4; *payload = 4;
payload++; // size payload++; // size
htobe32buf (payload, from.address ().to_v4 ().to_ulong ()); // Alice's IP htobe32buf (payload, from.address ().to_v4 ().to_ulong ()); // Alice's IP
payload += 4; // address payload += 4; // address
htobe16buf (payload, from.port ()); // Alice's port htobe16buf (payload, from.port ()); // Alice's port
payload += 2; // port payload += 2; // port
*payload = 0; // challenge size *payload = 0; // challenge size
uint8_t iv[16]; uint8_t iv[16];
RAND_bytes (iv, 16); // random iv RAND_bytes (iv, 16); // random iv
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey);
m_Server.Send (buf, 48, session->m_RemoteEndpoint); m_Server.Send (buf, 48, session->m_RemoteEndpoint);
LogPrint (eLogDebug, "SSU: relay intro sent"); LogPrint (eLogDebug, "SSU: relay intro sent");
} }
void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len) void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len)
{ {
LogPrint (eLogDebug, "SSU message: Relay response received"); LogPrint (eLogDebug, "SSU message: Relay response received");
uint8_t remoteSize = *buf; uint8_t remoteSize = *buf;
buf++; // remote size buf++; // remote size
boost::asio::ip::address_v4 remoteIP (bufbe32toh (buf)); boost::asio::ip::address_v4 remoteIP (bufbe32toh (buf));
buf += remoteSize; // remote address buf += remoteSize; // remote address
uint16_t remotePort = bufbe16toh (buf); uint16_t remotePort = bufbe16toh (buf);
buf += 2; // remote port buf += 2; // remote port
uint8_t ourSize = *buf; uint8_t ourSize = *buf;
buf++; // our size buf++; // our size
boost::asio::ip::address ourIP; boost::asio::ip::address ourIP;
if (ourSize == 4) if (ourSize == 4)
@ -675,7 +675,7 @@ namespace transport
buf += 4; // nonce buf += 4; // nonce
auto it = m_RelayRequests.find (nonce); auto it = m_RelayRequests.find (nonce);
if (it != m_RelayRequests.end ()) if (it != m_RelayRequests.end ())
{ {
// check if we are waiting for introduction // check if we are waiting for introduction
boost::asio::ip::udp::endpoint remoteEndpoint (remoteIP, remotePort); boost::asio::ip::udp::endpoint remoteEndpoint (remoteIP, remotePort);
if (!m_Server.FindSession (remoteEndpoint)) if (!m_Server.FindSession (remoteEndpoint))
@ -686,10 +686,10 @@ namespace transport
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
m_Server.CreateDirectSession (it->second, remoteEndpoint, false); m_Server.CreateDirectSession (it->second, remoteEndpoint, false);
} }
// delete request // delete request
m_RelayRequests.erase (it); m_RelayRequests.erase (it);
} }
else else
LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce); LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce);
} }
@ -708,11 +708,11 @@ namespace transport
} }
else else
LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported"); LogPrint (eLogWarning, "SSU: Address size ", size, " is not supported");
} }
void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len,
const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag) const i2p::crypto::AESKey& aesKey, const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag)
{ {
if (len < sizeof (SSUHeader)) if (len < sizeof (SSUHeader))
{ {
LogPrint (eLogError, "SSU: Unexpected packet length ", len); LogPrint (eLogError, "SSU: Unexpected packet length ", len);
@ -753,18 +753,18 @@ namespace transport
memcpy (buf + len, header->iv, 16); memcpy (buf + len, header->iv, 16);
htobe16buf (buf + len + 16, encryptedLen); htobe16buf (buf + len + 16, encryptedLen);
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac); i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
} }
void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey) void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey)
{ {
if (len < sizeof (SSUHeader)) if (len < sizeof (SSUHeader))
{ {
LogPrint (eLogError, "SSU: Unexpected packet length ", len); LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return; return;
} }
SSUHeader * header = (SSUHeader *)buf; SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag; uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf); uint16_t encryptedLen = len - (encrypted - buf);
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
decryption.SetKey (aesKey); decryption.SetKey (aesKey);
decryption.SetIV (header->iv); decryption.SetIV (header->iv);
@ -777,24 +777,24 @@ namespace transport
{ {
LogPrint (eLogError, "SSU: Unexpected packet length ", len); LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return; return;
} }
SSUHeader * header = (SSUHeader *)buf; SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag; uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf); uint16_t encryptedLen = len - (encrypted - buf);
if (encryptedLen > 0) if (encryptedLen > 0)
{ {
m_SessionKeyDecryption.SetIV (header->iv); m_SessionKeyDecryption.SetIV (header->iv);
m_SessionKeyDecryption.Decrypt (encrypted, encryptedLen, encrypted); m_SessionKeyDecryption.Decrypt (encrypted, encryptedLen, encrypted);
} }
} }
bool SSUSession::Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey) bool SSUSession::Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey)
{ {
if (len < sizeof (SSUHeader)) if (len < sizeof (SSUHeader))
{ {
LogPrint (eLogError, "SSU: Unexpected packet length ", len); LogPrint (eLogError, "SSU: Unexpected packet length ", len);
return false; return false;
} }
SSUHeader * header = (SSUHeader *)buf; SSUHeader * header = (SSUHeader *)buf;
uint8_t * encrypted = &header->flag; uint8_t * encrypted = &header->flag;
uint16_t encryptedLen = len - (encrypted - buf); uint16_t encryptedLen = len - (encrypted - buf);
@ -809,12 +809,12 @@ namespace transport
void SSUSession::Connect () void SSUSession::Connect ()
{ {
if (m_State == eSessionStateUnknown) if (m_State == eSessionStateUnknown)
{ {
// set connect timer // set connect timer
ScheduleConnectTimer (); ScheduleConnectTimer ();
m_DHKeysPair = transports.GetNextDHKeysPair (); m_DHKeysPair = transports.GetNextDHKeysPair ();
SendSessionRequest (); SendSessionRequest ();
} }
} }
void SSUSession::WaitForConnect () void SSUSession::WaitForConnect ()
@ -830,7 +830,7 @@ namespace transport
m_ConnectTimer.cancel (); m_ConnectTimer.cancel ();
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer, m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode) void SSUSession::HandleConnectTimer (const boost::system::error_code& ecode)
@ -840,14 +840,14 @@ namespace transport
// timeout expired // timeout expired
LogPrint (eLogWarning, "SSU: session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds"); LogPrint (eLogWarning, "SSU: session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
Failed (); Failed ();
} }
} }
void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer, void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer,
std::shared_ptr<const i2p::data::RouterInfo> to) std::shared_ptr<const i2p::data::RouterInfo> to)
{ {
if (m_State == eSessionStateUnknown) if (m_State == eSessionStateUnknown)
{ {
// set connect timer // set connect timer
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer, m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
@ -865,7 +865,7 @@ namespace transport
// set connect timer // set connect timer
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT)); m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer, m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
shared_from_this (), std::placeholders::_1)); shared_from_this (), std::placeholders::_1));
} }
void SSUSession::Close () void SSUSession::Close ()
@ -873,7 +873,7 @@ namespace transport
SendSessionDestroyed (); SendSessionDestroyed ();
Reset (); Reset ();
m_State = eSessionStateClosed; m_State = eSessionStateClosed;
} }
void SSUSession::Reset () void SSUSession::Reset ()
{ {
@ -882,10 +882,10 @@ namespace transport
m_Data.Stop (); m_Data.Stop ();
m_ConnectTimer.cancel (); m_ConnectTimer.cancel ();
if (m_SentRelayTag) if (m_SentRelayTag)
{ {
m_Server.RemoveRelay (m_SentRelayTag); // relay tag is not valid anymore m_Server.RemoveRelay (m_SentRelayTag); // relay tag is not valid anymore
m_SentRelayTag = 0; m_SentRelayTag = 0;
} }
m_DHKeysPair = nullptr; m_DHKeysPair = nullptr;
m_SignedData = nullptr; m_SignedData = nullptr;
m_IsSessionKey = false; m_IsSessionKey = false;
@ -908,20 +908,20 @@ namespace transport
if (m_SentRelayTag) if (m_SentRelayTag)
m_Server.AddRelay (m_SentRelayTag, shared_from_this ()); m_Server.AddRelay (m_SentRelayTag, shared_from_this ());
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
} }
void SSUSession::Failed () void SSUSession::Failed ()
{ {
if (m_State != eSessionStateFailed) if (m_State != eSessionStateFailed)
{ {
m_State = eSessionStateFailed; m_State = eSessionStateFailed;
m_Server.DeleteSession (shared_from_this ()); m_Server.DeleteSession (shared_from_this ());
} }
} }
void SSUSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) void SSUSession::SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs)
{ {
GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs)); GetService ().post (std::bind (&SSUSession::PostI2NPMessages, shared_from_this (), msgs));
} }
void SSUSession::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs) void SSUSession::PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs)
@ -931,7 +931,7 @@ namespace transport
for (const auto& it: msgs) for (const auto& it: msgs)
if (it) m_Data.Send (it); if (it) m_Data.Send (it);
} }
} }
void SSUSession::ProcessData (uint8_t * buf, size_t len) void SSUSession::ProcessData (uint8_t * buf, size_t len)
{ {
@ -942,29 +942,29 @@ namespace transport
void SSUSession::FlushData () void SSUSession::FlushData ()
{ {
if (m_IsDataReceived) if (m_IsDataReceived)
{ {
m_Data.FlushReceivedMessage (); m_Data.FlushReceivedMessage ();
m_IsDataReceived = false; m_IsDataReceived = false;
} }
} }
void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
{ {
uint32_t nonce = bufbe32toh (buf); // 4 bytes uint32_t nonce = bufbe32toh (buf); // 4 bytes
uint8_t size = buf[4]; // 1 byte uint8_t size = buf[4]; // 1 byte
const uint8_t * address = buf + 5; // big endian, size bytes const uint8_t * address = buf + 5; // big endian, size bytes
uint16_t port = buf16toh(buf + size + 5); // big endian, 2 bytes uint16_t port = buf16toh(buf + size + 5); // big endian, 2 bytes
const uint8_t * introKey = buf + size + 7; const uint8_t * introKey = buf + size + 7;
if (port && (size != 4) && (size != 16)) if (port && (size != 4) && (size != 16))
{ {
LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported"); LogPrint (eLogWarning, "SSU: Address of ", size, " bytes not supported");
return; return;
} }
switch (m_Server.GetPeerTestParticipant (nonce)) switch (m_Server.GetPeerTestParticipant (nonce))
{ {
// existing test // existing test
case ePeerTestParticipantAlice1: case ePeerTestParticipantAlice1:
{ {
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
{ {
LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice"); LogPrint (eLogDebug, "SSU: peer test from Bob. We are Alice");
@ -981,7 +981,7 @@ namespace transport
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, true, false); // to Charlie
} }
break; break;
} }
case ePeerTestParticipantAlice2: case ePeerTestParticipantAlice2:
{ {
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
@ -994,8 +994,8 @@ namespace transport
m_Server.RemovePeerTest (nonce); m_Server.RemovePeerTest (nonce);
} }
break; break;
} }
case ePeerTestParticipantBob: case ePeerTestParticipantBob:
{ {
LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob"); LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob");
auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest
@ -1005,13 +1005,13 @@ namespace transport
break; break;
} }
case ePeerTestParticipantCharlie: case ePeerTestParticipantCharlie:
{ {
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie"); LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie");
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey); // to Alice with her actual address SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey); // to Alice with her actual address
m_Server.RemovePeerTest (nonce); // nonce has been used m_Server.RemovePeerTest (nonce); // nonce has been used
break; break;
} }
// test not found // test not found
case ePeerTestParticipantUnknown: case ePeerTestParticipantUnknown:
{ {
if (m_State == eSessionStateEstablished) if (m_State == eSessionStateEstablished)
@ -1034,7 +1034,7 @@ namespace transport
boost::asio::ip::address_v6::bytes_type bytes; boost::asio::ip::address_v6::bytes_type bytes;
memcpy (bytes.data (), address, 16); memcpy (bytes.data (), address, 16);
addr = boost::asio::ip::address_v6 (bytes); addr = boost::asio::ip::address_v6 (bytes);
} }
SendPeerTest (nonce, addr, be16toh (port), introKey); // to Alice with her address received from Bob SendPeerTest (nonce, addr, be16toh (port), introKey); // to Alice with her address received from Bob
} }
else else
@ -1044,26 +1044,26 @@ namespace transport
if (session) if (session)
{ {
m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ()); m_Server.NewPeerTest (nonce, ePeerTestParticipantBob, shared_from_this ());
session->SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address session->SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address
} }
} }
} }
else else
LogPrint (eLogError, "SSU: unexpected peer test"); LogPrint (eLogError, "SSU: unexpected peer test");
} }
} }
} }
void SSUSession::SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, void SSUSession::SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port,
const uint8_t * introKey, bool toAddress, bool sendAddress) const uint8_t * introKey, bool toAddress, bool sendAddress)
// toAddress is true for Alice<->Chalie communications only // toAddress is true for Alice<->Chalie communications only
// sendAddress is false if message comes from Alice // sendAddress is false if message comes from Alice
{ {
uint8_t buf[80 + 18] = {0}; uint8_t buf[80 + 18] = {0};
uint8_t iv[16]; uint8_t iv[16];
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
htobe32buf (payload, nonce); htobe32buf (payload, nonce);
payload += 4; // nonce payload += 4; // nonce
// address and port // address and port
if (sendAddress) if (sendAddress)
{ {
@ -1075,11 +1075,11 @@ namespace transport
else if (address.is_v6 ()) else if (address.is_v6 ())
{ {
*payload = 16; *payload = 16;
memcpy (payload + 1, address.to_v6 ().to_bytes ().data (), 16); // our IP V6 memcpy (payload + 1, address.to_v6 ().to_bytes ().data (), 16); // our IP V6
} }
else else
*payload = 0; *payload = 0;
payload += (payload[0] + 1); payload += (payload[0] + 1);
} }
else else
{ {
@ -1096,27 +1096,27 @@ namespace transport
if (addr) if (addr)
memcpy (payload, addr->ssu->key, 32); // intro key memcpy (payload, addr->ssu->key, 32); // intro key
else else
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test"); LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
} }
else else
memcpy (payload, introKey, 32); // intro key memcpy (payload, introKey, 32); // intro key
// send // send
RAND_bytes (iv, 16); // random iv RAND_bytes (iv, 16); // random iv
if (toAddress) if (toAddress)
{ {
// encrypt message with specified intro key // encrypt message with specified intro key
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey); FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey);
boost::asio::ip::udp::endpoint e (address, port); boost::asio::ip::udp::endpoint e (address, port);
m_Server.Send (buf, 80, e); m_Server.Send (buf, 80, e);
} }
else else
{ {
// encrypt message with session key // encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80); FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80);
Send (buf, 80); Send (buf, 80);
} }
} }
void SSUSession::SendPeerTest () void SSUSession::SendPeerTest ()
{ {
@ -1134,23 +1134,23 @@ namespace transport
m_IsPeerTest = false; m_IsPeerTest = false;
m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ()); m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1, shared_from_this ());
SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice SendPeerTest (nonce, boost::asio::ip::address(), 0, address->ssu->key, false, false); // address and port always zero for Alice
} }
void SSUSession::SendKeepAlive () void SSUSession::SendKeepAlive ()
{ {
if (m_State == eSessionStateEstablished) if (m_State == eSessionStateEstablished)
{ {
uint8_t buf[48 + 18] = {0}; uint8_t buf[48 + 18] = {0};
uint8_t * payload = buf + sizeof (SSUHeader); uint8_t * payload = buf + sizeof (SSUHeader);
*payload = 0; // flags *payload = 0; // flags
payload++; payload++;
*payload = 0; // num fragments *payload = 0; // num fragments
// encrypt message with session key // encrypt message with session key
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48); FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
Send (buf, 48); Send (buf, 48);
LogPrint (eLogDebug, "SSU: keep-alive sent"); LogPrint (eLogDebug, "SSU: keep-alive sent");
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
} }
} }
void SSUSession::SendSessionDestroyed () void SSUSession::SendSessionDestroyed ()
@ -1170,31 +1170,31 @@ namespace transport
} }
LogPrint (eLogDebug, "SSU: session destroyed sent"); LogPrint (eLogDebug, "SSU: session destroyed sent");
} }
} }
void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len) void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len)
{ {
uint8_t buf[SSU_MTU_V4 + 18] = {0}; uint8_t buf[SSU_MTU_V4 + 18] = {0};
size_t msgSize = len + sizeof (SSUHeader); size_t msgSize = len + sizeof (SSUHeader);
size_t paddingSize = msgSize & 0x0F; // %16 size_t paddingSize = msgSize & 0x0F; // %16
if (paddingSize > 0) msgSize += (16 - paddingSize); if (paddingSize > 0) msgSize += (16 - paddingSize);
if (msgSize > SSU_MTU_V4) if (msgSize > SSU_MTU_V4)
{ {
LogPrint (eLogWarning, "SSU: payload size ", msgSize, " exceeds MTU"); LogPrint (eLogWarning, "SSU: payload size ", msgSize, " exceeds MTU");
return; return;
} }
memcpy (buf + sizeof (SSUHeader), payload, len); memcpy (buf + sizeof (SSUHeader), payload, len);
// encrypt message with session key // encrypt message with session key
FillHeaderAndEncrypt (type, buf, msgSize); FillHeaderAndEncrypt (type, buf, msgSize);
Send (buf, msgSize); Send (buf, msgSize);
} }
void SSUSession::Send (const uint8_t * buf, size_t size) void SSUSession::Send (const uint8_t * buf, size_t size)
{ {
m_NumSentBytes += size; m_NumSentBytes += size;
i2p::transport::transports.UpdateSentBytes (size); i2p::transport::transports.UpdateSentBytes (size);
m_Server.Send (buf, size, m_RemoteEndpoint); m_Server.Send (buf, size, m_RemoteEndpoint);
} }
} }
} }

View file

@ -19,15 +19,15 @@ namespace transport
uint8_t mac[16]; uint8_t mac[16];
uint8_t iv[16]; uint8_t iv[16];
uint8_t flag; uint8_t flag;
uint8_t time[4]; uint8_t time[4];
uint8_t GetPayloadType () const { return flag >> 4; }; uint8_t GetPayloadType () const { return flag >> 4; };
bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; }; bool IsExtendedOptions () const { return flag & SSU_HEADER_EXTENDED_OPTIONS_INCLUDED; };
}; };
const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds const int SSU_CONNECT_TIMEOUT = 5; // 5 seconds
const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes const int SSU_TERMINATION_TIMEOUT = 330; // 5.5 minutes
const int SSU_CLOCK_SKEW = 60; // in seconds const int SSU_CLOCK_SKEW = 60; // in seconds
// payload types (4 bits) // payload types (4 bits)
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0; const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
@ -45,12 +45,12 @@ namespace transport
enum SessionState enum SessionState
{ {
eSessionStateUnknown, eSessionStateUnknown,
eSessionStateIntroduced, eSessionStateIntroduced,
eSessionStateEstablished, eSessionStateEstablished,
eSessionStateClosed, eSessionStateClosed,
eSessionStateFailed eSessionStateFailed
}; };
enum PeerTestParticipant enum PeerTestParticipant
{ {
@ -60,7 +60,7 @@ namespace transport
ePeerTestParticipantBob, ePeerTestParticipantBob,
ePeerTestParticipantCharlie ePeerTestParticipantCharlie
}; };
class SSUServer; class SSUServer;
class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession> class SSUSession: public TransportSession, public std::enable_shared_from_this<SSUSession>
{ {
@ -68,12 +68,12 @@ namespace transport
SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint, SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false); std::shared_ptr<const i2p::data::RouterInfo> router = nullptr, bool peerTest = false);
void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
~SSUSession (); ~SSUSession ();
void Connect (); void Connect ();
void WaitForConnect (); void WaitForConnect ();
void Introduce (const i2p::data::RouterInfo::Introducer& introducer, void Introduce (const i2p::data::RouterInfo::Introducer& introducer,
std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie std::shared_ptr<const i2p::data::RouterInfo> to); // Alice to Charlie
void WaitForIntroduction (); void WaitForIntroduction ();
void Close (); void Close ();
@ -82,23 +82,23 @@ namespace transport
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); }; bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void SendPeerTest (); // Alice void SendPeerTest (); // Alice
SessionState GetState () const { return m_State; }; SessionState GetState () const { return m_State; };
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void SendKeepAlive (); void SendKeepAlive ();
uint32_t GetRelayTag () const { return m_RelayTag; }; uint32_t GetRelayTag () const { return m_RelayTag; };
const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; }; const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; };
uint32_t GetCreationTime () const { return m_CreationTime; }; uint32_t GetCreationTime () const { return m_CreationTime; };
void FlushData (); void FlushData ();
private: private:
boost::asio::io_service& GetService (); boost::asio::io_service& GetService ();
void CreateAESandMacKey (const uint8_t * pubKey); void CreateAESandMacKey (const uint8_t * pubKey);
size_t GetSSUHeaderSize (const uint8_t * buf) const; size_t GetSSUHeaderSize (const uint8_t * buf) const;
void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs); void PostI2NPMessages (std::vector<std::shared_ptr<I2NPMessage> > msgs);
void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session void ProcessMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); // call for established session
@ -119,23 +119,23 @@ namespace transport
void ScheduleConnectTimer (); void ScheduleConnectTimer ();
void HandleConnectTimer (const boost::system::error_code& ecode); void HandleConnectTimer (const boost::system::error_code& ecode);
void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint);
void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true); void SendPeerTest (uint32_t nonce, const boost::asio::ip::address& address, uint16_t port, const uint8_t * introKey, bool toAddress = true, bool sendAddress = true);
void ProcessData (uint8_t * buf, size_t len); void ProcessData (uint8_t * buf, size_t len);
void SendSessionDestroyed (); void SendSessionDestroyed ();
void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key void Send (uint8_t type, const uint8_t * payload, size_t len); // with session key
void Send (const uint8_t * buf, size_t size); void Send (const uint8_t * buf, size_t size);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey, void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0); const uint8_t * iv, const i2p::crypto::MACKey& macKey, uint8_t flag = 0);
void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len); // with session key
void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey); void Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey);
void DecryptSessionKey (uint8_t * buf, size_t len); void DecryptSessionKey (uint8_t * buf, size_t len);
bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey); bool Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey);
void Reset (); void Reset ();
private: private:
friend class SSUData; // TODO: change in later friend class SSUData; // TODO: change in later
SSUServer& m_Server; SSUServer& m_Server;
boost::asio::ip::udp::endpoint m_RemoteEndpoint; boost::asio::ip::udp::endpoint m_RemoteEndpoint;

View file

@ -16,24 +16,24 @@ namespace crypto
BIGNUM * tmp = BN_new (); BIGNUM * tmp = BN_new ();
q = BN_new (); q = BN_new ();
// 2^255-19 // 2^255-19
BN_set_bit (q, 255); // 2^255 BN_set_bit (q, 255); // 2^255
BN_sub_word (q, 19); BN_sub_word (q, 19);
l = BN_new (); l = BN_new ();
// 2^252 + 27742317777372353535851937790883648493 // 2^252 + 27742317777372353535851937790883648493
BN_set_bit (l, 252); BN_set_bit (l, 252);
two_252_2 = BN_dup (l); two_252_2 = BN_dup (l);
BN_dec2bn (&tmp, "27742317777372353535851937790883648493"); BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
BN_add (l, l, tmp); BN_add (l, l, tmp);
BN_sub_word (two_252_2, 2); // 2^252 - 2 BN_sub_word (two_252_2, 2); // 2^252 - 2
// -121665*inv(121666) // -121665*inv(121666)
d = BN_new (); d = BN_new ();
BN_set_word (tmp, 121666); BN_set_word (tmp, 121666);
BN_mod_inverse (tmp, tmp, q, ctx); BN_mod_inverse (tmp, tmp, q, ctx);
BN_set_word (d, 121665); BN_set_word (d, 121665);
BN_set_negative (d, 1); BN_set_negative (d, 1);
BN_mul (d, d, tmp, ctx); BN_mul (d, d, tmp, ctx);
// 2^((q-1)/4) // 2^((q-1)/4)
@ -41,20 +41,20 @@ namespace crypto
BN_free (tmp); BN_free (tmp);
tmp = BN_dup (q); tmp = BN_dup (q);
BN_sub_word (tmp, 1); BN_sub_word (tmp, 1);
BN_div_word (tmp, 4); BN_div_word (tmp, 4);
BN_set_word (I, 2); BN_set_word (I, 2);
BN_mod_exp (I, I, tmp, q, ctx); BN_mod_exp (I, I, tmp, q, ctx);
BN_free (tmp); BN_free (tmp);
// 4*inv(5) // 4*inv(5)
BIGNUM * By = BN_new (); BIGNUM * By = BN_new ();
BN_set_word (By, 5); BN_set_word (By, 5);
BN_mod_inverse (By, By, q, ctx); BN_mod_inverse (By, By, q, ctx);
BN_mul_word (By, 4); BN_mul_word (By, 4);
BIGNUM * Bx = RecoverX (By, ctx); BIGNUM * Bx = RecoverX (By, ctx);
BN_mod (Bx, Bx, q, ctx); // % q BN_mod (Bx, Bx, q, ctx); // % q
BN_mod (By, By, q, ctx); // % q BN_mod (By, By, q, ctx); // % q
// precalculate Bi256 table // precalculate Bi256 table
Bi256Carry = { Bx, By }; // B Bi256Carry = { Bx, By }; // B
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
@ -70,7 +70,7 @@ namespace crypto
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)), Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)),
d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)), d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)),
Bi256Carry (other.Bi256Carry) Bi256Carry (other.Bi256Carry)
{ {
@ -106,9 +106,9 @@ namespace crypto
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const
{ {
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
BIGNUM * h = DecodeBN<64> (digest); BIGNUM * h = DecodeBN<64> (digest);
// signature 0..31 - R, 32..63 - S // signature 0..31 - R, 32..63 - S
// B*S = R + PK*h => R = B*S - PK*h // B*S = R + PK*h => R = B*S - PK*h
// we don't decode R, but encode (B*S - PK*h) // we don't decode R, but encode (B*S - PK*h)
auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S; auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S;
@ -117,14 +117,14 @@ namespace crypto
uint8_t diff[32]; uint8_t diff[32];
EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
bool passed = !memcmp (signature, diff, 32); // R bool passed = !memcmp (signature, diff, 32); // R
BN_free (h); BN_free (h);
BN_CTX_free (ctx); BN_CTX_free (ctx);
if (!passed) if (!passed)
LogPrint (eLogError, "25519 signature verification failed"); LogPrint (eLogError, "25519 signature verification failed");
return passed; return passed;
} }
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len,
uint8_t * signature) const uint8_t * signature) const
{ {
BN_CTX * bnCtx = BN_CTX_new (); BN_CTX * bnCtx = BN_CTX_new ();
@ -138,14 +138,14 @@ namespace crypto
BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors
// calculate R // calculate R
uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors
// calculate S // calculate S
SHA512_Init (&ctx); SHA512_Init (&ctx);
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
SHA512_Update (&ctx, buf, len); // data SHA512_Update (&ctx, buf, len); // data
SHA512_Final (digest, &ctx); SHA512_Final (digest, &ctx);
BIGNUM * h = DecodeBN<64> (digest); BIGNUM * h = DecodeBN<64> (digest);
// S = (r + h*a) % l // S = (r + h*a) % l
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
BN_mod_mul (h, h, a, l, bnCtx); // %l BN_mod_mul (h, h, a, l, bnCtx); // %l
@ -156,7 +156,7 @@ namespace crypto
BN_CTX_free (bnCtx); BN_CTX_free (bnCtx);
} }
private: private:
EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
{ {
@ -165,9 +165,9 @@ namespace crypto
// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2) // z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2) // t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new (); BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2 BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2 BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
BN_CTX_start (ctx); BN_CTX_start (ctx);
BIGNUM * t1 = p1.t, * t2 = p2.t; BIGNUM * t1 = p1.t, * t2 = p2.t;
@ -189,10 +189,10 @@ namespace crypto
BN_copy (z3, p2.z); // D = z2 BN_copy (z3, p2.z); // D = z2
else else
BN_one (z3); // D = 1 BN_one (z3); // D = 1
} }
BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
BN_add (E, p1.x, p1.y); BN_add (E, p1.x, p1.y);
BN_add (F, p2.x, p2.y); BN_add (F, p2.x, p2.y);
BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2) BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
BN_sub (E, E, x3); BN_sub (E, E, x3);
@ -202,9 +202,9 @@ namespace crypto
BN_add (H, y3, x3); // H = B + A BN_add (H, y3, x3); // H = B + A
BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F
BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H
BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G
BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H
BN_CTX_end (ctx); BN_CTX_end (ctx);
@ -215,40 +215,40 @@ namespace crypto
{ {
BN_CTX_start (ctx); BN_CTX_start (ctx);
BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx); BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx);
BN_sqr (x2, p.x, ctx); // x2 = A = x^2 BN_sqr (x2, p.x, ctx); // x2 = A = x^2
BN_sqr (y2, p.y, ctx); // y2 = B = y^2 BN_sqr (y2, p.y, ctx); // y2 = B = y^2
if (p.t) if (p.t)
BN_sqr (t2, p.t, ctx); // t2 = t^2 BN_sqr (t2, p.t, ctx); // t2 = t^2
else else
{ {
BN_mul (t2, p.x, p.y, ctx); // t = x*y BN_mul (t2, p.x, p.y, ctx); // t = x*y
BN_sqr (t2, t2, ctx); // t2 = t^2 BN_sqr (t2, t2, ctx); // t2 = t^2
} }
BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2 BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
if (p.z) if (p.z)
BN_sqr (z2, p.z, ctx); // z2 = D = z^2 BN_sqr (z2, p.z, ctx); // z2 = D = z^2
else else
BN_one (z2); // z2 = 1 BN_one (z2); // z2 = 1
BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx); BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy // E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
BN_mul (E, p.x, p.y, ctx); BN_mul (E, p.x, p.y, ctx);
BN_lshift1 (E, E); // E =2*x*y BN_lshift1 (E, E); // E =2*x*y
BN_sub (F, z2, t2); // F = D - C BN_sub (F, z2, t2); // F = D - C
BN_add (G, z2, t2); // G = D + C BN_add (G, z2, t2); // G = D + C
BN_add (H, y2, x2); // H = B + A BN_add (H, y2, x2); // H = B + A
BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F
BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H
if (!p.z) p.z = BN_new (); if (!p.z) p.z = BN_new ();
BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G
if (!p.t) p.t = BN_new (); if (!p.t) p.t = BN_new ();
BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H
BN_CTX_end (ctx); BN_CTX_end (ctx);
} }
EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const
{ {
BIGNUM * zero = BN_new (), * one = BN_new (); BIGNUM * zero = BN_new (), * one = BN_new ();
@ -262,10 +262,10 @@ namespace crypto
Double (res, ctx); Double (res, ctx);
if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx); if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx);
} }
} }
return res; return res;
} }
EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian EDDSAPoint MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian
{ {
BIGNUM * zero = BN_new (), * one = BN_new (); BIGNUM * zero = BN_new (), * one = BN_new ();
@ -275,15 +275,15 @@ namespace crypto
for (int i = 0; i < 32; i++) for (int i = 0; i < 32; i++)
{ {
uint8_t x = e[i]; uint8_t x = e[i];
if (carry) if (carry)
{ {
if (x < 255) if (x < 255)
{ {
x++; x++;
carry = false; carry = false;
} }
else else
x = 0; x = 0;
} }
if (x > 0) if (x > 0)
{ {
@ -293,7 +293,7 @@ namespace crypto
{ {
res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x] res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
carry = true; carry = true;
} }
} }
} }
if (carry) res = Sum (res, Bi256Carry, ctx); if (carry) res = Sum (res, Bi256Carry, ctx);
@ -320,9 +320,9 @@ namespace crypto
BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * tmp = BN_CTX_get (ctx); BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * tmp = BN_CTX_get (ctx);
BN_sqr (x2, p.x, ctx); // x^2 BN_sqr (x2, p.x, ctx); // x^2
BN_sqr (y2, p.y, ctx); // y^2 BN_sqr (y2, p.y, ctx); // y^2
// y^2 - x^2 - 1 - d*x^2*y^2 // y^2 - x^2 - 1 - d*x^2*y^2
BN_mul (tmp, d, x2, ctx); BN_mul (tmp, d, x2, ctx);
BN_mul (tmp, tmp, y2, ctx); BN_mul (tmp, tmp, y2, ctx);
BN_sub (tmp, y2, tmp); BN_sub (tmp, y2, tmp);
BN_sub (tmp, tmp, x2); BN_sub (tmp, tmp, x2);
BN_sub_word (tmp, 1); BN_sub_word (tmp, 1);
@ -330,25 +330,25 @@ namespace crypto
bool ret = BN_is_zero (tmp); bool ret = BN_is_zero (tmp);
BN_CTX_end (ctx); BN_CTX_end (ctx);
return ret; return ret;
} }
BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const
{ {
BN_CTX_start (ctx); BN_CTX_start (ctx);
BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx); BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx);
BN_sqr (y2, y, ctx); // y^2 BN_sqr (y2, y, ctx); // y^2
// xx = (y^2 -1)*inv(d*y^2 +1) // xx = (y^2 -1)*inv(d*y^2 +1)
BN_mul (xx, d, y2, ctx); BN_mul (xx, d, y2, ctx);
BN_add_word (xx, 1); BN_add_word (xx, 1);
BN_mod_inverse (xx, xx, q, ctx); BN_mod_inverse (xx, xx, q, ctx);
BN_sub_word (y2, 1); BN_sub_word (y2, 1);
BN_mul (xx, y2, xx, ctx); BN_mul (xx, y2, xx, ctx);
// x = srqt(xx) = xx^(2^252-2) // x = srqt(xx) = xx^(2^252-2)
BIGNUM * x = BN_new (); BIGNUM * x = BN_new ();
BN_mod_exp (x, xx, two_252_2, q, ctx); BN_mod_exp (x, xx, two_252_2, q, ctx);
// check (x^2 -xx) % q // check (x^2 -xx) % q
BN_sqr (y2, x, ctx); BN_sqr (y2, x, ctx);
BN_mod_sub (y2, y2, xx, q, ctx); BN_mod_sub (y2, y2, xx, q, ctx);
if (!BN_is_zero (y2)) if (!BN_is_zero (y2))
BN_mod_mul (x, x, I, q, ctx); BN_mod_mul (x, x, I, q, ctx);
if (BN_is_odd (x)) if (BN_is_odd (x))
@ -373,18 +373,18 @@ namespace crypto
BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y); BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
BIGNUM * x = RecoverX (y, ctx); BIGNUM * x = RecoverX (y, ctx);
if (BN_is_bit_set (x, 0) != isHighestBitSet) if (BN_is_bit_set (x, 0) != isHighestBitSet)
BN_sub (x, q, x); // x = q - x BN_sub (x, q, x); // x = q - x
BIGNUM * z = BN_new (), * t = BN_new (); BIGNUM * z = BN_new (), * t = BN_new ();
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
EDDSAPoint p {x, y, z, t}; EDDSAPoint p {x, y, z, t};
if (!IsOnCurve (p, ctx)) if (!IsOnCurve (p, ctx))
LogPrint (eLogError, "Decoded point is not on 25519"); LogPrint (eLogError, "Decoded point is not on 25519");
return p; return p;
} }
void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const void EncodePoint (const EDDSAPoint& p, uint8_t * buf) const
{ {
EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH); EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH);
if (BN_is_bit_set (p.x, 0)) // highest bit if (BN_is_bit_set (p.x, 0)) // highest bit
buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit
} }
@ -413,12 +413,12 @@ namespace crypto
uint8_t tmp = buf[i]; uint8_t tmp = buf[i];
buf[i] = buf[len -1 - i]; buf[i] = buf[len -1 - i];
buf[len -1 - i] = tmp; buf[len -1 - i] = tmp;
} }
} }
private: private:
BIGNUM * q, * l, * d, * I; BIGNUM * q, * l, * d, * I;
// transient values // transient values
BIGNUM * two_252_2; // 2^252-2 BIGNUM * two_252_2; // 2^252-2
EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes EDDSAPoint Bi256[32][128]; // per byte, Bi256[i][j] = (256+j+1)^i*B, we don't store zeroes
@ -437,14 +437,14 @@ namespace crypto
g_Ed25519.reset (c); g_Ed25519.reset (c);
else else
delete c; delete c;
} }
return g_Ed25519; return g_Ed25519;
} }
EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey) EDDSA25519Verifier::EDDSA25519Verifier (const uint8_t * signingKey)
{ {
memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH); memcpy (m_PublicKeyEncoded, signingKey, EDDSA25519_PUBLIC_KEY_LENGTH);
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx); m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
BN_CTX_free (ctx); BN_CTX_free (ctx);
@ -457,40 +457,40 @@ namespace crypto
SHA512_Init (&ctx); SHA512_Init (&ctx);
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key SHA512_Update (&ctx, m_PublicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
SHA512_Update (&ctx, buf, len); // data SHA512_Update (&ctx, buf, len); // data
SHA512_Final (digest, &ctx); SHA512_Final (digest, &ctx);
return GetEd25519 ()->Verify (m_PublicKey, digest, signature); return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
} }
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
{ {
// expand key // expand key
SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey); SHA512 (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH, m_ExpandedPrivateKey);
m_ExpandedPrivateKey[0] &= 0xF8; // drop last 3 bits m_ExpandedPrivateKey[0] &= 0xF8; // drop last 3 bits
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
// generate and encode public key // generate and encode public key
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); auto publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx); GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
if (signingPublicKey && memcmp (m_PublicKeyEncoded, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH)) if (signingPublicKey && memcmp (m_PublicKeyEncoded, signingPublicKey, EDDSA25519_PUBLIC_KEY_LENGTH))
{ {
// keys don't match, it means older key with 0x1F // keys don't match, it means older key with 0x1F
LogPrint (eLogWarning, "Older EdDSA key detected"); LogPrint (eLogWarning, "Older EdDSA key detected");
m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit m_ExpandedPrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0xDF; // drop third bit
publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx); publicKey = GetEd25519 ()->GeneratePublicKey (m_ExpandedPrivateKey, ctx);
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx); GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
} }
BN_CTX_free (ctx); BN_CTX_free (ctx);
} }
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature); GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
} }
} }
} }

View file

@ -18,7 +18,7 @@ namespace crypto
class Verifier class Verifier
{ {
public: public:
virtual ~Verifier () {}; virtual ~Verifier () {};
virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0; virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0;
virtual size_t GetPublicKeyLen () const = 0; virtual size_t GetPublicKeyLen () const = 0;
@ -30,12 +30,12 @@ namespace crypto
{ {
public: public:
virtual ~Signer () {}; virtual ~Signer () {};
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0; virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
}; };
const size_t DSA_PUBLIC_KEY_LENGTH = 128; const size_t DSA_PUBLIC_KEY_LENGTH = 128;
const size_t DSA_SIGNATURE_LENGTH = 40; const size_t DSA_SIGNATURE_LENGTH = 40;
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2; const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2;
class DSAVerifier: public Verifier class DSAVerifier: public Verifier
{ {
@ -51,7 +51,7 @@ namespace crypto
{ {
DSA_free (m_PublicKey); DSA_free (m_PublicKey);
} }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
// calculate SHA1 digest // calculate SHA1 digest
@ -64,11 +64,11 @@ namespace crypto
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
DSA_SIG_free(sig); DSA_SIG_free(sig);
return ret; return ret;
} }
size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; }; size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; };
size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; }; size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; };
private: private:
DSA * m_PublicKey; DSA * m_PublicKey;
@ -89,7 +89,7 @@ namespace crypto
{ {
DSA_free (m_PrivateKey); DSA_free (m_PrivateKey);
} }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const void Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
uint8_t digest[20]; uint8_t digest[20];
@ -115,21 +115,21 @@ namespace crypto
DSA_get0_key(dsa, &pub_key, &priv_key); DSA_get0_key(dsa, &pub_key, &priv_key);
bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
DSA_free (dsa); DSA_free (dsa);
} }
struct SHA256Hash struct SHA256Hash
{ {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{ {
SHA256 (buf, len, digest); SHA256 (buf, len, digest);
} }
enum { hashLen = 32 }; enum { hashLen = 32 };
}; };
struct SHA384Hash struct SHA384Hash
{ {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{ {
SHA384 (buf, len, digest); SHA384 (buf, len, digest);
@ -139,7 +139,7 @@ namespace crypto
}; };
struct SHA512Hash struct SHA512Hash
{ {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{ {
SHA512 (buf, len, digest); SHA512 (buf, len, digest);
@ -147,10 +147,10 @@ namespace crypto
enum { hashLen = 64 }; enum { hashLen = 64 };
}; };
template<typename Hash, int curve, size_t keyLen> template<typename Hash, int curve, size_t keyLen>
class ECDSAVerifier: public Verifier class ECDSAVerifier: public Verifier
{ {
public: public:
ECDSAVerifier (const uint8_t * signingKey) ECDSAVerifier (const uint8_t * signingKey)
@ -166,7 +166,7 @@ namespace crypto
{ {
EC_KEY_free (m_PublicKey); EC_KEY_free (m_PublicKey);
} }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
@ -179,12 +179,12 @@ namespace crypto
int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey); int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey);
ECDSA_SIG_free(sig); ECDSA_SIG_free(sig);
return ret; return ret;
} }
size_t GetPublicKeyLen () const { return keyLen; }; size_t GetPublicKeyLen () const { return keyLen; };
size_t GetSignatureLen () const { return keyLen; }; // signature length = key length size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
private: private:
EC_KEY * m_PublicKey; EC_KEY * m_PublicKey;
@ -198,14 +198,14 @@ namespace crypto
ECDSASigner (const uint8_t * signingPrivateKey) ECDSASigner (const uint8_t * signingPrivateKey)
{ {
m_PrivateKey = EC_KEY_new_by_curve_name (curve); m_PrivateKey = EC_KEY_new_by_curve_name (curve);
EC_KEY_set_private_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen/2, NULL)); EC_KEY_set_private_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen/2, NULL));
} }
~ECDSASigner () ~ECDSASigner ()
{ {
EC_KEY_free (m_PrivateKey); EC_KEY_free (m_PrivateKey);
} }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const void Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
@ -235,18 +235,18 @@ namespace crypto
bn2buf (x, signingPublicKey, keyLen/2); bn2buf (x, signingPublicKey, keyLen/2);
bn2buf (y, signingPublicKey + keyLen/2, keyLen/2); bn2buf (y, signingPublicKey + keyLen/2, keyLen/2);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
EC_KEY_free (signingKey); EC_KEY_free (signingKey);
} }
// ECDSA_SHA256_P256 // ECDSA_SHA256_P256
const size_t ECDSAP256_KEY_LENGTH = 64; const size_t ECDSAP256_KEY_LENGTH = 64;
typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier; typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier;
typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer; typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer;
inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{ {
CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey); CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
} }
// ECDSA_SHA384_P384 // ECDSA_SHA384_P384
const size_t ECDSAP384_KEY_LENGTH = 96; const size_t ECDSAP384_KEY_LENGTH = 96;
@ -256,7 +256,7 @@ namespace crypto
inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{ {
CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey); CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
} }
// ECDSA_SHA512_P521 // ECDSA_SHA512_P521
const size_t ECDSAP521_KEY_LENGTH = 132; const size_t ECDSAP521_KEY_LENGTH = 132;
@ -269,7 +269,7 @@ namespace crypto
} }
// RSA // RSA
template<typename Hash, int type, size_t keyLen> template<typename Hash, int type, size_t keyLen>
class RSAVerifier: public Verifier class RSAVerifier: public Verifier
{ {
public: public:
@ -284,23 +284,23 @@ namespace crypto
{ {
RSA_free (m_PublicKey); RSA_free (m_PublicKey);
} }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
Hash::CalculateHash (buf, len, digest); Hash::CalculateHash (buf, len, digest);
return RSA_verify (type, digest, Hash::hashLen, signature, GetSignatureLen (), m_PublicKey); return RSA_verify (type, digest, Hash::hashLen, signature, GetSignatureLen (), m_PublicKey);
} }
size_t GetPublicKeyLen () const { return keyLen; } size_t GetPublicKeyLen () const { return keyLen; }
size_t GetSignatureLen () const { return keyLen; } size_t GetSignatureLen () const { return keyLen; }
size_t GetPrivateKeyLen () const { return GetSignatureLen ()*2; }; size_t GetPrivateKeyLen () const { return GetSignatureLen ()*2; };
private: private:
RSA * m_PublicKey;
};
RSA * m_PublicKey;
};
template<typename Hash, int type, size_t keyLen> template<typename Hash, int type, size_t keyLen>
class RSASigner: public Signer class RSASigner: public Signer
{ {
@ -317,7 +317,7 @@ namespace crypto
{ {
RSA_free (m_PrivateKey); RSA_free (m_PrivateKey);
} }
void Sign (const uint8_t * buf, int len, uint8_t * signature) const void Sign (const uint8_t * buf, int len, uint8_t * signature) const
{ {
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
@ -325,11 +325,11 @@ namespace crypto
unsigned int signatureLen = keyLen; unsigned int signatureLen = keyLen;
RSA_sign (type, digest, Hash::hashLen, signature, &signatureLen, m_PrivateKey); RSA_sign (type, digest, Hash::hashLen, signature, &signatureLen, m_PrivateKey);
} }
private: private:
RSA * m_PrivateKey; RSA * m_PrivateKey;
}; };
inline void CreateRSARandomKeys (size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateRSARandomKeys (size_t publicKeyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{ {
@ -337,14 +337,14 @@ namespace crypto
BIGNUM * e = BN_dup (GetRSAE ()); // make it non-const BIGNUM * e = BN_dup (GetRSAE ()); // make it non-const
RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL); RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL);
const BIGNUM * n, * d, * e1; const BIGNUM * n, * d, * e1;
RSA_get0_key (rsa, &n, &e1, &d); RSA_get0_key (rsa, &n, &e1, &d);
bn2buf (n, signingPrivateKey, publicKeyLen); bn2buf (n, signingPrivateKey, publicKeyLen);
bn2buf (d, signingPrivateKey + publicKeyLen, publicKeyLen); bn2buf (d, signingPrivateKey + publicKeyLen, publicKeyLen);
bn2buf (n, signingPublicKey, publicKeyLen); bn2buf (n, signingPublicKey, publicKeyLen);
BN_free (e); // this e is not assigned to rsa->e BN_free (e); // this e is not assigned to rsa->e
RSA_free (rsa); RSA_free (rsa);
} }
// RSA_SHA256_2048 // RSA_SHA256_2048
const size_t RSASHA2562048_KEY_LENGTH = 256; const size_t RSASHA2562048_KEY_LENGTH = 256;
typedef RSAVerifier<SHA256Hash, NID_sha256, RSASHA2562048_KEY_LENGTH> RSASHA2562048Verifier; typedef RSAVerifier<SHA256Hash, NID_sha256, RSASHA2562048_KEY_LENGTH> RSASHA2562048Verifier;
@ -353,7 +353,7 @@ namespace crypto
// RSA_SHA384_3072 // RSA_SHA384_3072
const size_t RSASHA3843072_KEY_LENGTH = 384; const size_t RSASHA3843072_KEY_LENGTH = 384;
typedef RSAVerifier<SHA384Hash, NID_sha384, RSASHA3843072_KEY_LENGTH> RSASHA3843072Verifier; typedef RSAVerifier<SHA384Hash, NID_sha384, RSASHA3843072_KEY_LENGTH> RSASHA3843072Verifier;
typedef RSASigner<SHA384Hash, NID_sha384, RSASHA3843072_KEY_LENGTH> RSASHA3843072Signer; typedef RSASigner<SHA384Hash, NID_sha384, RSASHA3843072_KEY_LENGTH> RSASHA3843072Signer;
// RSA_SHA512_4096 // RSA_SHA512_4096
const size_t RSASHA5124096_KEY_LENGTH = 512; const size_t RSASHA5124096_KEY_LENGTH = 512;
@ -379,7 +379,7 @@ namespace crypto
{} {}
~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); } ~EDDSAPoint () { BN_free (x); BN_free (y); BN_free(z); BN_free(t); }
EDDSAPoint& operator=(EDDSAPoint&& other) EDDSAPoint& operator=(EDDSAPoint&& other)
{ {
if (this != &other) if (this != &other)
{ {
@ -389,9 +389,9 @@ namespace crypto
BN_free (t); t = other.t; other.t = nullptr; BN_free (t); t = other.t; other.t = nullptr;
} }
return *this; return *this;
} }
EDDSAPoint& operator=(const EDDSAPoint& other) EDDSAPoint& operator=(const EDDSAPoint& other)
{ {
if (this != &other) if (this != &other)
{ {
@ -412,11 +412,11 @@ namespace crypto
if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); }; if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); };
return EDDSAPoint {x1, y1, z1, t1}; return EDDSAPoint {x1, y1, z1, t1};
} }
}; };
const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32; const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32;
const size_t EDDSA25519_SIGNATURE_LENGTH = 64; const size_t EDDSA25519_SIGNATURE_LENGTH = 64;
const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32; const size_t EDDSA25519_PRIVATE_KEY_LENGTH = 32;
class EDDSA25519Verifier: public Verifier class EDDSA25519Verifier: public Verifier
{ {
public: public:
@ -429,7 +429,7 @@ namespace crypto
private: private:
EDDSAPoint m_PublicKey; EDDSAPoint m_PublicKey;
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
}; };
@ -437,14 +437,14 @@ namespace crypto
{ {
public: public:
EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr); EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
// we pass signingPublicKey to check if it matches private key // we pass signingPublicKey to check if it matches private key
void Sign (const uint8_t * buf, int len, uint8_t * signature) const; void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; };
private: private:
uint8_t m_ExpandedPrivateKey[64]; uint8_t m_ExpandedPrivateKey[64];
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
}; };
@ -456,22 +456,22 @@ namespace crypto
} }
// ГОСТ Р 34.11 // ГОСТ Р 34.11
struct GOSTR3411_256_Hash struct GOSTR3411_256_Hash
{ {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{ {
GOSTR3411_2012_256 (buf, len, digest); GOSTR3411_2012_256 (buf, len, digest);
} }
enum { hashLen = 32 }; enum { hashLen = 32 };
}; };
struct GOSTR3411_512_Hash struct GOSTR3411_512_Hash
{ {
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
{ {
GOSTR3411_2012_512 (buf, len, digest); GOSTR3411_2012_512 (buf, len, digest);
} }
enum { hashLen = 64 }; enum { hashLen = 64 };
@ -487,7 +487,7 @@ namespace crypto
public: public:
enum { keyLen = Hash::hashLen }; enum { keyLen = Hash::hashLen };
GOSTR3410Verifier (GOSTR3410ParamSet paramSet, const uint8_t * signingKey): GOSTR3410Verifier (GOSTR3410ParamSet paramSet, const uint8_t * signingKey):
m_ParamSet (paramSet) m_ParamSet (paramSet)
{ {
@ -497,7 +497,7 @@ namespace crypto
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }
~GOSTR3410Verifier () { EC_POINT_free (m_PublicKey); } ~GOSTR3410Verifier () { EC_POINT_free (m_PublicKey); }
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
{ {
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
@ -506,7 +506,7 @@ namespace crypto
BIGNUM * r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL); BIGNUM * r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL);
BIGNUM * s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); BIGNUM * s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL);
bool ret = GetGOSTR3410Curve (m_ParamSet)->Verify (m_PublicKey, d, r, s); bool ret = GetGOSTR3410Curve (m_ParamSet)->Verify (m_PublicKey, d, r, s);
BN_free (d); BN_free (r); BN_free (s); BN_free (d); BN_free (r); BN_free (s);
return ret; return ret;
} }
@ -517,7 +517,7 @@ namespace crypto
GOSTR3410ParamSet m_ParamSet; GOSTR3410ParamSet m_ParamSet;
EC_POINT * m_PublicKey; EC_POINT * m_PublicKey;
}; };
template<typename Hash> template<typename Hash>
class GOSTR3410Signer: public Signer class GOSTR3410Signer: public Signer
@ -525,11 +525,11 @@ namespace crypto
public: public:
enum { keyLen = Hash::hashLen }; enum { keyLen = Hash::hashLen };
GOSTR3410Signer (GOSTR3410ParamSet paramSet, const uint8_t * signingPrivateKey): GOSTR3410Signer (GOSTR3410ParamSet paramSet, const uint8_t * signingPrivateKey):
m_ParamSet (paramSet) m_ParamSet (paramSet)
{ {
m_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr); m_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
} }
~GOSTR3410Signer () { BN_free (m_PrivateKey); } ~GOSTR3410Signer () { BN_free (m_PrivateKey); }
@ -537,19 +537,19 @@ namespace crypto
{ {
uint8_t digest[Hash::hashLen]; uint8_t digest[Hash::hashLen];
Hash::CalculateHash (buf, len, digest); Hash::CalculateHash (buf, len, digest);
BIGNUM * d = BN_bin2bn (digest, Hash::hashLen, nullptr); BIGNUM * d = BN_bin2bn (digest, Hash::hashLen, nullptr);
BIGNUM * r = BN_new (), * s = BN_new (); BIGNUM * r = BN_new (), * s = BN_new ();
GetGOSTR3410Curve (m_ParamSet)->Sign (m_PrivateKey, d, r, s); GetGOSTR3410Curve (m_ParamSet)->Sign (m_PrivateKey, d, r, s);
bn2buf (r, signature, keyLen); bn2buf (r, signature, keyLen);
bn2buf (s, signature + keyLen, keyLen); bn2buf (s, signature + keyLen, keyLen);
BN_free (d); BN_free (r); BN_free (s); BN_free (d); BN_free (r); BN_free (s);
} }
private: private:
GOSTR3410ParamSet m_ParamSet; GOSTR3410ParamSet m_ParamSet;
BIGNUM * m_PrivateKey; BIGNUM * m_PrivateKey;
}; };
inline void CreateGOSTR3410RandomKeys (GOSTR3410ParamSet paramSet, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) inline void CreateGOSTR3410RandomKeys (GOSTR3410ParamSet paramSet, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
{ {
@ -557,7 +557,7 @@ namespace crypto
auto keyLen = curve->GetKeyLen (); auto keyLen = curve->GetKeyLen ();
RAND_bytes (signingPrivateKey, keyLen); RAND_bytes (signingPrivateKey, keyLen);
BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen, nullptr); BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
auto pub = curve->MulP (priv); auto pub = curve->MulP (priv);
BN_free (priv); BN_free (priv);
BIGNUM * x = BN_new (), * y = BN_new (); BIGNUM * x = BN_new (), * y = BN_new ();
@ -565,7 +565,7 @@ namespace crypto
EC_POINT_free (pub); EC_POINT_free (pub);
bn2buf (x, signingPublicKey, keyLen); bn2buf (x, signingPublicKey, keyLen);
bn2buf (y, signingPublicKey + keyLen, keyLen); bn2buf (y, signingPublicKey + keyLen, keyLen);
BN_free (x); BN_free (y); BN_free (x); BN_free (y);
} }
typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier; typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier;

View file

@ -12,11 +12,11 @@ namespace i2p
namespace stream namespace stream
{ {
void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler) void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler)
{ {
m_Buffers.push_back (std::make_shared<SendBuffer>(buf, len, handler)); m_Buffers.push_back (std::make_shared<SendBuffer>(buf, len, handler));
m_Size += len; m_Size += len;
} }
size_t SendBufferQueue::Get (uint8_t * buf, size_t len) size_t SendBufferQueue::Get (uint8_t * buf, size_t len)
{ {
size_t offset = 0; size_t offset = 0;
@ -30,7 +30,7 @@ namespace stream
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem); memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem);
offset += rem; offset += rem;
m_Buffers.pop_front (); // delete it m_Buffers.pop_front (); // delete it
} }
else else
{ {
// partially // partially
@ -38,23 +38,23 @@ namespace stream
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset); memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset);
nextBuffer->offset += (len - offset); nextBuffer->offset += (len - offset);
offset = len; // break offset = len; // break
} }
} }
m_Size -= offset; m_Size -= offset;
return offset; return offset;
} }
void SendBufferQueue::CleanUp () void SendBufferQueue::CleanUp ()
{ {
if (!m_Buffers.empty ()) if (!m_Buffers.empty ())
{ {
for (auto it: m_Buffers) for (auto it: m_Buffers)
it->Cancel (); it->Cancel ();
m_Buffers.clear (); m_Buffers.clear ();
m_Size = 0; m_Size = 0;
} }
} }
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local, Stream::Stream (boost::asio::io_service& service, StreamingDestination& local,
std::shared_ptr<const i2p::data::LeaseSet> remote, int port): m_Service (service), std::shared_ptr<const i2p::data::LeaseSet> remote, int port): m_Service (service),
m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1), m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1),
@ -100,7 +100,7 @@ namespace stream
{ {
std::unique_lock<std::mutex> l(m_SendBufferMutex); std::unique_lock<std::mutex> l(m_SendBufferMutex);
m_SendBuffer.CleanUp (); m_SendBuffer.CleanUp ();
} }
while (!m_ReceiveQueue.empty ()) while (!m_ReceiveQueue.empty ())
{ {
auto packet = m_ReceiveQueue.front (); auto packet = m_ReceiveQueue.front ();
@ -1108,7 +1108,7 @@ namespace stream
} }
else // we must save old acceptor and set it back else // we must save old acceptor and set it back
{ {
m_Acceptor = std::bind (&StreamingDestination::AcceptOnceAcceptor, this, m_Acceptor = std::bind (&StreamingDestination::AcceptOnceAcceptor, this,
std::placeholders::_1, acceptor, m_Acceptor); std::placeholders::_1, acceptor, m_Acceptor);
} }
}); });
@ -1118,8 +1118,8 @@ namespace stream
{ {
m_Acceptor = prev; m_Acceptor = prev;
acceptor (stream); acceptor (stream);
} }
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode) void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
{ {
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)

View file

@ -41,40 +41,40 @@ namespace stream
const size_t STREAMING_MTU = 1730; const size_t STREAMING_MTU = 1730;
const size_t MAX_PACKET_SIZE = 4096; const size_t MAX_PACKET_SIZE = 4096;
const size_t COMPRESSION_THRESHOLD_SIZE = 66; const size_t COMPRESSION_THRESHOLD_SIZE = 66;
const int MAX_NUM_RESEND_ATTEMPTS = 6; const int MAX_NUM_RESEND_ATTEMPTS = 6;
const int WINDOW_SIZE = 6; // in messages const int WINDOW_SIZE = 6; // in messages
const int MIN_WINDOW_SIZE = 1; const int MIN_WINDOW_SIZE = 1;
const int MAX_WINDOW_SIZE = 128; const int MAX_WINDOW_SIZE = 128;
const int INITIAL_RTT = 8000; // in milliseconds const int INITIAL_RTT = 8000; // in milliseconds
const int INITIAL_RTO = 9000; // in milliseconds const int INITIAL_RTO = 9000; // in milliseconds
const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds const int SYN_TIMEOUT = 200; // how long we wait for SYN after follow-on, in milliseconds
const size_t MAX_PENDING_INCOMING_BACKLOG = 128; const size_t MAX_PENDING_INCOMING_BACKLOG = 128;
const int PENDING_INCOMING_TIMEOUT = 10; // in seconds const int PENDING_INCOMING_TIMEOUT = 10; // in seconds
const int MAX_RECEIVE_TIMEOUT = 30; // in seconds const int MAX_RECEIVE_TIMEOUT = 30; // in seconds
/** i2cp option for limiting inbound stremaing connections */ /** i2cp option for limiting inbound stremaing connections */
const char I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN[] = "maxconns"; const char I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN[] = "maxconns";
/** default maximum connections attempts per minute per destination */ /** default maximum connections attempts per minute per destination */
const uint32_t DEFAULT_MAX_CONNS_PER_MIN = 600; const uint32_t DEFAULT_MAX_CONNS_PER_MIN = 600;
/** /**
* max banned destinations per local destination * max banned destinations per local destination
* TODO: make configurable * TODO: make configurable
*/ */
const uint16_t MAX_BANNED_CONNS = 9999; const uint16_t MAX_BANNED_CONNS = 9999;
/** /**
* length of a ban in ms * length of a ban in ms
* TODO: make configurable * TODO: make configurable
*/ */
const uint64_t DEFAULT_BAN_INTERVAL = 60 * 60 * 1000; const uint64_t DEFAULT_BAN_INTERVAL = 60 * 60 * 1000;
struct Packet struct Packet
{ {
size_t len, offset; size_t len, offset;
uint8_t buf[MAX_PACKET_SIZE]; uint8_t buf[MAX_PACKET_SIZE];
uint64_t sendTime; uint64_t sendTime;
Packet (): len (0), offset (0), sendTime (0) {}; Packet (): len (0), offset (0), sendTime (0) {};
uint8_t * GetBuffer () { return buf + offset; }; uint8_t * GetBuffer () { return buf + offset; };
size_t GetLength () const { return len - offset; }; size_t GetLength () const { return len - offset; };
@ -93,15 +93,15 @@ namespace stream
bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; }; bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; };
bool IsNoAck () const { return GetFlags () & PACKET_FLAG_NO_ACK; }; bool IsNoAck () const { return GetFlags () & PACKET_FLAG_NO_ACK; };
}; };
struct PacketCmp struct PacketCmp
{ {
bool operator() (const Packet * p1, const Packet * p2) const bool operator() (const Packet * p1, const Packet * p2) const
{ {
return p1->GetSeqn () < p2->GetSeqn (); return p1->GetSeqn () < p2->GetSeqn ();
}; };
}; };
typedef std::function<void (const boost::system::error_code& ecode)> SendHandler; typedef std::function<void (const boost::system::error_code& ecode)> SendHandler;
struct SendBuffer struct SendBuffer
@ -115,16 +115,16 @@ namespace stream
{ {
buf = new uint8_t[len]; buf = new uint8_t[len];
memcpy (buf, b, len); memcpy (buf, b, len);
} }
~SendBuffer () ~SendBuffer ()
{ {
delete[] buf; delete[] buf;
if (handler) handler(boost::system::error_code ()); if (handler) handler(boost::system::error_code ());
} }
size_t GetRemainingSize () const { return len - offset; }; size_t GetRemainingSize () const { return len - offset; };
const uint8_t * GetRemaningBuffer () const { return buf + offset; }; const uint8_t * GetRemaningBuffer () const { return buf + offset; };
void Cancel () { if (handler) handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted)); handler = nullptr; }; void Cancel () { if (handler) handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted)); handler = nullptr; };
}; };
class SendBufferQueue class SendBufferQueue
{ {
@ -133,18 +133,18 @@ namespace stream
SendBufferQueue (): m_Size (0) {}; SendBufferQueue (): m_Size (0) {};
~SendBufferQueue () { CleanUp (); }; ~SendBufferQueue () { CleanUp (); };
void Add (const uint8_t * buf, size_t len, SendHandler handler); void Add (const uint8_t * buf, size_t len, SendHandler handler);
size_t Get (uint8_t * buf, size_t len); size_t Get (uint8_t * buf, size_t len);
size_t GetSize () const { return m_Size; }; size_t GetSize () const { return m_Size; };
bool IsEmpty () const { return m_Buffers.empty (); }; bool IsEmpty () const { return m_Buffers.empty (); };
void CleanUp (); void CleanUp ();
private: private:
std::list<std::shared_ptr<SendBuffer> > m_Buffers; std::list<std::shared_ptr<SendBuffer> > m_Buffers;
size_t m_Size; size_t m_Size;
}; };
enum StreamStatus enum StreamStatus
{ {
eStreamStatusNew = 0, eStreamStatusNew = 0,
@ -152,16 +152,16 @@ namespace stream
eStreamStatusReset, eStreamStatusReset,
eStreamStatusClosing, eStreamStatusClosing,
eStreamStatusClosed eStreamStatusClosed
}; };
class StreamingDestination; class StreamingDestination;
class Stream: public std::enable_shared_from_this<Stream> class Stream: public std::enable_shared_from_this<Stream>
{ {
public: public:
Stream (boost::asio::io_service& service, StreamingDestination& local, Stream (boost::asio::io_service& service, StreamingDestination& local,
std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); // outgoing
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
~Stream (); ~Stream ();
uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetSendStreamID () const { return m_SendStreamID; };
@ -172,15 +172,15 @@ namespace stream
bool IsEstablished () const { return m_SendStreamID; }; bool IsEstablished () const { return m_SendStreamID; };
StreamStatus GetStatus () const { return m_Status; }; StreamStatus GetStatus () const { return m_Status; };
StreamingDestination& GetLocalDestination () { return m_LocalDestination; }; StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
void HandleNextPacket (Packet * packet); void HandleNextPacket (Packet * packet);
size_t Send (const uint8_t * buf, size_t len); size_t Send (const uint8_t * buf, size_t len);
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler); void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0); void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); }; size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
void Close (); void Close ();
void Cancel () { m_ReceiveTimer.cancel (); }; void Cancel () { m_ReceiveTimer.cancel (); };
@ -194,11 +194,11 @@ namespace stream
/** don't call me */ /** don't call me */
void Terminate (); void Terminate ();
private: private:
void CleanUp (); void CleanUp ();
void SendBuffer (); void SendBuffer ();
void SendQuickAck (); void SendQuickAck ();
void SendClose (); void SendClose ();
@ -212,14 +212,14 @@ namespace stream
size_t ConcatenatePackets (uint8_t * buf, size_t len); size_t ConcatenatePackets (uint8_t * buf, size_t len);
void UpdateCurrentRemoteLease (bool expired = false); void UpdateCurrentRemoteLease (bool expired = false);
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout); void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout);
void ScheduleResend (); void ScheduleResend ();
void HandleResendTimer (const boost::system::error_code& ecode); void HandleResendTimer (const boost::system::error_code& ecode);
void HandleAckSendTimer (const boost::system::error_code& ecode); void HandleAckSendTimer (const boost::system::error_code& ecode);
private: private:
boost::asio::io_service& m_Service; boost::asio::io_service& m_Service;
@ -254,16 +254,16 @@ namespace stream
typedef std::function<void (std::shared_ptr<Stream>)> Acceptor; typedef std::function<void (std::shared_ptr<Stream>)> Acceptor;
StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0, bool gzip = true); StreamingDestination (std::shared_ptr<i2p::client::ClientDestination> owner, uint16_t localPort = 0, bool gzip = true);
~StreamingDestination (); ~StreamingDestination ();
void Start (); void Start ();
void Stop (); void Stop ();
std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0); std::shared_ptr<Stream> CreateNewOutgoingStream (std::shared_ptr<const i2p::data::LeaseSet> remote, int port = 0);
void DeleteStream (std::shared_ptr<Stream> stream); void DeleteStream (std::shared_ptr<Stream> stream);
void SetAcceptor (const Acceptor& acceptor); void SetAcceptor (const Acceptor& acceptor);
void ResetAcceptor (); void ResetAcceptor ();
bool IsAcceptorSet () const { return m_Acceptor != nullptr; }; bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
void AcceptOnce (const Acceptor& acceptor); void AcceptOnce (const Acceptor& acceptor);
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; }; std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
@ -278,11 +278,10 @@ namespace stream
Packet * NewPacket () { return new Packet; } Packet * NewPacket () { return new Packet; }
void DeletePacket (Packet * p) { delete p; } void DeletePacket (Packet * p) { delete p; }
private:
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev); void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
void HandleNextPacket (Packet * packet); void HandleNextPacket (Packet * packet);
std::shared_ptr<Stream> CreateNewIncomingStream (); std::shared_ptr<Stream> CreateNewIncomingStream ();
void HandlePendingIncomingTimer (const boost::system::error_code& ecode); void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
@ -293,7 +292,7 @@ namespace stream
bool DropNewStream(const i2p::data::IdentHash & ident); bool DropNewStream(const i2p::data::IdentHash & ident);
void ScheduleConnTrack(); void ScheduleConnTrack();
private: private:
std::shared_ptr<i2p::client::ClientDestination> m_Owner; std::shared_ptr<i2p::client::ClientDestination> m_Owner;
@ -306,7 +305,7 @@ namespace stream
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams; std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
boost::asio::deadline_timer m_PendingIncomingTimer; boost::asio::deadline_timer m_PendingIncomingTimer;
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
std::mutex m_ConnsMutex; std::mutex m_ConnsMutex;
/** how many connections per minute did each identity have */ /** how many connections per minute did each identity have */
std::map<i2p::data::IdentHash, uint32_t> m_Conns; std::map<i2p::data::IdentHash, uint32_t> m_Conns;
@ -318,15 +317,15 @@ namespace stream
//i2p::util::MemoryPool<Packet> m_PacketsPool; //i2p::util::MemoryPool<Packet> m_PacketsPool;
bool m_EnableDrop; bool m_EnableDrop;
public: public:
i2p::data::GzipInflator m_Inflator; i2p::data::GzipInflator m_Inflator;
i2p::data::GzipDeflator m_Deflator; i2p::data::GzipDeflator m_Deflator;
// for HTTP only // for HTTP only
const decltype(m_Streams)& GetStreams () const { return m_Streams; }; const decltype(m_Streams)& GetStreams () const { return m_Streams; };
}; };
//------------------------------------------------- //-------------------------------------------------
@ -350,7 +349,7 @@ namespace stream
self->HandleReceiveTimer(ec, buffer, handler, left); self->HandleReceiveTimer(ec, buffer, handler, left);
}); });
} }
}); });
} }
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
@ -360,27 +359,27 @@ namespace stream
if (received > 0) if (received > 0)
handler (boost::system::error_code (), received); handler (boost::system::error_code (), received);
else if (ecode == boost::asio::error::operation_aborted) else if (ecode == boost::asio::error::operation_aborted)
{ {
// timeout not expired // timeout not expired
if (m_Status == eStreamStatusReset) if (m_Status == eStreamStatusReset)
handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0); handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0);
else else
handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0); handler (boost::asio::error::make_error_code (boost::asio::error::operation_aborted), 0);
} }
else else
{ {
// timeout expired // timeout expired
if (remainingTimeout <= 0) if (remainingTimeout <= 0)
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received); handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
else else
{ {
// itermediate iterrupt // itermediate iterrupt
SendUpdatedLeaseSet (); // send our leaseset if applicable SendUpdatedLeaseSet (); // send our leaseset if applicable
AsyncReceive (buffer, handler, remainingTimeout); AsyncReceive (buffer, handler, remainingTimeout);
} }
} }
} }
} }
} }
#endif #endif

View file

@ -56,7 +56,7 @@ public:
{ {
RAND_bytes(m_Buf, sz); RAND_bytes(m_Buf, sz);
} }
std::string ToBase64 () const std::string ToBase64 () const
{ {
char str[sz*2]; char str[sz*2];

View file

@ -40,7 +40,7 @@ namespace util
int i = 0; int i = 0;
while (!socket.available() && i < 10) // 10 seconds max while (!socket.available() && i < 10) // 10 seconds max
{ {
std::this_thread::sleep_for (std::chrono::seconds(1)); std::this_thread::sleep_for (std::chrono::seconds(1));
i++; i++;
} }
if (socket.available ()) if (socket.available ())

View file

@ -11,19 +11,19 @@ namespace util
inline uint64_t GetMillisecondsSinceEpoch () inline uint64_t GetMillisecondsSinceEpoch ()
{ {
return std::chrono::duration_cast<std::chrono::milliseconds>( return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count (); std::chrono::system_clock::now().time_since_epoch()).count ();
} }
inline uint32_t GetHoursSinceEpoch () inline uint32_t GetHoursSinceEpoch ()
{ {
return std::chrono::duration_cast<std::chrono::hours>( return std::chrono::duration_cast<std::chrono::hours>(
std::chrono::system_clock::now().time_since_epoch()).count (); std::chrono::system_clock::now().time_since_epoch()).count ();
} }
inline uint64_t GetSecondsSinceEpoch () inline uint64_t GetSecondsSinceEpoch ()
{ {
return std::chrono::duration_cast<std::chrono::seconds>( return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count (); std::chrono::system_clock::now().time_since_epoch()).count ();
} }
} }
} }

View file

@ -10,58 +10,58 @@
namespace i2p namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID, TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey): const uint8_t * layerKey,const uint8_t * ivKey):
TunnelBase (receiveTunnelID, nextTunnelID, nextIdent) TunnelBase (receiveTunnelID, nextTunnelID, nextIdent)
{ {
m_Encryption.SetKeys (layerKey, ivKey); m_Encryption.SetKeys (layerKey, ivKey);
} }
void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) void TransitTunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
{ {
m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4); m_Encryption.Encrypt (in->GetPayload () + 4, out->GetPayload () + 4);
i2p::transport::transports.UpdateTotalTransitTransmittedBytes (TUNNEL_DATA_MSG_SIZE); i2p::transport::transports.UpdateTotalTransitTransmittedBytes (TUNNEL_DATA_MSG_SIZE);
} }
TransitTunnelParticipant::~TransitTunnelParticipant () TransitTunnelParticipant::~TransitTunnelParticipant ()
{ {
} }
void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (tunnelMsg, newMsg); EncryptTunnelMsg (tunnelMsg, newMsg);
m_NumTransmittedBytes += tunnelMsg->GetLength (); m_NumTransmittedBytes += tunnelMsg->GetLength ();
htobe32buf (newMsg->GetPayload (), GetNextTunnelID ()); htobe32buf (newMsg->GetPayload (), GetNextTunnelID ());
newMsg->FillI2NPMessageHeader (eI2NPTunnelData); newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
m_TunnelDataMsgs.push_back (newMsg); m_TunnelDataMsgs.push_back (newMsg);
} }
void TransitTunnelParticipant::FlushTunnelDataMsgs () void TransitTunnelParticipant::FlushTunnelDataMsgs ()
{ {
if (!m_TunnelDataMsgs.empty ()) if (!m_TunnelDataMsgs.empty ())
{ {
auto num = m_TunnelDataMsgs.size (); auto num = m_TunnelDataMsgs.size ();
if (num > 1) if (num > 1)
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num); LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs); i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
m_TunnelDataMsgs.clear (); m_TunnelDataMsgs.clear ();
} }
} }
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ()); LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ());
} }
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ()); LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ());
} }
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
{ {
TunnelMessageBlock block; TunnelMessageBlock block;
@ -69,43 +69,43 @@ namespace tunnel
block.data = msg; block.data = msg;
std::unique_lock<std::mutex> l(m_SendMutex); std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.PutTunnelDataMsg (block); m_Gateway.PutTunnelDataMsg (block);
} }
void TransitTunnelGateway::FlushTunnelDataMsgs () void TransitTunnelGateway::FlushTunnelDataMsgs ()
{ {
std::unique_lock<std::mutex> l(m_SendMutex); std::unique_lock<std::mutex> l(m_SendMutex);
m_Gateway.SendBuffer (); m_Gateway.SendBuffer ();
} }
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
{ {
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg ();
EncryptTunnelMsg (tunnelMsg, newMsg); EncryptTunnelMsg (tunnelMsg, newMsg);
LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ()); LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ());
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg); m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
} }
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID, std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey, const uint8_t * layerKey,const uint8_t * ivKey,
bool isGateway, bool isEndpoint) bool isGateway, bool isEndpoint)
{ {
if (isEndpoint) if (isEndpoint)
{ {
LogPrint (eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created"); LogPrint (eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
} }
else if (isGateway) else if (isGateway)
{ {
LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created"); LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
return std::make_shared<TransitTunnelGateway> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); return std::make_shared<TransitTunnelGateway> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
} }
else else
{ {
LogPrint (eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created"); LogPrint (eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey); return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
} }
} }
} }
} }

View file

@ -14,34 +14,34 @@
namespace i2p namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
class TransitTunnel: public TunnelBase class TransitTunnel: public TunnelBase
{ {
public: public:
TransitTunnel (uint32_t receiveTunnelID, TransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey); const uint8_t * layerKey,const uint8_t * ivKey);
virtual size_t GetNumTransmittedBytes () const { return 0; }; virtual size_t GetNumTransmittedBytes () const { return 0; };
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out); void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
private: private:
i2p::crypto::TunnelEncryption m_Encryption; i2p::crypto::TunnelEncryption m_Encryption;
}; };
class TransitTunnelParticipant: public TransitTunnel class TransitTunnelParticipant: public TransitTunnel
{ {
public: public:
TransitTunnelParticipant (uint32_t receiveTunnelID, TransitTunnelParticipant (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey): const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_NumTransmittedBytes (0) {}; layerKey, ivKey), m_NumTransmittedBytes (0) {};
~TransitTunnelParticipant (); ~TransitTunnelParticipant ();
@ -53,51 +53,51 @@ namespace tunnel
size_t m_NumTransmittedBytes; size_t m_NumTransmittedBytes;
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs; std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
}; };
class TransitTunnelGateway: public TransitTunnel class TransitTunnelGateway: public TransitTunnel
{ {
public: public:
TransitTunnelGateway (uint32_t receiveTunnelID, TransitTunnelGateway (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey): const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
layerKey, ivKey), m_Gateway(this) {}; layerKey, ivKey), m_Gateway(this) {};
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void FlushTunnelDataMsgs (); void FlushTunnelDataMsgs ();
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
private: private:
std::mutex m_SendMutex; std::mutex m_SendMutex;
TunnelGateway m_Gateway; TunnelGateway m_Gateway;
}; };
class TransitTunnelEndpoint: public TransitTunnel class TransitTunnelEndpoint: public TransitTunnel
{ {
public: public:
TransitTunnelEndpoint (uint32_t receiveTunnelID, TransitTunnelEndpoint (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey): const uint8_t * layerKey,const uint8_t * ivKey):
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
m_Endpoint (false) {}; // transit endpoint is always outbound m_Endpoint (false) {}; // transit endpoint is always outbound
void Cleanup () { m_Endpoint.Cleanup (); } void Cleanup () { m_Endpoint.Cleanup (); }
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); } size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
private: private:
TunnelEndpoint m_Endpoint; TunnelEndpoint m_Endpoint;
}; };
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID, std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID,
const uint8_t * layerKey,const uint8_t * ivKey, const uint8_t * layerKey,const uint8_t * ivKey,
bool isGateway, bool isEndpoint); bool isGateway, bool isEndpoint);
} }
} }

View file

@ -20,42 +20,42 @@ namespace transport
public: public:
SignedData () {} SignedData () {}
SignedData (const SignedData& other) SignedData (const SignedData& other)
{ {
m_Stream << other.m_Stream.rdbuf (); m_Stream << other.m_Stream.rdbuf ();
} }
void Insert (const uint8_t * buf, size_t len) void Insert (const uint8_t * buf, size_t len)
{ {
m_Stream.write ((char *)buf, len); m_Stream.write ((char *)buf, len);
} }
template<typename T> template<typename T>
void Insert (T t) void Insert (T t)
{ {
m_Stream.write ((char *)&t, sizeof (T)); m_Stream.write ((char *)&t, sizeof (T));
} }
bool Verify (std::shared_ptr<const i2p::data::IdentityEx> ident, const uint8_t * signature) const bool Verify (std::shared_ptr<const i2p::data::IdentityEx> ident, const uint8_t * signature) const
{ {
return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); return ident->Verify ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
} }
void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const void Sign (const i2p::data::PrivateKeys& keys, uint8_t * signature) const
{ {
keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature); keys.Sign ((const uint8_t *)m_Stream.str ().c_str (), m_Stream.str ().size (), signature);
} }
private: private:
std::stringstream m_Stream; std::stringstream m_Stream;
}; };
class TransportSession class TransportSession
{ {
public: public:
TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout): TransportSession (std::shared_ptr<const i2p::data::RouterInfo> router, int terminationTimeout):
m_DHKeysPair (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout), m_DHKeysPair (nullptr), m_NumSentBytes (0), m_NumReceivedBytes (0), m_IsOutgoing (router), m_TerminationTimeout (terminationTimeout),
m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ()) m_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ())
{ {
if (router) if (router)
@ -66,30 +66,30 @@ namespace transport
virtual void Done () = 0; virtual void Done () = 0;
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; } std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () { return m_RemoteIdentity; }; std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () { return m_RemoteIdentity; };
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) { m_RemoteIdentity = ident; }; void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) { m_RemoteIdentity = ident; };
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
bool IsOutgoing () const { return m_IsOutgoing; }; bool IsOutgoing () const { return m_IsOutgoing; };
int GetTerminationTimeout () const { return m_TerminationTimeout; }; int GetTerminationTimeout () const { return m_TerminationTimeout; };
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; }; void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
bool IsTerminationTimeoutExpired (uint64_t ts) const bool IsTerminationTimeoutExpired (uint64_t ts) const
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); }; { return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0; virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
protected: protected:
std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity; std::shared_ptr<const i2p::data::IdentityEx> m_RemoteIdentity;
std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server std::shared_ptr<i2p::crypto::DHKeys> m_DHKeysPair; // X - for client and Y - for server
size_t m_NumSentBytes, m_NumReceivedBytes; size_t m_NumSentBytes, m_NumReceivedBytes;
bool m_IsOutgoing; bool m_IsOutgoing;
int m_TerminationTimeout; int m_TerminationTimeout;
uint64_t m_LastActivityTimestamp; uint64_t m_LastActivityTimestamp;
}; };
} }
} }

View file

@ -119,7 +119,7 @@ namespace transport
m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys m_NTCPServer (nullptr), m_SSUServer (nullptr), m_DHKeysPairSupplier (5), // 5 pre-generated keys
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0), m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0), m_InBandwidth (0), m_OutBandwidth (0), m_TransitBandwidth(0),
m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0), m_LastInBandwidthUpdateBytes (0), m_LastOutBandwidthUpdateBytes (0),
m_LastTransitBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0) m_LastTransitBandwidthUpdateBytes (0), m_LastBandwidthUpdateTime (0)
{ {
@ -144,7 +144,7 @@ namespace transport
m_Service = new boost::asio::io_service (); m_Service = new boost::asio::io_service ();
m_Work = new boost::asio::io_service::work (*m_Service); m_Work = new boost::asio::io_service::work (*m_Service);
m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service); m_PeerCleanupTimer = new boost::asio::deadline_timer (*m_Service);
m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service); m_PeerTestTimer = new boost::asio::deadline_timer (*m_Service);
} }
i2p::config::GetOption("nat", m_IsNAT); i2p::config::GetOption("nat", m_IsNAT);
@ -623,7 +623,7 @@ namespace transport
void Transports::DetectExternalIP () void Transports::DetectExternalIP ()
{ {
if (RoutesRestricted()) if (RoutesRestricted())
{ {
LogPrint(eLogInfo, "Transports: restricted routes enabled, not detecting ip"); LogPrint(eLogInfo, "Transports: restricted routes enabled, not detecting ip");
i2p::context.SetStatus (eRouterStatusOK); i2p::context.SetStatus (eRouterStatusOK);
return; return;

View file

@ -136,10 +136,10 @@ namespace transport
void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident); void NTCPResolve (const std::string& addr, const i2p::data::IdentHash& ident);
void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, void HandleNTCPResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver); i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident); void SSUResolve (const std::string& addr, const i2p::data::IdentHash& ident);
void HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it, void HandleSSUResolve (const boost::system::error_code& ecode, boost::asio::ip::tcp::resolver::iterator it,
i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver); i2p::data::IdentHash ident, std::shared_ptr<boost::asio::ip::tcp::resolver> resolver);
void UpdateBandwidth (); void UpdateBandwidth ();
void DetectExternalIP (); void DetectExternalIP ();

View file

@ -2,7 +2,7 @@
#include "I2PEndian.h" #include "I2PEndian.h"
#include <thread> #include <thread>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include "Crypto.h" #include "Crypto.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "Log.h" #include "Log.h"
@ -20,8 +20,8 @@
namespace i2p namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config): Tunnel::Tunnel (std::shared_ptr<const TunnelConfig> config):
TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()), TunnelBase (config->GetTunnelID (), config->GetNextTunnelID (), config->GetNextIdentHash ()),
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false), m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false),
m_Latency (0) m_Latency (0)
@ -38,7 +38,7 @@ namespace tunnel
std::string peers = i2p::context.GetIdentity()->GetIdentHash().ToBase64(); std::string peers = i2p::context.GetIdentity()->GetIdentHash().ToBase64();
#endif #endif
auto numHops = m_Config->GetNumHops (); auto numHops = m_Config->GetNumHops ();
int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops; int numRecords = numHops <= STANDARD_NUM_RECORDS ? STANDARD_NUM_RECORDS : numHops;
auto msg = NewI2NPShortMessage (); auto msg = NewI2NPShortMessage ();
*msg->GetPayload () = numRecords; *msg->GetPayload () = numRecords;
msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1; msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1;
@ -48,20 +48,20 @@ namespace tunnel
std::random_shuffle (recordIndicies.begin(), recordIndicies.end()); std::random_shuffle (recordIndicies.begin(), recordIndicies.end());
// create real records // create real records
uint8_t * records = msg->GetPayload () + 1; uint8_t * records = msg->GetPayload () + 1;
TunnelHopConfig * hop = m_Config->GetFirstHop (); TunnelHopConfig * hop = m_Config->GetFirstHop ();
int i = 0; int i = 0;
BN_CTX * ctx = BN_CTX_new (); BN_CTX * ctx = BN_CTX_new ();
while (hop) while (hop)
{ {
uint32_t msgID; uint32_t msgID;
if (hop->next) // we set replyMsgID for last hop only if (hop->next) // we set replyMsgID for last hop only
RAND_bytes ((uint8_t *)&msgID, 4); RAND_bytes ((uint8_t *)&msgID, 4);
else else
msgID = replyMsgID; msgID = replyMsgID;
int idx = recordIndicies[i]; int idx = recordIndicies[i];
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID, ctx); hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID, ctx);
hop->recordIndex = idx; hop->recordIndex = idx;
i++; i++;
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
peers += ":" + hop->ident->GetIdentHash().ToBase64(); peers += ":" + hop->ident->GetIdentHash().ToBase64();
@ -76,7 +76,7 @@ namespace tunnel
for (int i = numHops; i < numRecords; i++) for (int i = numHops; i < numRecords; i++)
{ {
int idx = recordIndicies[i]; int idx = recordIndicies[i];
RAND_bytes (records + idx*TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE); RAND_bytes (records + idx*TUNNEL_BUILD_RECORD_SIZE, TUNNEL_BUILD_RECORD_SIZE);
} }
// decrypt real records // decrypt real records
@ -110,7 +110,7 @@ namespace tunnel
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records."); LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records.");
i2p::crypto::CBCDecryption decryption; i2p::crypto::CBCDecryption decryption;
TunnelHopConfig * hop = m_Config->GetLastHop (); TunnelHopConfig * hop = m_Config->GetLastHop ();
while (hop) while (hop)
{ {
decryption.SetKey (hop->replyKey); decryption.SetKey (hop->replyKey);
@ -142,12 +142,12 @@ namespace tunnel
auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ()); auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ());
if (profile) if (profile)
profile->TunnelBuildResponse (ret); profile->TunnelBuildResponse (ret);
if (ret) if (ret)
// if any of participants declined the tunnel is not established // if any of participants declined the tunnel is not established
established = false; established = false;
hop = hop->next; hop = hop->next;
} }
if (established) if (established)
{ {
// create tunnel decryptions from layer and iv keys in reverse order // create tunnel decryptions from layer and iv keys in reverse order
hop = m_Config->GetLastHop (); hop = m_Config->GetLastHop ();
@ -170,7 +170,7 @@ namespace tunnel
auto latency = GetMeanLatency(); auto latency = GetMeanLatency();
return latency >= lower && latency <= upper; return latency >= lower && latency <= upper;
} }
void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out) void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
{ {
const uint8_t * inPayload = in->GetPayload () + 4; const uint8_t * inPayload = in->GetPayload () + 4;
@ -178,7 +178,7 @@ namespace tunnel
for (auto& it: m_Hops) for (auto& it: m_Hops)
{ {
it->decryption.Decrypt (inPayload, outPayload); it->decryption.Decrypt (inPayload, outPayload);
inPayload = outPayload; inPayload = outPayload;
} }
} }
@ -210,11 +210,11 @@ namespace tunnel
EmitTunnelEvent("tunnel.state", this, state); EmitTunnelEvent("tunnel.state", this, state);
#endif #endif
} }
void Tunnel::PrintHops (std::stringstream& s) const void Tunnel::PrintHops (std::stringstream& s) const
{ {
// hops are in inverted order, we must print in direct order // hops are in inverted order, we must print in direct order
for (auto it = m_Hops.rbegin (); it != m_Hops.rend (); it++) for (auto it = m_Hops.rbegin (); it != m_Hops.rend (); it++)
{ {
s << " &#8658; "; s << " &#8658; ";
@ -354,7 +354,7 @@ namespace tunnel
{ {
return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels); return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels);
} }
std::shared_ptr<OutboundTunnel> Tunnels::GetPendingOutboundTunnel (uint32_t replyMsgID) std::shared_ptr<OutboundTunnel> Tunnels::GetPendingOutboundTunnel (uint32_t replyMsgID)
{ {
return GetPendingTunnel (replyMsgID, m_PendingOutboundTunnels); return GetPendingTunnel (replyMsgID, m_PendingOutboundTunnels);
@ -374,7 +374,7 @@ namespace tunnel
std::shared_ptr<InboundTunnel> Tunnels::GetNextInboundTunnel () std::shared_ptr<InboundTunnel> Tunnels::GetNextInboundTunnel ()
{ {
std::shared_ptr<InboundTunnel> tunnel; std::shared_ptr<InboundTunnel> tunnel;
size_t minReceived = 0; size_t minReceived = 0;
for (const auto& it : m_InboundTunnels) for (const auto& it : m_InboundTunnels)
{ {
@ -405,7 +405,7 @@ namespace tunnel
return tunnel; return tunnel;
} }
std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops, std::shared_ptr<TunnelPool> Tunnels::CreateTunnelPool (int numInboundHops,
int numOutboundHops, int numInboundTunnels, int numOutboundTunnels) int numOutboundHops, int numInboundTunnels, int numOutboundTunnels)
{ {
auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels); auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
@ -434,7 +434,7 @@ namespace tunnel
pool->DetachTunnels (); pool->DetachTunnels ();
} }
} }
void Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel) void Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
{ {
if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second) if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second)
@ -455,7 +455,7 @@ namespace tunnel
m_Queue.WakeUp (); m_Queue.WakeUp ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = 0; m_Thread = 0;
} }
@ -484,11 +484,11 @@ namespace tunnel
case eI2NPTunnelData: case eI2NPTunnelData:
case eI2NPTunnelGateway: case eI2NPTunnelGateway:
{ {
tunnelID = bufbe32toh (msg->GetPayload ()); tunnelID = bufbe32toh (msg->GetPayload ());
if (tunnelID == prevTunnelID) if (tunnelID == prevTunnelID)
tunnel = prevTunnel; tunnel = prevTunnel;
else if (prevTunnel) else if (prevTunnel)
prevTunnel->FlushTunnelDataMsgs (); prevTunnel->FlushTunnelDataMsgs ();
if (!tunnel) if (!tunnel)
tunnel = GetTunnel (tunnelID); tunnel = GetTunnel (tunnelID);
@ -561,9 +561,9 @@ namespace tunnel
LogPrint (eLogDebug, "Tunnel: gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID); LogPrint (eLogDebug, "Tunnel: gateway of ", (int) len, " bytes for tunnel ", tunnel->GetTunnelID (), ", msg type ", (int)typeID);
if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply) if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply)
// transit DatabaseStore my contain new/updated RI // transit DatabaseStore my contain new/updated RI
// or DatabaseSearchReply with new routers // or DatabaseSearchReply with new routers
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg)); i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg));
tunnel->SendTunnelDataMsg (msg); tunnel->SendTunnelDataMsg (msg);
} }
@ -593,7 +593,7 @@ namespace tunnel
auto pool = tunnel->GetTunnelPool(); auto pool = tunnel->GetTunnelPool();
switch (tunnel->GetState ()) switch (tunnel->GetState ())
{ {
case eTunnelStatePending: case eTunnelStatePending:
if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT) if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT)
{ {
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " timeout, deleted"); LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " timeout, deleted");
@ -632,7 +632,7 @@ namespace tunnel
#endif #endif
// for i2lua // for i2lua
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultRejected); if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultRejected);
it = pendingTunnels.erase (it); it = pendingTunnels.erase (it);
m_NumFailedTunnelCreations++; m_NumFailedTunnelCreations++;
break; break;
@ -664,7 +664,7 @@ namespace tunnel
// we don't have outbound tunnels in m_Tunnels // we don't have outbound tunnels in m_Tunnels
it = m_OutboundTunnels.erase (it); it = m_OutboundTunnels.erase (it);
} }
else else
{ {
if (tunnel->IsEstablished ()) if (tunnel->IsEstablished ())
{ {
@ -683,7 +683,7 @@ namespace tunnel
} }
} }
if (m_OutboundTunnels.size () < 3) if (m_OutboundTunnels.size () < 3)
{ {
// trying to create one more oubound tunnel // trying to create one more oubound tunnel
auto inboundTunnel = GetNextInboundTunnel (); auto inboundTunnel = GetNextInboundTunnel ();
@ -715,7 +715,7 @@ namespace tunnel
m_Tunnels.erase (tunnel->GetTunnelID ()); m_Tunnels.erase (tunnel->GetTunnelID ());
it = m_InboundTunnels.erase (it); it = m_InboundTunnels.erase (it);
} }
else else
{ {
if (tunnel->IsEstablished ()) if (tunnel->IsEstablished ())
{ {
@ -748,13 +748,13 @@ namespace tunnel
int obLen; i2p::config::GetOption("exploratory.outbound.length", obLen); int obLen; i2p::config::GetOption("exploratory.outbound.length", obLen);
int ibNum; i2p::config::GetOption("exploratory.inbound.quantity", ibNum); int ibNum; i2p::config::GetOption("exploratory.inbound.quantity", ibNum);
int obNum; i2p::config::GetOption("exploratory.outbound.quantity", obNum); int obNum; i2p::config::GetOption("exploratory.outbound.quantity", obNum);
m_ExploratoryPool = CreateTunnelPool (ibLen, obLen, ibNum, obNum); m_ExploratoryPool = CreateTunnelPool (ibLen, obLen, ibNum, obNum);
m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ()); m_ExploratoryPool->SetLocalDestination (i2p::context.GetSharedDestination ());
} }
return; return;
} }
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3) if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3)
{ {
// trying to create one more inbound tunnel // trying to create one more inbound tunnel
auto router = i2p::transport::transports.RoutesRestricted() ? auto router = i2p::transport::transports.RoutesRestricted() ?
@ -783,7 +783,7 @@ namespace tunnel
m_Tunnels.erase (tunnel->GetTunnelID ()); m_Tunnels.erase (tunnel->GetTunnelID ());
it = m_TransitTunnels.erase (it); it = m_TransitTunnels.erase (it);
} }
else else
{ {
tunnel->Cleanup (); tunnel->Cleanup ();
it++; it++;
@ -820,14 +820,14 @@ namespace tunnel
auto newTunnel = std::make_shared<TTunnel> (config); auto newTunnel = std::make_shared<TTunnel> (config);
uint32_t replyMsgID; uint32_t replyMsgID;
RAND_bytes ((uint8_t *)&replyMsgID, 4); RAND_bytes ((uint8_t *)&replyMsgID, 4);
AddPendingTunnel (replyMsgID, newTunnel); AddPendingTunnel (replyMsgID, newTunnel);
newTunnel->Build (replyMsgID, outboundTunnel); newTunnel->Build (replyMsgID, outboundTunnel);
return newTunnel; return newTunnel;
} }
std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel) std::shared_ptr<InboundTunnel> Tunnels::CreateInboundTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel)
{ {
if (config) if (config)
return CreateTunnel<InboundTunnel>(config, outboundTunnel); return CreateTunnel<InboundTunnel>(config, outboundTunnel);
else else
return CreateZeroHopsInboundTunnel (); return CreateZeroHopsInboundTunnel ();
@ -843,12 +843,12 @@ namespace tunnel
void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel) void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel)
{ {
m_PendingInboundTunnels[replyMsgID] = tunnel; m_PendingInboundTunnels[replyMsgID] = tunnel;
} }
void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel) void Tunnels::AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel)
{ {
m_PendingOutboundTunnels[replyMsgID] = tunnel; m_PendingOutboundTunnels[replyMsgID] = tunnel;
} }
void Tunnels::AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel) void Tunnels::AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel)
@ -872,7 +872,7 @@ namespace tunnel
{ {
// build symmetric outbound tunnel // build symmetric outbound tunnel
CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (), CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (),
newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()), newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()),
GetNextOutboundTunnel ()); GetNextOutboundTunnel ());
} }
else else

View file

@ -36,7 +36,7 @@ namespace tunnel
(void) t; (void) t;
#endif #endif
} }
template<typename TunnelT, typename T> template<typename TunnelT, typename T>
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const T & val) static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const T & val)
{ {
@ -46,7 +46,7 @@ namespace tunnel
(void) ev; (void) ev;
(void) t; (void) t;
(void) val; (void) val;
#endif #endif
} }
template<typename TunnelT> template<typename TunnelT>
@ -58,13 +58,13 @@ namespace tunnel
(void) ev; (void) ev;
(void) t; (void) t;
(void) val; (void) val;
#endif #endif
} }
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds
const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message
@ -77,8 +77,8 @@ namespace tunnel
eTunnelStateTestFailed, eTunnelStateTestFailed,
eTunnelStateFailed, eTunnelStateFailed,
eTunnelStateExpiring eTunnelStateExpiring
}; };
class OutboundTunnel; class OutboundTunnel;
class InboundTunnel; class InboundTunnel;
class Tunnel: public TunnelBase class Tunnel: public TunnelBase
@ -87,18 +87,18 @@ namespace tunnel
{ {
std::shared_ptr<const i2p::data::IdentityEx> ident; std::shared_ptr<const i2p::data::IdentityEx> ident;
i2p::crypto::TunnelDecryption decryption; i2p::crypto::TunnelDecryption decryption;
}; };
public: public:
Tunnel (std::shared_ptr<const TunnelConfig> config); Tunnel (std::shared_ptr<const TunnelConfig> config);
~Tunnel (); ~Tunnel ();
void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr); void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; } std::shared_ptr<const TunnelConfig> GetTunnelConfig () const { return m_Config; }
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const;
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const;
TunnelState GetState () const { return m_State; }; TunnelState GetState () const { return m_State; };
void SetState (TunnelState state); void SetState (TunnelState state);
bool IsEstablished () const { return m_State == eTunnelStateEstablished; }; bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
@ -106,17 +106,17 @@ namespace tunnel
bool IsRecreated () const { return m_IsRecreated; }; bool IsRecreated () const { return m_IsRecreated; };
void SetIsRecreated () { m_IsRecreated = true; }; void SetIsRecreated () { m_IsRecreated = true; };
virtual bool IsInbound() const = 0; virtual bool IsInbound() const = 0;
std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; }; std::shared_ptr<TunnelPool> GetTunnelPool () const { return m_Pool; };
void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; }; void SetTunnelPool (std::shared_ptr<TunnelPool> pool) { m_Pool = pool; };
bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); bool HandleTunnelBuildResponse (uint8_t * msg, size_t len);
virtual void Print (std::stringstream&) const {}; virtual void Print (std::stringstream&) const {};
// implements TunnelBase // implements TunnelBase
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out); void EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out);
/** @brief add latency sample */ /** @brief add latency sample */
void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; } void AddLatencySample(const uint64_t ms) { m_Latency = (m_Latency + ms) >> 1; }
@ -124,12 +124,12 @@ namespace tunnel
uint64_t GetMeanLatency() const { return m_Latency; } uint64_t GetMeanLatency() const { return m_Latency; }
/** @brief return true if this tunnel's latency fits in range [lowerbound, upperbound] */ /** @brief return true if this tunnel's latency fits in range [lowerbound, upperbound] */
bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const; bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
bool LatencyIsKnown() const { return m_Latency > 0; } bool LatencyIsKnown() const { return m_Latency > 0; }
protected: protected:
void PrintHops (std::stringstream& s) const; void PrintHops (std::stringstream& s) const;
private: private:
std::shared_ptr<const TunnelConfig> m_Config; std::shared_ptr<const TunnelConfig> m_Config;
@ -138,30 +138,30 @@ namespace tunnel
TunnelState m_State; TunnelState m_State;
bool m_IsRecreated; bool m_IsRecreated;
uint64_t m_Latency; // in milliseconds uint64_t m_Latency; // in milliseconds
}; };
class OutboundTunnel: public Tunnel class OutboundTunnel: public Tunnel
{ {
public: public:
OutboundTunnel (std::shared_ptr<const TunnelConfig> config): OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {}; Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, std::shared_ptr<i2p::I2NPMessage> msg);
virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages virtual void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); // multiple messages
const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; }; const i2p::data::IdentHash& GetEndpointIdentHash () const { return m_EndpointIdentHash; };
virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; virtual size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); };
void Print (std::stringstream& s) const; void Print (std::stringstream& s) const;
// implements TunnelBase // implements TunnelBase
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg); void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
bool IsInbound() const { return false; } bool IsInbound() const { return false; }
private: private:
std::mutex m_SendMutex; std::mutex m_SendMutex;
TunnelGateway m_Gateway; TunnelGateway m_Gateway;
i2p::data::IdentHash m_EndpointIdentHash; i2p::data::IdentHash m_EndpointIdentHash;
}; };
@ -176,27 +176,27 @@ namespace tunnel
bool IsInbound() const { return true; } bool IsInbound() const { return true; }
// override TunnelBase // override TunnelBase
void Cleanup () { m_Endpoint.Cleanup (); }; void Cleanup () { m_Endpoint.Cleanup (); };
private: private:
TunnelEndpoint m_Endpoint; TunnelEndpoint m_Endpoint;
}; };
class ZeroHopsInboundTunnel: public InboundTunnel class ZeroHopsInboundTunnel: public InboundTunnel
{ {
public: public:
ZeroHopsInboundTunnel (); ZeroHopsInboundTunnel ();
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg); void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
void Print (std::stringstream& s) const; void Print (std::stringstream& s) const;
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
private: private:
size_t m_NumReceivedBytes; size_t m_NumReceivedBytes;
}; };
class ZeroHopsOutboundTunnel: public OutboundTunnel class ZeroHopsOutboundTunnel: public OutboundTunnel
{ {
public: public:
@ -205,23 +205,23 @@ namespace tunnel
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs); void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs);
void Print (std::stringstream& s) const; void Print (std::stringstream& s) const;
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };
private: private:
size_t m_NumSentBytes; size_t m_NumSentBytes;
}; };
class Tunnels class Tunnels
{ {
public: public:
Tunnels (); Tunnels ();
~Tunnels (); ~Tunnels ();
void Start (); void Start ();
void Stop (); void Stop ();
std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID); std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID);
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID); std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
std::shared_ptr<InboundTunnel> GetNextInboundTunnel (); std::shared_ptr<InboundTunnel> GetNextInboundTunnel ();
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel (); std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; }; std::shared_ptr<TunnelPool> GetExploratoryPool () const { return m_ExploratoryPool; };
@ -236,22 +236,22 @@ namespace tunnel
void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs); void PostTunnelData (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> tunnel);
void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel); void AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> tunnel);
std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops, std::shared_ptr<TunnelPool> CreateTunnelPool (int numInboundHops,
int numOuboundHops, int numInboundTunnels, int numOutboundTunnels); int numOuboundHops, int numInboundTunnels, int numOutboundTunnels);
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool); void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
void StopTunnelPool (std::shared_ptr<TunnelPool> pool); void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
private: private:
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr); std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
template<class TTunnel> template<class TTunnel>
std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels); std::shared_ptr<TTunnel> GetPendingTunnel (uint32_t replyMsgID, const std::map<uint32_t, std::shared_ptr<TTunnel> >& pendingTunnels);
void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg); void HandleTunnelGatewayMsg (std::shared_ptr<TunnelBase> tunnel, std::shared_ptr<I2NPMessage> msg);
void Run (); void Run ();
void ManageTunnels (); void ManageTunnels ();
void ManageOutboundTunnels (); void ManageOutboundTunnels ();
void ManageInboundTunnels (); void ManageInboundTunnels ();
@ -260,14 +260,14 @@ namespace tunnel
template<class PendingTunnels> template<class PendingTunnels>
void ManagePendingTunnels (PendingTunnels& pendingTunnels); void ManagePendingTunnels (PendingTunnels& pendingTunnels);
void ManageTunnelPools (); void ManageTunnelPools ();
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel (); std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel ();
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel (); std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel ();
private: private:
bool m_IsRunning; bool m_IsRunning;
std::thread * m_Thread; std::thread * m_Thread;
std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID std::map<uint32_t, std::shared_ptr<InboundTunnel> > m_PendingInboundTunnels; // by replyMsgID
std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID std::map<uint32_t, std::shared_ptr<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels; std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels;
@ -292,17 +292,17 @@ namespace tunnel
size_t CountTransitTunnels() const; size_t CountTransitTunnels() const;
size_t CountInboundTunnels() const; size_t CountInboundTunnels() const;
size_t CountOutboundTunnels() const; size_t CountOutboundTunnels() const;
int GetQueueSize () { return m_Queue.GetSize (); }; int GetQueueSize () { return m_Queue.GetSize (); };
int GetTunnelCreationSuccessRate () const // in percents int GetTunnelCreationSuccessRate () const // in percents
{ {
int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations; int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations;
return totalNum ? m_NumSuccesiveTunnelCreations*100/totalNum : 0; return totalNum ? m_NumSuccesiveTunnelCreations*100/totalNum : 0;
} }
}; };
extern Tunnels tunnels; extern Tunnels tunnels;
} }
} }
#endif #endif

View file

@ -14,17 +14,17 @@ namespace tunnel
const size_t TUNNEL_DATA_MSG_SIZE = 1028; const size_t TUNNEL_DATA_MSG_SIZE = 1028;
const size_t TUNNEL_DATA_ENCRYPTED_SIZE = 1008; const size_t TUNNEL_DATA_ENCRYPTED_SIZE = 1008;
const size_t TUNNEL_DATA_MAX_PAYLOAD_SIZE = 1003; const size_t TUNNEL_DATA_MAX_PAYLOAD_SIZE = 1003;
enum TunnelDeliveryType enum TunnelDeliveryType
{ {
eDeliveryTypeLocal = 0, eDeliveryTypeLocal = 0,
eDeliveryTypeTunnel = 1, eDeliveryTypeTunnel = 1,
eDeliveryTypeRouter = 2 eDeliveryTypeRouter = 2
}; };
struct TunnelMessageBlock struct TunnelMessageBlock
{ {
TunnelDeliveryType deliveryType; TunnelDeliveryType deliveryType;
i2p::data::IdentHash hash; i2p::data::IdentHash hash;
uint32_t tunnelID; uint32_t tunnelID;
std::shared_ptr<I2NPMessage> data; std::shared_ptr<I2NPMessage> data;
}; };
@ -33,12 +33,12 @@ namespace tunnel
{ {
public: public:
TunnelBase (uint32_t tunnelID, uint32_t nextTunnelID, i2p::data::IdentHash nextIdent): TunnelBase (uint32_t tunnelID, uint32_t nextTunnelID, i2p::data::IdentHash nextIdent):
m_TunnelID (tunnelID), m_NextTunnelID (nextTunnelID), m_NextIdent (nextIdent), m_TunnelID (tunnelID), m_NextTunnelID (nextTunnelID), m_NextIdent (nextIdent),
m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {}; m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {};
virtual ~TunnelBase () {}; virtual ~TunnelBase () {};
virtual void Cleanup () {}; virtual void Cleanup () {};
virtual void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) = 0; virtual void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) = 0;
virtual void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) = 0; virtual void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) = 0;
virtual void FlushTunnelDataMsgs () {}; virtual void FlushTunnelDataMsgs () {};
@ -49,24 +49,24 @@ namespace tunnel
uint32_t GetCreationTime () const { return m_CreationTime; }; uint32_t GetCreationTime () const { return m_CreationTime; };
void SetCreationTime (uint32_t t) { m_CreationTime = t; }; void SetCreationTime (uint32_t t) { m_CreationTime = t; };
private: private:
uint32_t m_TunnelID, m_NextTunnelID; uint32_t m_TunnelID, m_NextTunnelID;
i2p::data::IdentHash m_NextIdent; i2p::data::IdentHash m_NextIdent;
uint32_t m_CreationTime; // seconds since epoch uint32_t m_CreationTime; // seconds since epoch
}; };
struct TunnelCreationTimeCmp struct TunnelCreationTimeCmp
{ {
bool operator() (std::shared_ptr<const TunnelBase> t1, std::shared_ptr<const TunnelBase> t2) const bool operator() (std::shared_ptr<const TunnelBase> t1, std::shared_ptr<const TunnelBase> t2) const
{ {
if (t1->GetCreationTime () != t2->GetCreationTime ()) if (t1->GetCreationTime () != t2->GetCreationTime ())
return t1->GetCreationTime () > t2->GetCreationTime (); return t1->GetCreationTime () > t2->GetCreationTime ();
else else
return t1 < t2; return t1 < t2;
}; };
}; };
} }
} }

View file

@ -23,11 +23,11 @@ namespace tunnel
uint8_t ivKey[32]; uint8_t ivKey[32];
uint8_t replyKey[32]; uint8_t replyKey[32];
uint8_t replyIV[16]; uint8_t replyIV[16];
bool isGateway, isEndpoint; bool isGateway, isEndpoint;
TunnelHopConfig * next, * prev; TunnelHopConfig * next, * prev;
int recordIndex; // record # in tunnel build message int recordIndex; // record # in tunnel build message
TunnelHopConfig (std::shared_ptr<const i2p::data::IdentityEx> r) TunnelHopConfig (std::shared_ptr<const i2p::data::IdentityEx> r)
{ {
RAND_bytes (layerKey, 32); RAND_bytes (layerKey, 32);
@ -37,20 +37,20 @@ namespace tunnel
RAND_bytes ((uint8_t *)&tunnelID, 4); RAND_bytes ((uint8_t *)&tunnelID, 4);
isGateway = true; isGateway = true;
isEndpoint = true; isEndpoint = true;
ident = r; ident = r;
//nextRouter = nullptr; //nextRouter = nullptr;
nextTunnelID = 0; nextTunnelID = 0;
next = nullptr; next = nullptr;
prev = nullptr; prev = nullptr;
} }
void SetNextIdent (const i2p::data::IdentHash& ident) void SetNextIdent (const i2p::data::IdentHash& ident)
{ {
nextIdent = ident; nextIdent = ident;
isEndpoint = false; isEndpoint = false;
RAND_bytes ((uint8_t *)&nextTunnelID, 4); RAND_bytes ((uint8_t *)&nextTunnelID, 4);
} }
void SetReplyHop (uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent) void SetReplyHop (uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent)
{ {
@ -58,35 +58,35 @@ namespace tunnel
nextTunnelID = replyTunnelID; nextTunnelID = replyTunnelID;
isEndpoint = true; isEndpoint = true;
} }
void SetNext (TunnelHopConfig * n) void SetNext (TunnelHopConfig * n)
{ {
next = n; next = n;
if (next) if (next)
{ {
next->prev = this; next->prev = this;
next->isGateway = false; next->isGateway = false;
isEndpoint = false; isEndpoint = false;
nextIdent = next->ident->GetIdentHash (); nextIdent = next->ident->GetIdentHash ();
nextTunnelID = next->tunnelID; nextTunnelID = next->tunnelID;
} }
} }
void SetPrev (TunnelHopConfig * p) void SetPrev (TunnelHopConfig * p)
{ {
prev = p; prev = p;
if (prev) if (prev)
{ {
prev->next = this; prev->next = this;
prev->isEndpoint = false; prev->isEndpoint = false;
isGateway = false; isGateway = false;
} }
} }
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) const void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) const
{ {
uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE];
htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID); htobe32buf (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET, tunnelID);
memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, ident->GetIdentHash (), 32); memcpy (clearText + BUILD_REQUEST_RECORD_OUR_IDENT_OFFSET, ident->GetIdentHash (), 32);
htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID); htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextIdent, 32); memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextIdent, 32);
@ -98,44 +98,44 @@ namespace tunnel
if (isGateway) flag |= 0x80; if (isGateway) flag |= 0x80;
if (isEndpoint) flag |= 0x40; if (isEndpoint) flag |= 0x40;
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag; clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ()); htobe32buf (clearText + BUILD_REQUEST_RECORD_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID); htobe32buf (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET, replyMsgID);
RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET); RAND_bytes (clearText + BUILD_REQUEST_RECORD_PADDING_OFFSET, BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE - BUILD_REQUEST_RECORD_PADDING_OFFSET);
i2p::crypto::ElGamalEncrypt (ident->GetEncryptionPublicKey (), clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx); i2p::crypto::ElGamalEncrypt (ident->GetEncryptionPublicKey (), clearText, record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, ctx);
memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16); memcpy (record + BUILD_REQUEST_RECORD_TO_PEER_OFFSET, (const uint8_t *)ident->GetIdentHash (), 16);
} }
}; };
class TunnelConfig class TunnelConfig
{ {
public: public:
TunnelConfig (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers) // inbound TunnelConfig (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers) // inbound
{ {
CreatePeers (peers); CreatePeers (peers);
m_LastHop->SetNextIdent (i2p::context.GetIdentHash ()); m_LastHop->SetNextIdent (i2p::context.GetIdentHash ());
} }
TunnelConfig (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers, TunnelConfig (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers,
uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent) // outbound uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent) // outbound
{ {
CreatePeers (peers); CreatePeers (peers);
m_FirstHop->isGateway = false; m_FirstHop->isGateway = false;
m_LastHop->SetReplyHop (replyTunnelID, replyIdent); m_LastHop->SetReplyHop (replyTunnelID, replyIdent);
} }
~TunnelConfig () ~TunnelConfig ()
{ {
TunnelHopConfig * hop = m_FirstHop; TunnelHopConfig * hop = m_FirstHop;
while (hop) while (hop)
{ {
auto tmp = hop; auto tmp = hop;
hop = hop->next; hop = hop->next;
delete tmp; delete tmp;
} }
} }
TunnelHopConfig * GetFirstHop () const TunnelHopConfig * GetFirstHop () const
{ {
return m_FirstHop; return m_FirstHop;
@ -149,63 +149,63 @@ namespace tunnel
int GetNumHops () const int GetNumHops () const
{ {
int num = 0; int num = 0;
TunnelHopConfig * hop = m_FirstHop; TunnelHopConfig * hop = m_FirstHop;
while (hop) while (hop)
{ {
num++; num++;
hop = hop->next; hop = hop->next;
} }
return num; return num;
} }
bool IsEmpty () const bool IsEmpty () const
{ {
return !m_FirstHop; return !m_FirstHop;
} }
virtual bool IsInbound () const { return m_FirstHop->isGateway; } virtual bool IsInbound () const { return m_FirstHop->isGateway; }
virtual uint32_t GetTunnelID () const virtual uint32_t GetTunnelID () const
{ {
if (!m_FirstHop) return 0; if (!m_FirstHop) return 0;
return IsInbound () ? m_LastHop->nextTunnelID : m_FirstHop->tunnelID; return IsInbound () ? m_LastHop->nextTunnelID : m_FirstHop->tunnelID;
} }
virtual uint32_t GetNextTunnelID () const virtual uint32_t GetNextTunnelID () const
{ {
if (!m_FirstHop) return 0; if (!m_FirstHop) return 0;
return m_FirstHop->tunnelID; return m_FirstHop->tunnelID;
} }
virtual const i2p::data::IdentHash& GetNextIdentHash () const virtual const i2p::data::IdentHash& GetNextIdentHash () const
{ {
return m_FirstHop->ident->GetIdentHash (); return m_FirstHop->ident->GetIdentHash ();
} }
virtual const i2p::data::IdentHash& GetLastIdentHash () const
{
return m_LastHop->ident->GetIdentHash ();
}
virtual const i2p::data::IdentHash& GetLastIdentHash () const
{
return m_LastHop->ident->GetIdentHash ();
}
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const
{ {
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers; std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers;
TunnelHopConfig * hop = m_FirstHop; TunnelHopConfig * hop = m_FirstHop;
while (hop) while (hop)
{ {
peers.push_back (hop->ident); peers.push_back (hop->ident);
hop = hop->next; hop = hop->next;
} }
return peers; return peers;
} }
protected: protected:
// this constructor can't be called from outside // this constructor can't be called from outside
TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr) TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr)
{ {
} }
private: private:
template<class Peers> template<class Peers>
@ -217,13 +217,13 @@ namespace tunnel
auto hop = new TunnelHopConfig (it); auto hop = new TunnelHopConfig (it);
if (prev) if (prev)
prev->SetNext (hop); prev->SetNext (hop);
else else
m_FirstHop = hop; m_FirstHop = hop;
prev = hop; prev = hop;
} }
m_LastHop = prev; m_LastHop = prev;
} }
private: private:
TunnelHopConfig * m_FirstHop, * m_LastHop; TunnelHopConfig * m_FirstHop, * m_LastHop;
@ -235,7 +235,7 @@ namespace tunnel
ZeroHopsTunnelConfig () { RAND_bytes ((uint8_t *)&m_TunnelID, 4);}; ZeroHopsTunnelConfig () { RAND_bytes ((uint8_t *)&m_TunnelID, 4);};
bool IsInbound () const { return true; }; // TODO: bool IsInbound () const { return true; }; // TODO:
uint32_t GetTunnelID () const { return m_TunnelID; }; uint32_t GetTunnelID () const { return m_TunnelID; };
uint32_t GetNextTunnelID () const { return m_TunnelID; }; uint32_t GetNextTunnelID () const { return m_TunnelID; };
const i2p::data::IdentHash& GetNextIdentHash () const { return i2p::context.GetIdentHash (); }; const i2p::data::IdentHash& GetNextIdentHash () const { return i2p::context.GetIdentHash (); };
@ -243,10 +243,10 @@ namespace tunnel
private: private:
uint32_t m_TunnelID; uint32_t m_TunnelID;
}; };
} }
} }
#endif #endif

View file

@ -15,16 +15,16 @@ namespace tunnel
{ {
TunnelEndpoint::~TunnelEndpoint () TunnelEndpoint::~TunnelEndpoint ()
{ {
} }
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg) void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg)
{ {
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE; m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
uint8_t * decrypted = msg->GetPayload () + 20; // 4 + 16 uint8_t * decrypted = msg->GetPayload () + 20; // 4 + 16
uint8_t * zero = (uint8_t *)memchr (decrypted + 4, 0, TUNNEL_DATA_ENCRYPTED_SIZE - 4); // witout 4-byte checksum uint8_t * zero = (uint8_t *)memchr (decrypted + 4, 0, TUNNEL_DATA_ENCRYPTED_SIZE - 4); // witout 4-byte checksum
if (zero) if (zero)
{ {
uint8_t * fragment = zero + 1; uint8_t * fragment = zero + 1;
// verify checksum // verify checksum
memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end memcpy (msg->GetPayload () + TUNNEL_DATA_MSG_SIZE, msg->GetPayload () + 4, 16); // copy iv to the end
@ -34,58 +34,58 @@ namespace tunnel
{ {
LogPrint (eLogError, "TunnelMessage: checksum verification failed"); LogPrint (eLogError, "TunnelMessage: checksum verification failed");
return; return;
} }
// process fragments // process fragments
while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE) while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
{ {
uint8_t flag = fragment[0]; uint8_t flag = fragment[0];
fragment++; fragment++;
bool isFollowOnFragment = flag & 0x80, isLastFragment = true; bool isFollowOnFragment = flag & 0x80, isLastFragment = true;
uint32_t msgID = 0; uint32_t msgID = 0;
int fragmentNum = 0; int fragmentNum = 0;
TunnelMessageBlockEx m; TunnelMessageBlockEx m;
if (!isFollowOnFragment) if (!isFollowOnFragment)
{ {
// first fragment // first fragment
m.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03); m.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03);
switch (m.deliveryType) switch (m.deliveryType)
{ {
case eDeliveryTypeLocal: // 0 case eDeliveryTypeLocal: // 0
break; break;
case eDeliveryTypeTunnel: // 1 case eDeliveryTypeTunnel: // 1
m.tunnelID = bufbe32toh (fragment); m.tunnelID = bufbe32toh (fragment);
fragment += 4; // tunnelID fragment += 4; // tunnelID
m.hash = i2p::data::IdentHash (fragment); m.hash = i2p::data::IdentHash (fragment);
fragment += 32; // hash fragment += 32; // hash
break; break;
case eDeliveryTypeRouter: // 2 case eDeliveryTypeRouter: // 2
m.hash = i2p::data::IdentHash (fragment); m.hash = i2p::data::IdentHash (fragment);
fragment += 32; // to hash fragment += 32; // to hash
break; break;
default: default:
; ;
} }
bool isFragmented = flag & 0x08; bool isFragmented = flag & 0x08;
if (isFragmented) if (isFragmented)
{ {
// Message ID // Message ID
msgID = bufbe32toh (fragment); msgID = bufbe32toh (fragment);
fragment += 4; fragment += 4;
isLastFragment = false; isLastFragment = false;
} }
} }
else else
{ {
// follow on // follow on
msgID = bufbe32toh (fragment); // MessageID msgID = bufbe32toh (fragment); // MessageID
fragment += 4; fragment += 4;
fragmentNum = (flag >> 1) & 0x3F; // 6 bits fragmentNum = (flag >> 1) & 0x3F; // 6 bits
isLastFragment = flag & 0x01; isLastFragment = flag & 0x01;
} }
uint16_t size = bufbe16toh (fragment); uint16_t size = bufbe16toh (fragment);
fragment += 2; fragment += 2;
@ -106,7 +106,7 @@ namespace tunnel
} }
else else
m.data = msg; m.data = msg;
if (!isFollowOnFragment && isLastFragment) if (!isFollowOnFragment && isLastFragment)
HandleNextMessage (m); HandleNextMessage (m);
else else
@ -127,18 +127,18 @@ namespace tunnel
{ {
m.nextFragmentNum = fragmentNum; m.nextFragmentNum = fragmentNum;
HandleFollowOnFragment (msgID, isLastFragment, m); HandleFollowOnFragment (msgID, isLastFragment, m);
} }
} }
else else
LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented"); LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented");
} }
fragment += size; fragment += size;
} }
} }
else else
LogPrint (eLogError, "TunnelMessage: zero not found"); LogPrint (eLogError, "TunnelMessage: zero not found");
} }
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m) void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m)
{ {
@ -151,7 +151,7 @@ namespace tunnel
if (m.nextFragmentNum == msg.nextFragmentNum) if (m.nextFragmentNum == msg.nextFragmentNum)
{ {
if (msg.data->len + size < I2NP_MAX_MESSAGE_SIZE) // check if message is not too long if (msg.data->len + size < I2NP_MAX_MESSAGE_SIZE) // check if message is not too long
{ {
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
{ {
// LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough"); // LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough");
@ -164,14 +164,14 @@ namespace tunnel
if (isLastFragment) if (isLastFragment)
{ {
// message complete // message complete
HandleNextMessage (msg); HandleNextMessage (msg);
m_IncompleteMessages.erase (it); m_IncompleteMessages.erase (it);
} }
else else
{ {
msg.nextFragmentNum++; msg.nextFragmentNum++;
HandleOutOfSequenceFragments (msgID, msg); HandleOutOfSequenceFragments (msgID, msg);
} }
} }
else else
{ {
@ -180,31 +180,31 @@ namespace tunnel
} }
} }
else else
{ {
LogPrint (eLogWarning, "TunnelMessage: Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ", saved"); LogPrint (eLogWarning, "TunnelMessage: Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ", saved");
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data); AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
} }
} }
else else
{ {
LogPrint (eLogWarning, "TunnelMessage: First fragment of message ", msgID, " not found, saved"); LogPrint (eLogWarning, "TunnelMessage: First fragment of message ", msgID, " not found, saved");
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data); AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
} }
} }
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data) void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data)
{ {
if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {isLastFragment, data, i2p::util::GetMillisecondsSinceEpoch () }}).second) if (!m_OutOfSequenceFragments.insert ({{msgID, fragmentNum}, {isLastFragment, data, i2p::util::GetMillisecondsSinceEpoch () }}).second)
LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID); LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID);
} }
void TunnelEndpoint::HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg) void TunnelEndpoint::HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg)
{ {
while (ConcatNextOutOfSequenceFragment (msgID, msg)) while (ConcatNextOutOfSequenceFragment (msgID, msg))
{ {
if (!msg.nextFragmentNum) // message complete if (!msg.nextFragmentNum) // message complete
{ {
HandleNextMessage (msg); HandleNextMessage (msg);
m_IncompleteMessages.erase (msgID); m_IncompleteMessages.erase (msgID);
break; break;
} }
@ -215,7 +215,7 @@ namespace tunnel
{ {
auto it = m_OutOfSequenceFragments.find ({msgID, msg.nextFragmentNum}); auto it = m_OutOfSequenceFragments.find ({msgID, msg.nextFragmentNum});
if (it != m_OutOfSequenceFragments.end ()) if (it != m_OutOfSequenceFragments.end ())
{ {
LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found"); LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found");
size_t size = it->second.data->GetLength (); size_t size = it->second.data->GetLength ();
if (msg.data->len + size > msg.data->maxLen) if (msg.data->len + size > msg.data->maxLen)
@ -233,21 +233,21 @@ namespace tunnel
else else
msg.nextFragmentNum++; msg.nextFragmentNum++;
m_OutOfSequenceFragments.erase (it); m_OutOfSequenceFragments.erase (it);
return true; return true;
} }
return false; return false;
} }
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg) void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
{ {
if (!m_IsInbound && msg.data->IsExpired ()) if (!m_IsInbound && msg.data->IsExpired ())
{ {
LogPrint (eLogInfo, "TunnelMessage: message expired"); LogPrint (eLogInfo, "TunnelMessage: message expired");
return; return;
} }
uint8_t typeID = msg.data->GetTypeID (); uint8_t typeID = msg.data->GetTypeID ();
LogPrint (eLogDebug, "TunnelMessage: handle fragment of ", msg.data->GetLength (), " bytes, msg type ", (int)typeID); LogPrint (eLogDebug, "TunnelMessage: handle fragment of ", msg.data->GetLength (), " bytes, msg type ", (int)typeID);
// catch RI or reply with new list of routers // catch RI or reply with new list of routers
if ((IsRouterInfoMsg (msg.data) || typeID == eI2NPDatabaseSearchReply) && if ((IsRouterInfoMsg (msg.data) || typeID == eI2NPDatabaseSearchReply) &&
!m_IsInbound && msg.deliveryType != eDeliveryTypeLocal) !m_IsInbound && msg.deliveryType != eDeliveryTypeLocal)
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg.data)); i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg.data));
@ -263,15 +263,15 @@ namespace tunnel
else else
LogPrint (eLogError, "TunnelMessage: Delivery type 'tunnel' arrived from an inbound tunnel, dropped"); LogPrint (eLogError, "TunnelMessage: Delivery type 'tunnel' arrived from an inbound tunnel, dropped");
break; break;
case eDeliveryTypeRouter: case eDeliveryTypeRouter:
if (!m_IsInbound) // outbound transit tunnel if (!m_IsInbound) // outbound transit tunnel
i2p::transport::transports.SendMessage (msg.hash, msg.data); i2p::transport::transports.SendMessage (msg.hash, msg.data);
else // we shouldn't send this message. possible leakage else // we shouldn't send this message. possible leakage
LogPrint (eLogError, "TunnelMessage: Delivery type 'router' arrived from an inbound tunnel, dropped"); LogPrint (eLogError, "TunnelMessage: Delivery type 'router' arrived from an inbound tunnel, dropped");
break; break;
default: default:
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType); LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
}; };
} }
void TunnelEndpoint::Cleanup () void TunnelEndpoint::Cleanup ()
@ -293,6 +293,6 @@ namespace tunnel
else else
++it; ++it;
} }
} }
} }
} }

View file

@ -12,26 +12,26 @@ namespace i2p
namespace tunnel namespace tunnel
{ {
class TunnelEndpoint class TunnelEndpoint
{ {
struct TunnelMessageBlockEx: public TunnelMessageBlock struct TunnelMessageBlockEx: public TunnelMessageBlock
{ {
uint64_t receiveTime; // milliseconds since epoch uint64_t receiveTime; // milliseconds since epoch
uint8_t nextFragmentNum; uint8_t nextFragmentNum;
}; };
struct Fragment struct Fragment
{ {
bool isLastFragment; bool isLastFragment;
std::shared_ptr<I2NPMessage> data; std::shared_ptr<I2NPMessage> data;
uint64_t receiveTime; // milliseconds since epoch uint64_t receiveTime; // milliseconds since epoch
}; };
public: public:
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {}; TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {};
~TunnelEndpoint (); ~TunnelEndpoint ();
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; }; size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
void Cleanup (); void Cleanup ();
void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg); void HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg);
@ -42,16 +42,16 @@ namespace tunnel
void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data); void AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum, bool isLastFragment, std::shared_ptr<I2NPMessage> data);
bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added bool ConcatNextOutOfSequenceFragment (uint32_t msgID, TunnelMessageBlockEx& msg); // true if something added
void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg); void HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg);
private: private:
std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages; std::map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
std::map<std::pair<uint32_t, uint8_t>, Fragment> m_OutOfSequenceFragments; // (msgID, fragment#)->fragment std::map<std::pair<uint32_t, uint8_t>, Fragment> m_OutOfSequenceFragments; // (msgID, fragment#)->fragment
bool m_IsInbound; bool m_IsInbound;
size_t m_NumReceivedBytes; size_t m_NumReceivedBytes;
}; };
} }
} }
#endif #endif

View file

@ -10,8 +10,8 @@ namespace i2p
{ {
namespace tunnel namespace tunnel
{ {
TunnelGatewayBuffer::TunnelGatewayBuffer (): TunnelGatewayBuffer::TunnelGatewayBuffer ():
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0)
{ {
RAND_bytes (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE); RAND_bytes (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE);
for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++) for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++)
@ -21,31 +21,31 @@ namespace tunnel
TunnelGatewayBuffer::~TunnelGatewayBuffer () TunnelGatewayBuffer::~TunnelGatewayBuffer ()
{ {
ClearTunnelDataMsgs (); ClearTunnelDataMsgs ();
} }
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
{ {
bool messageCreated = false; bool messageCreated = false;
if (!m_CurrentTunnelDataMsg) if (!m_CurrentTunnelDataMsg)
{ {
CreateCurrentTunnelDataMessage (); CreateCurrentTunnelDataMessage ();
messageCreated = true; messageCreated = true;
} }
// create delivery instructions // create delivery instructions
uint8_t di[43]; // max delivery instruction length is 43 for tunnel uint8_t di[43]; // max delivery instruction length is 43 for tunnel
size_t diLen = 1;// flag size_t diLen = 1;// flag
if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router
{ {
if (block.deliveryType == eDeliveryTypeTunnel) if (block.deliveryType == eDeliveryTypeTunnel)
{ {
htobe32buf (di + diLen, block.tunnelID); htobe32buf (di + diLen, block.tunnelID);
diLen += 4; // tunnelID diLen += 4; // tunnelID
} }
memcpy (di + diLen, block.hash, 32); memcpy (di + diLen, block.hash, 32);
diLen += 32; //len diLen += 32; //len
} }
di[0] = block.deliveryType << 5; // set delivery type di[0] = block.deliveryType << 5; // set delivery type
// create fragments // create fragments
@ -62,21 +62,21 @@ namespace tunnel
m_RemainingSize -= diLen + msg->GetLength (); m_RemainingSize -= diLen + msg->GetLength ();
if (!m_RemainingSize) if (!m_RemainingSize)
CompleteCurrentTunnelDataMessage (); CompleteCurrentTunnelDataMessage ();
} }
else else
{ {
if (!messageCreated) // check if we should complete previous message if (!messageCreated) // check if we should complete previous message
{ {
size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE; size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
// length of bytes don't fit full tunnel message // length of bytes don't fit full tunnel message
// every follow-on fragment adds 7 bytes // every follow-on fragment adds 7 bytes
size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE; size_t nonFit = (fullMsgLen + numFollowOnFragments*7) % TUNNEL_DATA_MAX_PAYLOAD_SIZE;
if (!nonFit || nonFit > m_RemainingSize) if (!nonFit || nonFit > m_RemainingSize)
{ {
CompleteCurrentTunnelDataMessage (); CompleteCurrentTunnelDataMessage ();
CreateCurrentTunnelDataMessage (); CreateCurrentTunnelDataMessage ();
} }
} }
if (diLen + 6 <= m_RemainingSize) if (diLen + 6 <= m_RemainingSize)
{ {
// delivery instructions fit // delivery instructions fit
@ -97,16 +97,16 @@ namespace tunnel
// follow on fragments // follow on fragments
int fragmentNumber = 1; int fragmentNumber = 1;
while (size < msg->GetLength ()) while (size < msg->GetLength ())
{ {
CreateCurrentTunnelDataMessage (); CreateCurrentTunnelDataMessage ();
uint8_t * buf = m_CurrentTunnelDataMsg->GetBuffer (); uint8_t * buf = m_CurrentTunnelDataMsg->GetBuffer ();
buf[0] = 0x80 | (fragmentNumber << 1); // frag buf[0] = 0x80 | (fragmentNumber << 1); // frag
bool isLastFragment = false; bool isLastFragment = false;
size_t s = msg->GetLength () - size; size_t s = msg->GetLength () - size;
if (s > TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7) // 7 follow on instructions if (s > TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7) // 7 follow on instructions
s = TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7; s = TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7;
else // last fragment else // last fragment
{ {
buf[0] |= 0x01; buf[0] |= 0x01;
isLastFragment = true; isLastFragment = true;
} }
@ -119,7 +119,7 @@ namespace tunnel
if(m_RemainingSize < (s+7)) { if(m_RemainingSize < (s+7)) {
LogPrint (eLogError, "TunnelGateway: remaining size overflow: ", m_RemainingSize, " < ", s+7); LogPrint (eLogError, "TunnelGateway: remaining size overflow: ", m_RemainingSize, " < ", s+7);
} else { } else {
m_RemainingSize -= s+7; m_RemainingSize -= s+7;
if (m_RemainingSize == 0) if (m_RemainingSize == 0)
CompleteCurrentTunnelDataMessage (); CompleteCurrentTunnelDataMessage ();
} }
@ -129,17 +129,17 @@ namespace tunnel
size += s; size += s;
fragmentNumber++; fragmentNumber++;
} }
} }
else else
{ {
// delivery instructions don't fit. Create new message // delivery instructions don't fit. Create new message
CompleteCurrentTunnelDataMessage (); CompleteCurrentTunnelDataMessage ();
PutI2NPMsg (block); PutI2NPMsg (block);
// don't delete msg because it's taken care inside // don't delete msg because it's taken care inside
} }
} }
} }
void TunnelGatewayBuffer::ClearTunnelDataMsgs () void TunnelGatewayBuffer::ClearTunnelDataMsgs ()
{ {
m_TunnelDataMsgs.clear (); m_TunnelDataMsgs.clear ();
@ -155,49 +155,49 @@ namespace tunnel
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE; m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE;
m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset; m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset;
m_RemainingSize = TUNNEL_DATA_MAX_PAYLOAD_SIZE; m_RemainingSize = TUNNEL_DATA_MAX_PAYLOAD_SIZE;
} }
void TunnelGatewayBuffer::CompleteCurrentTunnelDataMessage () void TunnelGatewayBuffer::CompleteCurrentTunnelDataMessage ()
{ {
if (!m_CurrentTunnelDataMsg) return; if (!m_CurrentTunnelDataMsg) return;
uint8_t * payload = m_CurrentTunnelDataMsg->GetBuffer (); uint8_t * payload = m_CurrentTunnelDataMsg->GetBuffer ();
size_t size = m_CurrentTunnelDataMsg->len - m_CurrentTunnelDataMsg->offset; size_t size = m_CurrentTunnelDataMsg->len - m_CurrentTunnelDataMsg->offset;
m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE; m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE;
uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload (); uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload ();
RAND_bytes (buf + 4, 16); // original IV RAND_bytes (buf + 4, 16); // original IV
memcpy (payload + size, buf + 4, 16); // copy IV for checksum memcpy (payload + size, buf + 4, 16); // copy IV for checksum
uint8_t hash[32]; uint8_t hash[32];
SHA256(payload, size+16, hash); SHA256(payload, size+16, hash);
memcpy (buf+20, hash, 4); // checksum memcpy (buf+20, hash, 4); // checksum
payload[-1] = 0; // zero payload[-1] = 0; // zero
ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1 ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1
if (paddingSize > 0) if (paddingSize > 0)
{ {
// non-zero padding // non-zero padding
auto randomOffset = rand () % (TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize + 1); auto randomOffset = rand () % (TUNNEL_DATA_MAX_PAYLOAD_SIZE - paddingSize + 1);
memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize); memcpy (buf + 24, m_NonZeroRandomBuffer + randomOffset, paddingSize);
} }
// we can't fill message header yet because encryption is required // we can't fill message header yet because encryption is required
m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg); m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg);
m_CurrentTunnelDataMsg = nullptr; m_CurrentTunnelDataMsg = nullptr;
} }
void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block) void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block)
{ {
if (block.data) if (block.data)
{ {
PutTunnelDataMsg (block); PutTunnelDataMsg (block);
SendBuffer (); SendBuffer ();
} }
} }
void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block) void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block)
{ {
if (block.data) if (block.data)
m_Buffer.PutI2NPMsg (block); m_Buffer.PutI2NPMsg (block);
} }
void TunnelGateway::SendBuffer () void TunnelGateway::SendBuffer ()
{ {
@ -205,17 +205,17 @@ namespace tunnel
std::vector<std::shared_ptr<I2NPMessage> > newTunnelMsgs; std::vector<std::shared_ptr<I2NPMessage> > newTunnelMsgs;
const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs (); const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs ();
for (auto& tunnelMsg : tunnelDataMsgs) for (auto& tunnelMsg : tunnelDataMsgs)
{ {
auto newMsg = CreateEmptyTunnelDataMsg (); auto newMsg = CreateEmptyTunnelDataMsg ();
m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg); m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg);
htobe32buf (newMsg->GetPayload (), m_Tunnel->GetNextTunnelID ()); htobe32buf (newMsg->GetPayload (), m_Tunnel->GetNextTunnelID ());
newMsg->FillI2NPMessageHeader (eI2NPTunnelData); newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
newTunnelMsgs.push_back (newMsg); newTunnelMsgs.push_back (newMsg);
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE; m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
} }
m_Buffer.ClearTunnelDataMsgs (); m_Buffer.ClearTunnelDataMsgs ();
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), newTunnelMsgs); i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), newTunnelMsgs);
} }
} }
} }

View file

@ -16,7 +16,7 @@ namespace tunnel
public: public:
TunnelGatewayBuffer (); TunnelGatewayBuffer ();
~TunnelGatewayBuffer (); ~TunnelGatewayBuffer ();
void PutI2NPMsg (const TunnelMessageBlock& block); void PutI2NPMsg (const TunnelMessageBlock& block);
const std::vector<std::shared_ptr<const I2NPMessage> >& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; }; const std::vector<std::shared_ptr<const I2NPMessage> >& GetTunnelDataMsgs () const { return m_TunnelDataMsgs; };
void ClearTunnelDataMsgs (); void ClearTunnelDataMsgs ();
void CompleteCurrentTunnelDataMessage (); void CompleteCurrentTunnelDataMessage ();
@ -24,14 +24,14 @@ namespace tunnel
private: private:
void CreateCurrentTunnelDataMessage (); void CreateCurrentTunnelDataMessage ();
private: private:
std::vector<std::shared_ptr<const I2NPMessage> > m_TunnelDataMsgs; std::vector<std::shared_ptr<const I2NPMessage> > m_TunnelDataMsgs;
std::shared_ptr<I2NPMessage> m_CurrentTunnelDataMsg; std::shared_ptr<I2NPMessage> m_CurrentTunnelDataMsg;
size_t m_RemainingSize; size_t m_RemainingSize;
uint8_t m_NonZeroRandomBuffer[TUNNEL_DATA_MAX_PAYLOAD_SIZE]; uint8_t m_NonZeroRandomBuffer[TUNNEL_DATA_MAX_PAYLOAD_SIZE];
}; };
class TunnelGateway class TunnelGateway
{ {
@ -39,18 +39,18 @@ namespace tunnel
TunnelGateway (TunnelBase * tunnel): TunnelGateway (TunnelBase * tunnel):
m_Tunnel (tunnel), m_NumSentBytes (0) {}; m_Tunnel (tunnel), m_NumSentBytes (0) {};
void SendTunnelDataMsg (const TunnelMessageBlock& block); void SendTunnelDataMsg (const TunnelMessageBlock& block);
void PutTunnelDataMsg (const TunnelMessageBlock& block); void PutTunnelDataMsg (const TunnelMessageBlock& block);
void SendBuffer (); void SendBuffer ();
size_t GetNumSentBytes () const { return m_NumSentBytes; }; size_t GetNumSentBytes () const { return m_NumSentBytes; };
private: private:
TunnelBase * m_Tunnel; TunnelBase * m_Tunnel;
TunnelGatewayBuffer m_Buffer; TunnelGatewayBuffer m_Buffer;
size_t m_NumSentBytes; size_t m_NumSentBytes;
}; };
} }
} }
#endif #endif

View file

@ -298,13 +298,13 @@ namespace tunnel
} }
if (!failed) if (!failed)
{ {
uint32_t msgID; uint32_t msgID;
RAND_bytes ((uint8_t *)&msgID, 4); RAND_bytes ((uint8_t *)&msgID, 4);
{ {
std::unique_lock<std::mutex> l(m_TestsMutex); std::unique_lock<std::mutex> l(m_TestsMutex);
m_Tests[msgID] = std::make_pair (*it1, *it2); m_Tests[msgID] = std::make_pair (*it1, *it2);
} }
(*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (), (*it1)->SendTunnelDataMsg ((*it2)->GetNextIdentHash (), (*it2)->GetNextTunnelID (),
CreateDeliveryStatusMsg (msgID)); CreateDeliveryStatusMsg (msgID));
++it1; ++it2; ++it1; ++it2;
} }

View file

@ -28,23 +28,23 @@ namespace api
i2p::fs::DetectDataDir(datadir, false); i2p::fs::DetectDataDir(datadir, false);
i2p::fs::Init(); i2p::fs::Init();
#if defined(__x86_64__) #if defined(__x86_64__)
i2p::crypto::InitCrypto (false); i2p::crypto::InitCrypto (false);
#else #else
i2p::crypto::InitCrypto (true); i2p::crypto::InitCrypto (true);
#endif #endif
int netID; i2p::config::GetOption("netid", netID); int netID; i2p::config::GetOption("netid", netID);
i2p::context.SetNetID (netID); i2p::context.SetNetID (netID);
i2p::context.Init (); i2p::context.Init ();
} }
void TerminateI2P () void TerminateI2P ()
{ {
i2p::crypto::TerminateCrypto (); i2p::crypto::TerminateCrypto ();
} }
void StartI2P (std::shared_ptr<std::ostream> logStream) void StartI2P (std::shared_ptr<std::ostream> logStream)
{ {
if (logStream) if (logStream)
@ -75,8 +75,8 @@ namespace api
void RunPeerTest () void RunPeerTest ()
{ {
i2p::transport::transports.PeerTest (); i2p::transport::transports.PeerTest ();
} }
std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic, std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
const std::map<std::string, std::string> * params) const std::map<std::string, std::string> * params)
{ {
@ -119,8 +119,8 @@ namespace api
else else
{ {
RequestLeaseSet (dest, remote); RequestLeaseSet (dest, remote);
return nullptr; return nullptr;
} }
} }
void AcceptStream (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::stream::StreamingDestination::Acceptor& acceptor) void AcceptStream (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::stream::StreamingDestination::Acceptor& acceptor)

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