remove trailing whitespaces

This commit is contained in:
yangfl 2018-01-06 11:48:51 +08:00
parent b91efaa973
commit 46f62e1af9
117 changed files with 3039 additions and 3040 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);
@ -67,7 +67,7 @@ namespace http
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 ()
@ -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);
} }
@ -190,12 +190,12 @@ namespace client
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,7 +261,7 @@ 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)
@ -276,8 +276,8 @@ namespace data
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

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

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

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

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,7 +123,7 @@ 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 ();
} }
@ -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,10 +268,10 @@ 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:
@ -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

@ -96,7 +96,7 @@ namespace data
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;

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,9 +189,9 @@ 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
{ {
@ -199,7 +199,7 @@ namespace data
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 */ /** return true if we are in a router family and the signature is valid */
bool IsFamily(const std::string & fam) const; 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
} }
@ -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 ();
@ -362,21 +362,21 @@ namespace transport
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,11 +72,11 @@ 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)
@ -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,11 @@ namespace stream
Packet * NewPacket () { return m_PacketsPool.Acquire (); } Packet * NewPacket () { return m_PacketsPool.Acquire (); }
void DeletePacket (Packet * p) { m_PacketsPool.Release (p); } void DeletePacket (Packet * p) { m_PacketsPool.Release (p); }
private: 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 +293,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 +306,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 +318,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; };
}; };
//------------------------------------------------- //-------------------------------------------------
@ -345,7 +345,7 @@ namespace stream
s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode) s->m_ReceiveTimer.async_wait ([=](const boost::system::error_code& ecode)
{ s->HandleReceiveTimer (ecode, buffer, handler, timeout - t); }); { s->HandleReceiveTimer (ecode, buffer, handler, timeout - t); });
} }
}); });
} }
template<typename Buffer, typename ReceiveHandler> template<typename Buffer, typename ReceiveHandler>
@ -355,27 +355,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

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

@ -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,21 +34,21 @@ 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)
{ {
@ -61,31 +61,31 @@ namespace tunnel
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

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

View file

@ -11,18 +11,18 @@ namespace i2p
{ {
namespace api namespace api
{ {
// initialization start and stop // initialization start and stop
void InitI2P (int argc, char* argv[], const char * appName); void InitI2P (int argc, char* argv[], const char * appName);
void TerminateI2P (); void TerminateI2P ();
void StartI2P (std::shared_ptr<std::ostream> logStream = nullptr); void StartI2P (std::shared_ptr<std::ostream> logStream = nullptr);
// write system log to logStream, if not specified to <appName>.log in application's folder // write system log to logStream, if not specified to <appName>.log in application's folder
void StopI2P (); void StopI2P ();
void RunPeerTest (); // should be called after UPnP void RunPeerTest (); // should be called after UPnP
// destinations // destinations
std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true, std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
const std::map<std::string, std::string> * params = nullptr); const std::map<std::string, std::string> * params = nullptr);
std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256, std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (bool isPublic = false, i2p::data::SigningKeyType sigType = i2p::data::SIGNING_KEY_TYPE_ECDSA_SHA256_P256,
const std::map<std::string, std::string> * params = nullptr); // transient destinations usually not published const std::map<std::string, std::string> * params = nullptr); // transient destinations usually not published
void DestroyLocalDestination (std::shared_ptr<i2p::client::ClientDestination> dest); void DestroyLocalDestination (std::shared_ptr<i2p::client::ClientDestination> dest);

View file

@ -8,7 +8,7 @@
#ifdef WIN32 #ifdef WIN32
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#include <iphlpapi.h> #include <iphlpapi.h>
@ -167,7 +167,7 @@ namespace net
} }
int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback) int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback)
{ {
#ifdef UNICODE #ifdef UNICODE
string localAddress_temporary = localAddress.to_string(); string localAddress_temporary = localAddress.to_string();
wstring localAddressUniversal(localAddress_temporary.begin(), localAddress_temporary.end()); wstring localAddressUniversal(localAddress_temporary.begin(), localAddress_temporary.end());
@ -181,7 +181,7 @@ namespace net
return GetMTUWindowsIpv4(inputAddress, fallback); return GetMTUWindowsIpv4(inputAddress, fallback);
} else if(localAddress.is_v6()) { } else if(localAddress.is_v6()) {
sockaddr_in6 inputAddress; sockaddr_in6 inputAddress;
inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr)); inet_pton(AF_INET6, localAddressUniversal.c_str(), &(inputAddress.sin6_addr));
return GetMTUWindowsIpv6(inputAddress, fallback); return GetMTUWindowsIpv6(inputAddress, fallback);
} else { } else {
LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported"); LogPrint(eLogError, "NetIface: GetMTU(): address family is not supported");
@ -193,27 +193,27 @@ namespace net
int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback) int GetMTUUnix(const boost::asio::ip::address& localAddress, int fallback)
{ {
ifaddrs* ifaddr, *ifa = nullptr; ifaddrs* ifaddr, *ifa = nullptr;
if(getifaddrs(&ifaddr) == -1) if(getifaddrs(&ifaddr) == -1)
{ {
LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno)); LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno));
return fallback; return fallback;
} }
int family = 0; int family = 0;
// look for interface matching local address // look for interface matching local address
for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
{ {
if(!ifa->ifa_addr) if(!ifa->ifa_addr)
continue; continue;
family = ifa->ifa_addr->sa_family; family = ifa->ifa_addr->sa_family;
if(family == AF_INET && localAddress.is_v4()) if(family == AF_INET && localAddress.is_v4())
{ {
sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr; sockaddr_in* sa = (sockaddr_in*) ifa->ifa_addr;
if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4)) if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
break; // address matches break; // address matches
} }
else if(family == AF_INET6 && localAddress.is_v6()) else if(family == AF_INET6 && localAddress.is_v6())
{ {
sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr; sockaddr_in6* sa = (sockaddr_in6*) ifa->ifa_addr;
if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16)) if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
@ -221,28 +221,28 @@ namespace net
} }
} }
int mtu = fallback; int mtu = fallback;
if(ifa && family) if(ifa && family)
{ // interface found? { // interface found?
int fd = socket(family, SOCK_DGRAM, 0); int fd = socket(family, SOCK_DGRAM, 0);
if(fd > 0) if(fd > 0)
{ {
ifreq ifr; ifreq ifr;
strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query strncpy(ifr.ifr_name, ifa->ifa_name, IFNAMSIZ); // set interface for query
if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0) if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0)
mtu = ifr.ifr_mtu; // MTU mtu = ifr.ifr_mtu; // MTU
else else
LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno)); LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno));
close(fd); close(fd);
} }
else else
LogPrint(eLogError, "NetIface: Failed to create datagram socket"); LogPrint(eLogError, "NetIface: Failed to create datagram socket");
} }
else else
LogPrint(eLogWarning, "NetIface: interface for local address", localAddress.to_string(), " not found"); LogPrint(eLogWarning, "NetIface: interface for local address", localAddress.to_string(), " not found");
freeifaddrs(ifaddr); freeifaddrs(ifaddr);
return mtu; return mtu;
} }
#endif // WIN32 #endif // WIN32
int GetMTU(const boost::asio::ip::address& localAddress) int GetMTU(const boost::asio::ip::address& localAddress)
@ -256,7 +256,7 @@ namespace net
#endif #endif
return fallback; return fallback;
} }
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6) const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6)
{ {
#ifdef WIN32 #ifdef WIN32
@ -299,9 +299,9 @@ namespace net
LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname); LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname);
} }
return boost::asio::ip::address::from_string(fallback); return boost::asio::ip::address::from_string(fallback);
#endif #endif
} }
} }
} // util } // util
} // i2p } // i2p

View file

@ -38,15 +38,15 @@ namespace util
public: public:
MemoryPool (): m_Head (nullptr) {} MemoryPool (): m_Head (nullptr) {}
~MemoryPool () ~MemoryPool ()
{ {
while (m_Head) while (m_Head)
{ {
auto tmp = m_Head; auto tmp = m_Head;
m_Head = static_cast<T*>(*(void * *)m_Head); // next m_Head = static_cast<T*>(*(void * *)m_Head); // next
delete tmp; delete tmp;
} }
} }
template<typename... TArgs> template<typename... TArgs>
T * Acquire (TArgs&&... args) T * Acquire (TArgs&&... args)
@ -65,7 +65,7 @@ namespace util
if (!t) return; if (!t) return;
t->~T (); t->~T ();
*(void * *)t = m_Head; // next *(void * *)t = m_Head; // next
m_Head = t; m_Head = t;
} }
template<typename... TArgs> template<typename... TArgs>
@ -74,7 +74,7 @@ namespace util
return std::unique_ptr<T, std::function<void(T*)> >(Acquire (std::forward<TArgs>(args)...), return std::unique_ptr<T, std::function<void(T*)> >(Acquire (std::forward<TArgs>(args)...),
std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1)); std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1));
} }
template<typename... TArgs> template<typename... TArgs>
std::shared_ptr<T> AcquireShared (TArgs&&... args) std::shared_ptr<T> AcquireShared (TArgs&&... args)
{ {
@ -85,7 +85,7 @@ namespace util
protected: protected:
T * m_Head; T * m_Head;
}; };
template<class T> template<class T>
class MemoryPoolMt: public MemoryPool<T> class MemoryPoolMt: public MemoryPool<T>
@ -104,19 +104,19 @@ namespace util
void ReleaseMt (T * t) void ReleaseMt (T * t)
{ {
std::lock_guard<std::mutex> l(m_Mutex); std::lock_guard<std::mutex> l(m_Mutex);
this->Release (t); this->Release (t);
} }
template<template<typename, typename...>class C, typename... R> template<template<typename, typename...>class C, typename... R>
void ReleaseMt(const C<T *, R...>& c) void ReleaseMt(const C<T *, R...>& c)
{ {
std::lock_guard<std::mutex> l(m_Mutex); std::lock_guard<std::mutex> l(m_Mutex);
for (auto& it: c) for (auto& it: c)
this->Release (it); this->Release (it);
} }
private: private:
std::mutex m_Mutex; std::mutex m_Mutex;
}; };

View file

@ -383,9 +383,9 @@ namespace client
{ {
it->second = ident->GetIdentHash (); it->second = ident->GetIdentHash ();
m_Storage->AddAddress (ident); m_Storage->AddAddress (ident);
LogPrint (eLogInfo, "Addressbook: updated host: ", name); LogPrint (eLogInfo, "Addressbook: updated host: ", name);
} }
} }
else else
{ {
m_Addresses.insert (std::make_pair (name, ident->GetIdentHash ())); m_Addresses.insert (std::make_pair (name, ident->GetIdentHash ()));

View file

@ -18,15 +18,15 @@ namespace i2p
{ {
namespace client namespace client
{ {
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // in minutes
const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes const int INITIAL_SUBSCRIPTION_RETRY_TIMEOUT = 1; // in minutes
const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours) const int CONTINIOUS_SUBSCRIPTION_UPDATE_TIMEOUT = 720; // in minutes (12 hours)
const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes const int CONTINIOUS_SUBSCRIPTION_RETRY_TIMEOUT = 5; // in minutes
const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second const int SUBSCRIPTION_REQUEST_TIMEOUT = 60; //in second
const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53; const uint16_t ADDRESS_RESOLVER_DATAGRAM_PORT = 53;
const uint16_t ADDRESS_RESPONSE_DATAGRAM_PORT = 54; const uint16_t ADDRESS_RESPONSE_DATAGRAM_PORT = 54;
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); } inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
class AddressBookStorage // interface for storage class AddressBookStorage // interface for storage
@ -34,10 +34,10 @@ namespace client
public: public:
virtual ~AddressBookStorage () {}; virtual ~AddressBookStorage () {};
virtual std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const = 0; virtual std::shared_ptr<const i2p::data::IdentityEx> GetAddress (const i2p::data::IdentHash& ident) const = 0;
virtual void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address) = 0; virtual void AddAddress (std::shared_ptr<const i2p::data::IdentityEx> address) = 0;
virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0; virtual void RemoveAddress (const i2p::data::IdentHash& ident) = 0;
virtual bool Init () = 0; virtual bool Init () = 0;
virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0; virtual int Load (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
virtual int LoadLocal (std::map<std::string, i2p::data::IdentHash>& addresses) = 0; virtual int LoadLocal (std::map<std::string, i2p::data::IdentHash>& addresses) = 0;
@ -45,7 +45,7 @@ namespace client
virtual void SaveEtag (const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) = 0; virtual void SaveEtag (const i2p::data::IdentHash& subscription, const std::string& etag, const std::string& lastModified) = 0;
virtual bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) = 0; virtual bool GetEtag (const i2p::data::IdentHash& subscription, std::string& etag, std::string& lastModified) = 0;
}; };
class AddressBookSubscription; class AddressBookSubscription;
class AddressResolver; class AddressResolver;
@ -77,7 +77,7 @@ namespace client
void StartSubscriptions (); void StartSubscriptions ();
void StopSubscriptions (); void StopSubscriptions ();
void LoadHosts (); void LoadHosts ();
void LoadSubscriptions (); void LoadSubscriptions ();
void LoadLocal (); void LoadLocal ();
@ -87,8 +87,8 @@ namespace client
void StartLookups (); void StartLookups ();
void StopLookups (); void StopLookups ();
void HandleLookupResponse (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleLookupResponse (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len);
private: private:
std::mutex m_AddressBookMutex; std::mutex m_AddressBookMutex;
std::map<std::string, i2p::data::IdentHash> m_Addresses; std::map<std::string, i2p::data::IdentHash> m_Addresses;
@ -112,7 +112,7 @@ namespace client
private: private:
bool MakeRequest (); bool MakeRequest ();
private: private:
AddressBook& m_Book; AddressBook& m_Book;

View file

@ -8,7 +8,7 @@ namespace i2p
{ {
namespace client namespace client
{ {
BOBI2PInboundTunnel::BOBI2PInboundTunnel (const boost::asio::ip::tcp::endpoint& ep, std::shared_ptr<ClientDestination> localDestination): BOBI2PInboundTunnel::BOBI2PInboundTunnel (const boost::asio::ip::tcp::endpoint& ep, std::shared_ptr<ClientDestination> localDestination):
BOBI2PTunnel (localDestination), m_Acceptor (localDestination->GetService (), ep) BOBI2PTunnel (localDestination), m_Acceptor (localDestination->GetService (), ep)
{ {
} }
@ -36,13 +36,13 @@ namespace client
receiver->socket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ()); receiver->socket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this, m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this,
std::placeholders::_1, receiver)); std::placeholders::_1, receiver));
} }
void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver) void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver)
{ {
if (!ecode) if (!ecode)
{ {
Accept (); Accept ();
ReceiveAddress (receiver); ReceiveAddress (receiver);
} }
} }
@ -50,12 +50,12 @@ namespace client
void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver) void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver)
{ {
receiver->socket->async_read_some (boost::asio::buffer( receiver->socket->async_read_some (boost::asio::buffer(
receiver->buffer + receiver->bufferOffset, receiver->buffer + receiver->bufferOffset,
BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset), BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset),
std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this, std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this,
std::placeholders::_1, std::placeholders::_2, receiver)); std::placeholders::_1, std::placeholders::_2, receiver));
} }
void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred, void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
std::shared_ptr<AddressReceiver> receiver) std::shared_ptr<AddressReceiver> receiver)
{ {
@ -69,11 +69,11 @@ namespace client
if (eol) if (eol)
{ {
*eol = 0; *eol = 0;
if (eol != receiver->buffer && eol[-1] == '\r') eol[-1] = 0; // workaround for Transmission, it sends '\r\n' terminated address if (eol != receiver->buffer && eol[-1] == '\r') eol[-1] = 0; // workaround for Transmission, it sends '\r\n' terminated address
receiver->data = (uint8_t *)eol + 1; receiver->data = (uint8_t *)eol + 1;
receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1); receiver->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident)) if (!context.GetAddressBook ().GetIdentHash (receiver->buffer, ident))
{ {
LogPrint (eLogError, "BOB: address ", receiver->buffer, " not found"); LogPrint (eLogError, "BOB: address ", receiver->buffer, " not found");
return; return;
@ -82,7 +82,7 @@ namespace client
if (leaseSet) if (leaseSet)
CreateConnection (receiver, leaseSet); CreateConnection (receiver, leaseSet);
else else
GetLocalDestination ()->RequestDestination (ident, GetLocalDestination ()->RequestDestination (ident,
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete, std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
this, std::placeholders::_1, receiver)); this, std::placeholders::_1, receiver));
} }
@ -92,7 +92,7 @@ namespace client
ReceiveAddress (receiver); ReceiveAddress (receiver);
else else
LogPrint (eLogError, "BOB: missing inbound address"); LogPrint (eLogError, "BOB: missing inbound address");
} }
} }
} }
@ -102,7 +102,7 @@ namespace client
CreateConnection (receiver, leaseSet); CreateConnection (receiver, leaseSet);
else else
LogPrint (eLogError, "BOB: LeaseSet for inbound destination not found"); LogPrint (eLogError, "BOB: LeaseSet for inbound destination not found");
} }
void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet) void BOBI2PInboundTunnel::CreateConnection (std::shared_ptr<AddressReceiver> receiver, std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
{ {
@ -112,12 +112,12 @@ namespace client
connection->I2PConnect (receiver->data, receiver->dataLen); connection->I2PConnect (receiver->data, receiver->dataLen);
} }
BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& address, int port, BOBI2POutboundTunnel::BOBI2POutboundTunnel (const std::string& address, int port,
std::shared_ptr<ClientDestination> localDestination, bool quiet): BOBI2PTunnel (localDestination), std::shared_ptr<ClientDestination> localDestination, bool quiet): BOBI2PTunnel (localDestination),
m_Endpoint (boost::asio::ip::address::from_string (address), port), m_IsQuiet (quiet) m_Endpoint (boost::asio::ip::address::from_string (address), port), m_IsQuiet (quiet)
{ {
} }
void BOBI2POutboundTunnel::Start () void BOBI2POutboundTunnel::Start ()
{ {
Accept (); Accept ();
@ -126,11 +126,11 @@ namespace client
void BOBI2POutboundTunnel::Stop () void BOBI2POutboundTunnel::Stop ()
{ {
ClearHandlers (); ClearHandlers ();
} }
void BOBI2POutboundTunnel::Accept () void BOBI2POutboundTunnel::Accept ()
{ {
auto localDestination = GetLocalDestination (); auto localDestination = GetLocalDestination ();
if (localDestination) if (localDestination)
localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1)); localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1));
else else
@ -140,54 +140,54 @@ namespace client
void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream) void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
{ {
if (stream) if (stream)
{ {
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), m_Endpoint, m_IsQuiet); auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), m_Endpoint, m_IsQuiet);
AddHandler (conn); AddHandler (conn);
conn->Connect (); conn->Connect ();
} }
} }
BOBDestination::BOBDestination (std::shared_ptr<ClientDestination> localDestination): BOBDestination::BOBDestination (std::shared_ptr<ClientDestination> localDestination):
m_LocalDestination (localDestination), m_LocalDestination (localDestination),
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr) m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr)
{ {
} }
BOBDestination::~BOBDestination () BOBDestination::~BOBDestination ()
{ {
delete m_OutboundTunnel; delete m_OutboundTunnel;
delete m_InboundTunnel; delete m_InboundTunnel;
i2p::client::context.DeleteLocalDestination (m_LocalDestination); i2p::client::context.DeleteLocalDestination (m_LocalDestination);
} }
void BOBDestination::Start () void BOBDestination::Start ()
{ {
if (m_OutboundTunnel) m_OutboundTunnel->Start (); if (m_OutboundTunnel) m_OutboundTunnel->Start ();
if (m_InboundTunnel) m_InboundTunnel->Start (); if (m_InboundTunnel) m_InboundTunnel->Start ();
} }
void BOBDestination::Stop () void BOBDestination::Stop ()
{ {
StopTunnels (); StopTunnels ();
m_LocalDestination->Stop (); m_LocalDestination->Stop ();
} }
void BOBDestination::StopTunnels () void BOBDestination::StopTunnels ()
{ {
if (m_OutboundTunnel) if (m_OutboundTunnel)
{ {
m_OutboundTunnel->Stop (); m_OutboundTunnel->Stop ();
delete m_OutboundTunnel; delete m_OutboundTunnel;
m_OutboundTunnel = nullptr; m_OutboundTunnel = nullptr;
} }
if (m_InboundTunnel) if (m_InboundTunnel)
{ {
m_InboundTunnel->Stop (); m_InboundTunnel->Stop ();
delete m_InboundTunnel; delete m_InboundTunnel;
m_InboundTunnel = nullptr; m_InboundTunnel = nullptr;
} }
} }
void BOBDestination::CreateInboundTunnel (int port, const std::string& address) void BOBDestination::CreateInboundTunnel (int port, const std::string& address)
{ {
if (!m_InboundTunnel) if (!m_InboundTunnel)
@ -200,21 +200,21 @@ namespace client
if (!ec) if (!ec)
ep.address (addr); ep.address (addr);
else else
LogPrint (eLogError, "BOB: ", ec.message ()); LogPrint (eLogError, "BOB: ", ec.message ());
} }
m_InboundTunnel = new BOBI2PInboundTunnel (ep, m_LocalDestination); m_InboundTunnel = new BOBI2PInboundTunnel (ep, m_LocalDestination);
} }
} }
void BOBDestination::CreateOutboundTunnel (const std::string& address, int port, bool quiet) void BOBDestination::CreateOutboundTunnel (const std::string& address, int port, bool quiet)
{ {
if (!m_OutboundTunnel) if (!m_OutboundTunnel)
m_OutboundTunnel = new BOBI2POutboundTunnel (address, port, m_LocalDestination, quiet); m_OutboundTunnel = new BOBI2POutboundTunnel (address, port, m_LocalDestination, quiet);
} }
BOBCommandSession::BOBCommandSession (BOBCommandChannel& owner): BOBCommandSession::BOBCommandSession (BOBCommandChannel& owner):
m_Owner (owner), m_Socket (m_Owner.GetService ()), m_Owner (owner), m_Socket (m_Owner.GetService ()),
m_ReceiveBufferOffset (0), m_IsOpen (true), m_IsQuiet (false), m_IsActive (false), m_ReceiveBufferOffset (0), m_IsOpen (true), m_IsQuiet (false), m_IsActive (false),
m_InPort (0), m_OutPort (0), m_CurrentDestination (nullptr) m_InPort (0), m_OutPort (0), m_CurrentDestination (nullptr)
{ {
} }
@ -226,13 +226,13 @@ namespace client
void BOBCommandSession::Terminate () void BOBCommandSession::Terminate ()
{ {
m_Socket.close (); m_Socket.close ();
m_IsOpen = false; m_IsOpen = false;
} }
void BOBCommandSession::Receive () void BOBCommandSession::Receive ()
{ {
m_Socket.async_read_some (boost::asio::buffer(m_ReceiveBuffer + m_ReceiveBufferOffset, BOB_COMMAND_BUFFER_SIZE - m_ReceiveBufferOffset), m_Socket.async_read_some (boost::asio::buffer(m_ReceiveBuffer + m_ReceiveBufferOffset, BOB_COMMAND_BUFFER_SIZE - m_ReceiveBufferOffset),
std::bind(&BOBCommandSession::HandleReceived, shared_from_this (), std::bind(&BOBCommandSession::HandleReceived, shared_from_this (),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} }
@ -243,29 +243,29 @@ namespace client
LogPrint (eLogError, "BOB: command channel read error: ", ecode.message ()); LogPrint (eLogError, "BOB: command channel read error: ", ecode.message ());
if (ecode != boost::asio::error::operation_aborted) if (ecode != boost::asio::error::operation_aborted)
Terminate (); Terminate ();
} }
else else
{ {
size_t size = m_ReceiveBufferOffset + bytes_transferred; size_t size = m_ReceiveBufferOffset + bytes_transferred;
m_ReceiveBuffer[size] = 0; m_ReceiveBuffer[size] = 0;
char * eol = strchr (m_ReceiveBuffer, '\n'); char * eol = strchr (m_ReceiveBuffer, '\n');
if (eol) if (eol)
{ {
*eol = 0; *eol = 0;
char * operand = strchr (m_ReceiveBuffer, ' '); char * operand = strchr (m_ReceiveBuffer, ' ');
if (operand) if (operand)
{ {
*operand = 0; *operand = 0;
operand++; operand++;
} }
else else
operand = eol; operand = eol;
// process command // process command
auto& handlers = m_Owner.GetCommandHandlers (); auto& handlers = m_Owner.GetCommandHandlers ();
auto it = handlers.find (m_ReceiveBuffer); auto it = handlers.find (m_ReceiveBuffer);
if (it != handlers.end ()) if (it != handlers.end ())
(this->*(it->second))(operand, eol - operand); (this->*(it->second))(operand, eol - operand);
else else
{ {
LogPrint (eLogError, "BOB: unknown command ", m_ReceiveBuffer); LogPrint (eLogError, "BOB: unknown command ", m_ReceiveBuffer);
SendReplyError ("unknown command"); SendReplyError ("unknown command");
@ -283,15 +283,15 @@ namespace client
LogPrint (eLogError, "BOB: Malformed input of the command channel"); LogPrint (eLogError, "BOB: Malformed input of the command channel");
Terminate (); Terminate ();
} }
} }
} }
} }
void BOBCommandSession::Send (size_t len) void BOBCommandSession::Send (size_t len)
{ {
boost::asio::async_write (m_Socket, boost::asio::buffer (m_SendBuffer, len), boost::asio::async_write (m_Socket, boost::asio::buffer (m_SendBuffer, len),
boost::asio::transfer_all (), boost::asio::transfer_all (),
std::bind(&BOBCommandSession::HandleSent, shared_from_this (), std::bind(&BOBCommandSession::HandleSent, shared_from_this (),
std::placeholders::_1, std::placeholders::_2)); std::placeholders::_1, std::placeholders::_2));
} }
@ -308,7 +308,7 @@ namespace client
if (m_IsOpen) if (m_IsOpen)
Receive (); Receive ();
else else
Terminate (); Terminate ();
} }
} }
@ -316,7 +316,7 @@ namespace client
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg); size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg);
#else #else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg); size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_OK, msg);
#endif #endif
Send (len); Send (len);
@ -326,12 +326,12 @@ namespace client
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg); size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg);
#else #else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg); size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_REPLY_ERROR, msg);
#endif #endif
Send (len); Send (len);
} }
void BOBCommandSession::SendVersion () void BOBCommandSession::SendVersion ()
{ {
size_t len = strlen (BOB_VERSION); size_t len = strlen (BOB_VERSION);
@ -343,12 +343,12 @@ namespace client
{ {
#ifdef _MSC_VER #ifdef _MSC_VER
size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname); size_t len = sprintf_s (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname);
#else #else
size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname); size_t len = snprintf (m_SendBuffer, BOB_COMMAND_BUFFER_SIZE, BOB_DATA, nickname);
#endif #endif
Send (len); Send (len);
} }
void BOBCommandSession::ZapCommandHandler (const char * operand, size_t len) void BOBCommandSession::ZapCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: zap"); LogPrint (eLogDebug, "BOB: zap");
@ -368,21 +368,21 @@ namespace client
if (m_IsActive) if (m_IsActive)
{ {
SendReplyError ("tunnel is active"); SendReplyError ("tunnel is active");
return; return;
} }
if (!m_CurrentDestination) if (!m_CurrentDestination)
{ {
m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options)); m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options));
m_Owner.AddDestination (m_Nickname, m_CurrentDestination); m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
} }
if (m_InPort) if (m_InPort)
m_CurrentDestination->CreateInboundTunnel (m_InPort, m_Address); m_CurrentDestination->CreateInboundTunnel (m_InPort, m_Address);
if (m_OutPort && !m_Address.empty ()) if (m_OutPort && !m_Address.empty ())
m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet); m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet);
m_CurrentDestination->Start (); m_CurrentDestination->Start ();
SendReplyOK ("Tunnel starting"); SendReplyOK ("Tunnel starting");
m_IsActive = true; m_IsActive = true;
} }
void BOBCommandSession::StopCommandHandler (const char * operand, size_t len) void BOBCommandSession::StopCommandHandler (const char * operand, size_t len)
{ {
@ -401,8 +401,8 @@ namespace client
else else
SendReplyError ("tunnel not found"); SendReplyError ("tunnel not found");
m_IsActive = false; m_IsActive = false;
} }
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len) void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: setnick ", operand); LogPrint (eLogDebug, "BOB: setnick ", operand);
@ -410,30 +410,30 @@ namespace client
std::string msg ("Nickname set to "); std::string msg ("Nickname set to ");
msg += m_Nickname; msg += m_Nickname;
SendReplyOK (msg.c_str ()); SendReplyOK (msg.c_str ());
} }
void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len) void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: getnick ", operand); LogPrint (eLogDebug, "BOB: getnick ", operand);
m_CurrentDestination = m_Owner.FindDestination (operand); m_CurrentDestination = m_Owner.FindDestination (operand);
if (m_CurrentDestination) if (m_CurrentDestination)
{ {
m_Keys = m_CurrentDestination->GetKeys (); m_Keys = m_CurrentDestination->GetKeys ();
m_Nickname = operand; m_Nickname = operand;
} }
if (m_Nickname == operand) if (m_Nickname == operand)
{ {
std::string msg ("Nickname set to "); std::string msg ("Nickname set to ");
msg += m_Nickname; msg += m_Nickname;
SendReplyOK (msg.c_str ()); SendReplyOK (msg.c_str ());
} }
else else
SendReplyError ("no nickname has been set"); SendReplyError ("no nickname has been set");
} }
void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len) void BOBCommandSession::NewkeysCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: newkeys"); LogPrint (eLogDebug, "BOB: newkeys");
i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1; i2p::data::SigningKeyType signatureType = i2p::data::SIGNING_KEY_TYPE_DSA_SHA1;
i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; i2p::data::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
if (*operand) if (*operand)
@ -441,23 +441,23 @@ namespace client
try try
{ {
char * operand1 = (char *)strchr (operand, ' '); char * operand1 = (char *)strchr (operand, ' ');
if (operand1) if (operand1)
{ {
*operand1 = 0; operand1++; *operand1 = 0; operand1++;
cryptoType = std::stoi(operand1); cryptoType = std::stoi(operand1);
} }
signatureType = std::stoi(operand); signatureType = std::stoi(operand);
} }
catch (std::invalid_argument& ex) catch (std::invalid_argument& ex)
{ {
LogPrint (eLogWarning, "BOB: newkeys ", ex.what ()); LogPrint (eLogWarning, "BOB: newkeys ", ex.what ());
} }
} }
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType); m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
} }
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len) void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
{ {
@ -467,9 +467,9 @@ namespace client
else else
SendReplyError ("invalid keys"); SendReplyError ("invalid keys");
} }
void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len) void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: getkeys"); LogPrint (eLogDebug, "BOB: getkeys");
if (m_Keys.GetPublic ()) // keys are set ? if (m_Keys.GetPublic ()) // keys are set ?
SendReplyOK (m_Keys.ToBase64 ().c_str ()); SendReplyOK (m_Keys.ToBase64 ().c_str ());
@ -484,15 +484,15 @@ namespace client
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ()); SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
else else
SendReplyError ("keys are not set"); SendReplyError ("keys are not set");
} }
void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len) void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: outhost ", operand); LogPrint (eLogDebug, "BOB: outhost ", operand);
m_Address = operand; m_Address = operand;
SendReplyOK ("outhost set"); SendReplyOK ("outhost set");
} }
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len) void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: outport ", operand); LogPrint (eLogDebug, "BOB: outport ", operand);
@ -501,7 +501,7 @@ namespace client
SendReplyOK ("outbound port set"); SendReplyOK ("outbound port set");
else else
SendReplyError ("port out of range"); SendReplyError ("port out of range");
} }
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len) void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
{ {
@ -509,7 +509,7 @@ namespace client
m_Address = operand; m_Address = operand;
SendReplyOK ("inhost set"); SendReplyOK ("inhost set");
} }
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len) void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: inport ", operand); LogPrint (eLogDebug, "BOB: inport ", operand);
@ -518,7 +518,7 @@ namespace client
SendReplyOK ("inbound port set"); SendReplyOK ("inbound port set");
else else
SendReplyError ("port out of range"); SendReplyError ("port out of range");
} }
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len) void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
{ {
@ -535,17 +535,17 @@ namespace client
} }
else else
SendReplyError ("no nickname has been set"); SendReplyError ("no nickname has been set");
} }
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len) void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: lookup ", operand); LogPrint (eLogDebug, "BOB: lookup ", operand);
i2p::data::IdentHash ident; i2p::data::IdentHash ident;
if (!context.GetAddressBook ().GetIdentHash (operand, ident)) if (!context.GetAddressBook ().GetIdentHash (operand, ident))
{ {
SendReplyError ("Address Not found"); SendReplyError ("Address Not found");
return; return;
} }
auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination (); auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
auto leaseSet = localDestination->FindLeaseSet (ident); auto leaseSet = localDestination->FindLeaseSet (ident);
if (leaseSet) if (leaseSet)
@ -553,14 +553,14 @@ namespace client
else else
{ {
auto s = shared_from_this (); auto s = shared_from_this ();
localDestination->RequestDestination (ident, localDestination->RequestDestination (ident,
[s](std::shared_ptr<i2p::data::LeaseSet> ls) [s](std::shared_ptr<i2p::data::LeaseSet> ls)
{ {
if (ls) if (ls)
s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ()); s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
else else
s->SendReplyError ("LeaseSet Not found"); s->SendReplyError ("LeaseSet Not found");
} }
); );
} }
} }
@ -571,7 +571,7 @@ namespace client
m_Owner.DeleteDestination (m_Nickname); m_Owner.DeleteDestination (m_Nickname);
m_Nickname = ""; m_Nickname = "";
SendReplyOK ("cleared"); SendReplyOK ("cleared");
} }
void BOBCommandSession::ListCommandHandler (const char * operand, size_t len) void BOBCommandSession::ListCommandHandler (const char * operand, size_t len)
{ {
@ -580,26 +580,26 @@ namespace client
for (const auto& it: destinations) for (const auto& it: destinations)
SendData (it.first.c_str ()); SendData (it.first.c_str ());
SendReplyOK ("Listing done"); SendReplyOK ("Listing done");
} }
void BOBCommandSession::OptionCommandHandler (const char * operand, size_t len) void BOBCommandSession::OptionCommandHandler (const char * operand, size_t len)
{ {
LogPrint (eLogDebug, "BOB: option ", operand); LogPrint (eLogDebug, "BOB: option ", operand);
const char * value = strchr (operand, '='); const char * value = strchr (operand, '=');
if (value) if (value)
{ {
std::string msg ("option "); std::string msg ("option ");
*(const_cast<char *>(value)) = 0; *(const_cast<char *>(value)) = 0;
m_Options[operand] = value + 1; m_Options[operand] = value + 1;
msg += operand; msg += operand;
*(const_cast<char *>(value)) = '='; *(const_cast<char *>(value)) = '=';
msg += " set to "; msg += " set to ";
msg += value; msg += value;
SendReplyOK (msg.c_str ()); SendReplyOK (msg.c_str ());
} }
else else
SendReplyError ("malformed"); SendReplyError ("malformed");
} }
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len) void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
{ {
@ -609,37 +609,37 @@ namespace client
std::stringstream s; std::stringstream s;
s << "DATA"; s << " NICKNAME: "; s << m_Nickname; s << "DATA"; s << " NICKNAME: "; s << m_Nickname;
if (m_CurrentDestination) if (m_CurrentDestination)
{ {
if (m_CurrentDestination->GetLocalDestination ()->IsReady ()) if (m_CurrentDestination->GetLocalDestination ()->IsReady ())
s << " STARTING: false RUNNING: true STOPPING: false"; s << " STARTING: false RUNNING: true STOPPING: false";
else else
s << " STARTING: true RUNNING: false STOPPING: false"; s << " STARTING: true RUNNING: false STOPPING: false";
} }
else else
s << " STARTING: false RUNNING: false STOPPING: false"; s << " STARTING: false RUNNING: false STOPPING: false";
s << " KEYS: true"; s << " QUIET: "; s << (m_IsQuiet ? "true":"false"); s << " KEYS: true"; s << " QUIET: "; s << (m_IsQuiet ? "true":"false");
if (m_InPort) if (m_InPort)
{ {
s << " INPORT: " << m_InPort; s << " INPORT: " << m_InPort;
s << " INHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1"); s << " INHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1");
} }
if (m_OutPort) if (m_OutPort)
{ {
s << " OUTPORT: " << m_OutPort; s << " OUTPORT: " << m_OutPort;
s << " OUTHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1"); s << " OUTHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1");
} }
SendReplyOK (s.str().c_str()); SendReplyOK (s.str().c_str());
} }
else else
SendReplyError ("no nickname has been set"); SendReplyError ("no nickname has been set");
} }
BOBCommandChannel::BOBCommandChannel (const std::string& address, int port): BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
m_IsRunning (false), m_Thread (nullptr), m_IsRunning (false), m_Thread (nullptr),
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port)) m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
{ {
// command -> handler // command -> handler
m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler; m_CommandHandlers[BOB_COMMAND_ZAP] = &BOBCommandSession::ZapCommandHandler;
m_CommandHandlers[BOB_COMMAND_QUIT] = &BOBCommandSession::QuitCommandHandler; m_CommandHandlers[BOB_COMMAND_QUIT] = &BOBCommandSession::QuitCommandHandler;
m_CommandHandlers[BOB_COMMAND_START] = &BOBCommandSession::StartCommandHandler; m_CommandHandlers[BOB_COMMAND_START] = &BOBCommandSession::StartCommandHandler;
m_CommandHandlers[BOB_COMMAND_STOP] = &BOBCommandSession::StopCommandHandler; m_CommandHandlers[BOB_COMMAND_STOP] = &BOBCommandSession::StopCommandHandler;
@ -680,35 +680,35 @@ namespace client
m_IsRunning = false; m_IsRunning = false;
for (auto& it: m_Destinations) for (auto& it: m_Destinations)
it.second->Stop (); it.second->Stop ();
m_Acceptor.cancel (); m_Acceptor.cancel ();
m_Service.stop (); m_Service.stop ();
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
delete m_Thread; delete m_Thread;
m_Thread = nullptr; m_Thread = nullptr;
} }
} }
void BOBCommandChannel::Run () void BOBCommandChannel::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, "BOB: runtime exception: ", ex.what ()); LogPrint (eLogError, "BOB: runtime exception: ", ex.what ());
} }
} }
} }
void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest) void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
{ {
m_Destinations[name] = dest; m_Destinations[name] = dest;
} }
void BOBCommandChannel::DeleteDestination (const std::string& name) void BOBCommandChannel::DeleteDestination (const std::string& name)
{ {
@ -718,17 +718,17 @@ namespace client
it->second->Stop (); it->second->Stop ();
delete it->second; delete it->second;
m_Destinations.erase (it); m_Destinations.erase (it);
} }
} }
BOBDestination * BOBCommandChannel::FindDestination (const std::string& name) BOBDestination * BOBCommandChannel::FindDestination (const std::string& name)
{ {
auto it = m_Destinations.find (name); auto it = m_Destinations.find (name);
if (it != m_Destinations.end ()) if (it != m_Destinations.end ())
return it->second; return it->second;
return nullptr; return nullptr;
} }
void BOBCommandChannel::Accept () void BOBCommandChannel::Accept ()
{ {
auto newSession = std::make_shared<BOBCommandSession> (*this); auto newSession = std::make_shared<BOBCommandSession> (*this);
@ -744,7 +744,7 @@ namespace client
if (!ecode) if (!ecode)
{ {
LogPrint (eLogInfo, "BOB: New command connection from ", session->GetSocket ().remote_endpoint ()); LogPrint (eLogInfo, "BOB: New command connection from ", session->GetSocket ().remote_endpoint ());
session->SendVersion (); session->SendVersion ();
} }
else else
LogPrint (eLogError, "BOB: accept error: ", ecode.message ()); LogPrint (eLogError, "BOB: accept error: ", ecode.message ());

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