mirror of
https://github.com/PurpleI2P/i2pd
synced 2024-11-09 15:50:26 +03:00
remove trailing whitespaces
This commit is contained in:
parent
b91efaa973
commit
46f62e1af9
@ -37,7 +37,7 @@
|
||||
|
||||
## [2.15.0] - 2017-08-17
|
||||
### Added
|
||||
- QT GUI
|
||||
- QT GUI
|
||||
- Ability to add and remove I2P tunnels without restart
|
||||
- Ability to disable SOCKS outproxy option
|
||||
### Changed
|
||||
@ -81,7 +81,7 @@
|
||||
- Some stats in a main window for Windows version
|
||||
### Changed
|
||||
- Reseed servers list
|
||||
- MTU of 1488 for ipv6
|
||||
- MTU of 1488 for ipv6
|
||||
- Android and Mac OS X versions use OpenSSL 1.1
|
||||
- New logo for Android
|
||||
### Fixed
|
||||
@ -111,7 +111,7 @@
|
||||
## [2.10.2] - 2016-12-04
|
||||
### Fixed
|
||||
- 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
|
||||
### Fixed
|
||||
|
@ -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.
|
||||
#
|
||||
|
||||
# 1. install deps, clone and build.
|
||||
# 2. strip binaries.
|
||||
# 3. Purge all dependencies and other unrelated packages, including build directory.
|
||||
# 1. install deps, clone and build.
|
||||
# 2. strip binaries.
|
||||
# 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 \
|
||||
&& mkdir -p /tmp/build \
|
||||
&& cd /tmp/build && git clone -b ${GIT_BRANCH} https://github.com/PurpleI2P/i2pd.git \
|
||||
|
@ -4,7 +4,7 @@ BOOSTROOT = ${BREWROOT}/opt/boost
|
||||
SSLROOT = ${BREWROOT}/opt/libressl
|
||||
UPNPROOT = ${BREWROOT}/opt/miniupnpc
|
||||
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
|
||||
CXX = clang++
|
||||
|
@ -12,7 +12,7 @@ INCFLAGS ?=
|
||||
# detect proper flag for c++11 support by compilers
|
||||
CXXVER := $(shell $(CXX) -dumpversion)
|
||||
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
|
||||
NEEDED_CXXFLAGS += -std=c++11
|
||||
else ifeq ($(shell expr match ${CXXVER} "4\.[7-9]"),3) # >= 4.7
|
||||
|
@ -1,7 +1,7 @@
|
||||
CXX = clang++
|
||||
CXXFLAGS = -Os -Wall -std=c++11 -DMAC_OSX
|
||||
#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
|
||||
|
||||
ifeq ($(USE_STATIC),yes)
|
||||
|
34
README.md
34
README.md
@ -5,13 +5,13 @@ i2pd
|
||||
|
||||
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
|
||||
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
|
||||
networks. Such networks are commonly used for anonymous peer-to-peer
|
||||
applications (filesharing, cryptocurrencies) and anonymous client-server
|
||||
I2P client is a software used for building and using anonymous I2P
|
||||
networks. Such networks are commonly used for anonymous peer-to-peer
|
||||
applications (filesharing, cryptocurrencies) and anonymous client-server
|
||||
applications (websites, instant messengers, chat-servers).
|
||||
|
||||
I2P allows people from all around the world to communicate and share information
|
||||
@ -38,9 +38,9 @@ Resources
|
||||
Installing
|
||||
----------
|
||||
|
||||
The easiest way to install i2pd is by using
|
||||
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
|
||||
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
|
||||
The easiest way to install i2pd is by using
|
||||
[precompiled binaries](https://github.com/PurpleI2P/i2pd/releases/latest).
|
||||
See [documentation](https://i2pd.readthedocs.io/en/latest/) for how to build
|
||||
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)
|
||||
* Mac OS X - [![Build Status](https://travis-ci.org/PurpleI2P/i2pd.svg?branch=openssl)](https://travis-ci.org/PurpleI2P/i2pd)
|
||||
* FreeBSD
|
||||
* Android
|
||||
* Android
|
||||
* iOS
|
||||
|
||||
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).
|
||||
|
||||
Donations
|
||||
---------
|
||||
|
||||
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
|
||||
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
|
||||
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
|
||||
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
||||
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
|
||||
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
|
||||
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
|
||||
BTC: 1K7Ds6KUeR8ya287UC4rYTjvC96vXyZbDY
|
||||
ZEC: t1cTckLuXsr1dwVrK4NDzfhehss4NvMadAJ
|
||||
DASH: Xw8YUrQpYzP9tZBmbjqxS3M97Q7v3vJKUF
|
||||
LTC: LKQirrYrDeTuAPnpYq5y7LVKtywfkkHi59
|
||||
DOGE: DNXLQKziRPAsD9H3DFNjk4fLQrdaSX893Y
|
||||
ANC: AQJYweYYUqM1nVfLqfoSMpUMfzxvS4Xd7z
|
||||
GST: GbD2JSQHBHCKLa9WTHmigJRpyFgmBj4woG
|
||||
|
||||
License
|
||||
-------
|
||||
|
@ -23,4 +23,4 @@
|
||||
</activity>
|
||||
<service android:enabled="true" android:name=".ForegroundService"/>
|
||||
</application>
|
||||
</manifest>
|
||||
</manifest>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<menu
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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">
|
||||
<item
|
||||
android:id="@+id/action_graceful_quit"
|
||||
|
@ -14,10 +14,10 @@ public class DaemonSingleton {
|
||||
public static DaemonSingleton getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
|
||||
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
|
||||
|
||||
|
||||
public synchronized void stopAcceptingTunnels() {
|
||||
if(isStartedOkay()){
|
||||
state=State.gracefulShutdownInProgress;
|
||||
@ -25,19 +25,19 @@ public class DaemonSingleton {
|
||||
I2PD_JNI.stopAcceptingTunnels();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void onNetworkStateChange(boolean isConnected) {
|
||||
I2PD_JNI.onNetworkStateChanged(isConnected);
|
||||
}
|
||||
|
||||
|
||||
private boolean startedOkay;
|
||||
|
||||
public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress};
|
||||
|
||||
|
||||
private State state = State.uninitialized;
|
||||
|
||||
|
||||
public State getState() { return state; }
|
||||
|
||||
|
||||
public synchronized void start() {
|
||||
if(state != State.uninitialized)return;
|
||||
state = State.starting;
|
||||
@ -76,9 +76,9 @@ public class DaemonSingleton {
|
||||
fireStateUpdate();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}, "i2pdDaemonStart").start();
|
||||
}
|
||||
private Throwable lastThrowable;
|
||||
@ -87,10 +87,10 @@ public class DaemonSingleton {
|
||||
private synchronized void fireStateUpdate() {
|
||||
Log.i(TAG, "daemon state change: "+state);
|
||||
for(StateUpdateListener listener : stateUpdateListeners) {
|
||||
try {
|
||||
listener.daemonStateUpdate();
|
||||
} catch (Throwable tr) {
|
||||
Log.e(TAG, "exception in listener ignored", tr);
|
||||
try {
|
||||
listener.daemonStateUpdate();
|
||||
} catch (Throwable tr) {
|
||||
Log.e(TAG, "exception in listener ignored", tr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,7 +102,7 @@ public class DaemonSingleton {
|
||||
public String getDaemonStartResult() {
|
||||
return daemonStartResult;
|
||||
}
|
||||
|
||||
|
||||
private final Object startedOkayLock = new Object();
|
||||
|
||||
public boolean isStartedOkay() {
|
||||
|
@ -50,7 +50,7 @@ public class ForegroundService extends Service {
|
||||
public void onDestroy() {
|
||||
// Cancel the persistent notification.
|
||||
notificationManager.cancel(NOTIFICATION);
|
||||
|
||||
|
||||
stopForeground(true);
|
||||
|
||||
// Tell the user we stopped.
|
||||
@ -91,7 +91,7 @@ public class ForegroundService extends Service {
|
||||
//mNM.notify(NOTIFICATION, notification);
|
||||
startForeground(NOTIFICATION, notification);
|
||||
}
|
||||
|
||||
|
||||
private final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,12 @@ public class I2PD extends Activity {
|
||||
private static final String TAG = "i2pd";
|
||||
|
||||
private TextView textView;
|
||||
|
||||
|
||||
private final DaemonSingleton daemon = DaemonSingleton.getInstance();
|
||||
|
||||
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
|
||||
|
||||
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
|
||||
new DaemonSingleton.StateUpdateListener() {
|
||||
|
||||
|
||||
@Override
|
||||
public void daemonStateUpdate() {
|
||||
runOnUiThread(new Runnable(){
|
||||
@ -53,7 +53,7 @@ public class I2PD extends Activity {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@ -123,7 +123,7 @@ public class I2PD extends Activity {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
private boolean mIsBound;
|
||||
|
||||
private void doBindService() {
|
||||
@ -147,7 +147,7 @@ public class I2PD extends Activity {
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -216,9 +216,9 @@ public class I2PD extends Activity {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
quit();
|
||||
quit();
|
||||
}
|
||||
|
||||
|
||||
}, 10*60*1000/*milliseconds*/);
|
||||
}else{
|
||||
quit();
|
||||
@ -227,7 +227,7 @@ public class I2PD extends Activity {
|
||||
Log.e(TAG,"",tr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},"gracQuitInit").start();
|
||||
}
|
||||
|
||||
|
@ -9,9 +9,9 @@ public class I2PD_JNI {
|
||||
public static native String startDaemon();
|
||||
//should only be called after startDaemon() success
|
||||
public static native void stopDaemon();
|
||||
|
||||
|
||||
public static native void stopAcceptingTunnels();
|
||||
|
||||
|
||||
public static native void onNetworkStateChanged(boolean isConnected);
|
||||
|
||||
public static void loadLibraries() {
|
||||
|
@ -24,5 +24,5 @@ else()
|
||||
endif()
|
||||
|
||||
mark_as_advanced(MINIUPNPC_INCLUDE_DIR MINIUPNPC_LIBRARY)
|
||||
|
||||
|
||||
endif()
|
||||
|
@ -5,7 +5,7 @@ RUN apt-get update && apt-get install -y libboost-dev libboost-filesystem-dev \
|
||||
libssl-dev git build-essential
|
||||
|
||||
RUN git clone https://github.com/PurpleI2P/i2pd.git
|
||||
WORKDIR /i2pd
|
||||
WORKDIR /i2pd
|
||||
RUN make
|
||||
|
||||
CMD ./i2pd
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Basic profile for i2pd
|
||||
# Basic profile for i2pd
|
||||
# Should work without modifications with Ubuntu/Debian packages
|
||||
# Author: Darknet Villain <supervillain@riseup.net>
|
||||
#
|
||||
|
@ -17,13 +17,13 @@ RUN mkdir -p "$I2PD_HOME" "$DATA_DIR" \
|
||||
&& 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.
|
||||
#
|
||||
|
||||
# 1. install deps, clone and build.
|
||||
# 2. strip binaries.
|
||||
# 3. Purge all dependencies and other unrelated packages, including build directory.
|
||||
# 1. install deps, clone and build.
|
||||
# 2. strip binaries.
|
||||
# 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 \
|
||||
&& mkdir -p /tmp/build \
|
||||
&& cd /tmp/build && git clone -b ${GIT_BRANCH} ${REPO_URL} \
|
||||
|
@ -54,7 +54,7 @@ ipv4 = true
|
||||
ipv6 = false
|
||||
|
||||
## Network interface to bind to
|
||||
# ifname =
|
||||
# ifname =
|
||||
|
||||
## Enable NTCP transport (default = true)
|
||||
# ntcp = true
|
||||
@ -88,18 +88,18 @@ ipv6 = false
|
||||
|
||||
[upnp]
|
||||
## 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
|
||||
|
||||
[reseed]
|
||||
## Enable or disable reseed data verification.
|
||||
## Enable or disable reseed data verification.
|
||||
verify = true
|
||||
## URLs to request reseed data from, separated by comma
|
||||
## Default: "mainline" I2P Network reseeds
|
||||
# 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
|
||||
## or HTTPS URL to reseed from
|
||||
# file = https://legit-website.com/i2pseeds.su3
|
||||
|
@ -48,7 +48,7 @@ using dedicated user's permissions.
|
||||
|
||||
%build
|
||||
cd build
|
||||
%if 0%{?rhel} == 7
|
||||
%if 0%{?rhel} == 7
|
||||
%cmake3 \
|
||||
-DWITH_LIBRARY=OFF \
|
||||
-DWITH_UPNP=ON \
|
||||
@ -133,7 +133,7 @@ getent passwd i2pd >/dev/null || \
|
||||
- Fixed QT GUI issues
|
||||
|
||||
* 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 to disable SOCKS outproxy option
|
||||
- Changed strip-out Accept-* hedaers in HTTP proxy
|
||||
|
@ -123,7 +123,7 @@ namespace i2p
|
||||
LogPrint(eLogInfo, "AESNI enabled");
|
||||
#endif
|
||||
#if defined(__AVX__)
|
||||
LogPrint(eLogInfo, "AVX enabled");
|
||||
LogPrint(eLogInfo, "AVX enabled");
|
||||
#endif
|
||||
LogPrint(eLogDebug, "FS: main config file: ", config);
|
||||
LogPrint(eLogDebug, "FS: data directory: ", datadir);
|
||||
|
@ -505,7 +505,7 @@ namespace http {
|
||||
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
|
||||
#endif
|
||||
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 << " <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> ";
|
||||
|
@ -10,12 +10,12 @@
|
||||
#include <sstream>
|
||||
#include "HTTP.h"
|
||||
|
||||
namespace i2p
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
namespace http
|
||||
{
|
||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
|
||||
const size_t HTTP_CONNECTION_BUFFER_SIZE = 8192;
|
||||
const int TOKEN_EXPIRATION_TIMEOUT = 30; // in seconds
|
||||
|
||||
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);
|
||||
void Receive ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
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,
|
||||
std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
|
||||
void CreateConnection(std::shared_ptr<boost::asio::ip::tcp::socket> newSocket);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
bool m_IsRunning;
|
||||
|
@ -67,7 +67,7 @@ namespace client
|
||||
m_MethodHandlers["NetworkSetting"] = &I2PControlService::NetworkSettingHandler;
|
||||
|
||||
// I2PControl
|
||||
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
|
||||
m_I2PControlHandlers["i2pcontrol.password"] = &I2PControlService::PasswordHandler;
|
||||
|
||||
// RouterInfo
|
||||
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.tunnels.participating"] = &I2PControlService::TunnelsParticipatingHandler;
|
||||
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.sent.bytes"] = &I2PControlService::NetTotalSentBytes;
|
||||
|
||||
// RouterManager
|
||||
// RouterManager
|
||||
m_RouterManagerHandlers["Reseed"] = &I2PControlService::ReseedHandler;
|
||||
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
|
||||
m_RouterManagerHandlers["Shutdown"] = &I2PControlService::ShutdownHandler;
|
||||
m_RouterManagerHandlers["ShutdownGraceful"] = &I2PControlService::ShutdownGracefulHandler;
|
||||
|
||||
// NetworkSetting
|
||||
@ -133,8 +133,8 @@ namespace client
|
||||
m_Service.run ();
|
||||
} catch (std::exception& ex) {
|
||||
LogPrint (eLogError, "I2PControl: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void I2PControlService::Accept ()
|
||||
@ -168,7 +168,7 @@ namespace client
|
||||
if (ecode) {
|
||||
LogPrint (eLogError, "I2PControl: handshake error: ", ecode.message ());
|
||||
return;
|
||||
}
|
||||
}
|
||||
//std::this_thread::sleep_for (std::chrono::milliseconds(5));
|
||||
ReadRequest (socket);
|
||||
}
|
||||
@ -190,12 +190,12 @@ namespace client
|
||||
size_t bytes_transferred, std::shared_ptr<ssl_socket> socket,
|
||||
std::shared_ptr<I2PControlBuffer> buf)
|
||||
{
|
||||
if (ecode)
|
||||
if (ecode)
|
||||
{
|
||||
LogPrint (eLogError, "I2PControl: read error: ", ecode.message ());
|
||||
return;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isHtml = !memcmp (buf->data (), "POST", 4);
|
||||
try
|
||||
@ -243,8 +243,8 @@ namespace client
|
||||
response << "{\"id\":" << id << ",\"result\":{";
|
||||
(this->*(it->second))(pt.get_child ("params"), response);
|
||||
response << "},\"jsonrpc\":\"2.0\"}";
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "I2PControl: unknown method ", method);
|
||||
response << "{\"id\":null,\"error\":";
|
||||
@ -337,9 +337,9 @@ namespace client
|
||||
InsertParam (results, "API", api);
|
||||
results << ",";
|
||||
std::string token = boost::lexical_cast<std::string>(i2p::util::GetSecondsSinceEpoch ());
|
||||
m_Tokens.insert (token);
|
||||
m_Tokens.insert (token);
|
||||
InsertParam (results, "Token", token);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PControlService::EchoHandler (const boost::property_tree::ptree& params, std::ostringstream& results)
|
||||
{
|
||||
@ -364,7 +364,7 @@ namespace client
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "I2PControl: I2PControl unknown request: ", it.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void I2PControlService::PasswordHandler (const std::string& value)
|
||||
@ -394,28 +394,28 @@ namespace client
|
||||
|
||||
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)
|
||||
{
|
||||
InsertParam (results, "i2p.router.version", VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
void I2PControlService::StatusHandler (std::ostringstream& results)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -463,11 +463,11 @@ namespace client
|
||||
{
|
||||
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);
|
||||
auto it1 = m_RouterManagerHandlers.find (it->first);
|
||||
if (it1 != m_RouterManagerHandlers.end ()) {
|
||||
(this->*(it1->second))(results);
|
||||
(this->*(it1->second))(results);
|
||||
} else
|
||||
LogPrint (eLogError, "I2PControl: RouterManager unknown request: ", it->first);
|
||||
}
|
||||
@ -516,7 +516,7 @@ namespace client
|
||||
auto it1 = m_NetworkSettingHandlers.find (it->first);
|
||||
if (it1 != m_NetworkSettingHandlers.end ()) {
|
||||
if (it != params.begin ()) results << ",";
|
||||
(this->*(it1->second))(it->second.data (), results);
|
||||
(this->*(it1->second))(it->second.data (), results);
|
||||
} else
|
||||
LogPrint (eLogError, "I2PControl: NetworkSetting unknown request: ", it->first);
|
||||
}
|
||||
@ -538,7 +538,7 @@ namespace client
|
||||
InsertParam (results, "i2p.router.net.bw.out", bw);
|
||||
}
|
||||
|
||||
// certificate
|
||||
// certificate
|
||||
void I2PControlService::CreateCertificate (const char *crt_path, const char *key_path)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
namespace i2p
|
||||
|
@ -42,13 +42,13 @@ namespace transport
|
||||
std::string GetProto (std::shared_ptr<i2p::data::RouterInfo::Address> address);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
bool m_IsRunning;
|
||||
std::unique_ptr<std::thread> m_Thread;
|
||||
std::condition_variable m_Started;
|
||||
std::mutex m_StartedMutex;
|
||||
std::condition_variable m_Started;
|
||||
std::mutex m_StartedMutex;
|
||||
boost::asio::io_service m_Service;
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
boost::asio::deadline_timer m_Timer;
|
||||
struct UPNPUrls m_upnpUrls;
|
||||
struct IGDdatas m_upnpData;
|
||||
|
||||
|
@ -163,7 +163,7 @@ namespace i2p
|
||||
sigaction(SIGABRT, &sa, 0);
|
||||
sigaction(SIGTERM, &sa, 0);
|
||||
sigaction(SIGINT, &sa, 0);
|
||||
sigaction(SIGPIPE, &sa, 0);
|
||||
sigaction(SIGPIPE, &sa, 0);
|
||||
|
||||
return Daemon_Singleton::start();
|
||||
}
|
||||
|
4
debian/changelog
vendored
4
debian/changelog
vendored
@ -62,7 +62,7 @@ i2pd (2.10.0-1) unstable; urgency=low
|
||||
|
||||
* updated to version 2.10.0/0.9.27
|
||||
* reseed.verify set to true by default
|
||||
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Sun, 16 Oct 2016 13:55:40 +0000
|
||||
|
||||
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
|
||||
* fixed logrotate
|
||||
* subscriptions.txt and tunnels.conf taken from docs folder
|
||||
|
||||
|
||||
-- orignal <orignal@i2pmail.org> Fri, 12 Aug 2016 14:25:40 +0000
|
||||
|
||||
i2pd (2.7.0-1) unstable; urgency=low
|
||||
|
2
debian/i2pd.default
vendored
2
debian/i2pd.default
vendored
@ -7,5 +7,5 @@ I2PD_ENABLED="yes"
|
||||
# see possible switches in /usr/share/doc/i2pd/configuration.md.gz
|
||||
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
|
||||
|
5
debian/patches/01-tune-build-opts.patch
vendored
5
debian/patches/01-tune-build-opts.patch
vendored
@ -1,12 +1,11 @@
|
||||
diff --git a/Makefile b/Makefile
|
||||
index bdadfe0..2f71eec 100644
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -9,10 +9,10 @@ DEPS := obj/make.dep
|
||||
|
||||
|
||||
include filelist.mk
|
||||
|
||||
|
||||
-USE_AESNI := yes
|
||||
+USE_AESNI := no
|
||||
-USE_AVX := yes
|
||||
|
@ -43,8 +43,8 @@ namespace data
|
||||
const char * GetBase64SubstitutionTable ()
|
||||
{
|
||||
return T64;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse Substitution Table (built in run time)
|
||||
*/
|
||||
@ -53,10 +53,10 @@ namespace data
|
||||
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 */
|
||||
ByteStreamToBase64 (
|
||||
ByteStreamToBase64 (
|
||||
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 */
|
||||
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 acc_1;
|
||||
unsigned char acc_2;
|
||||
int i;
|
||||
int n;
|
||||
int m;
|
||||
int i;
|
||||
int n;
|
||||
int m;
|
||||
size_t outCount;
|
||||
|
||||
ps = (unsigned char *)InBuffer;
|
||||
@ -96,7 +96,7 @@ namespace data
|
||||
pd = (unsigned char *)OutBuffer;
|
||||
for ( i = 0; i<n; i++ ){
|
||||
acc_1 = *ps++;
|
||||
acc_2 = (acc_1<<4)&0x30;
|
||||
acc_2 = (acc_1<<4)&0x30;
|
||||
acc_1 >>= 2; /* base64 digit #1 */
|
||||
*pd++ = T64[acc_1];
|
||||
acc_1 = *ps++;
|
||||
@ -109,7 +109,7 @@ namespace data
|
||||
*pd++ = T64[acc_1];
|
||||
acc_2 &= 0x3f; /* base64 digit #4 */
|
||||
*pd++ = T64[acc_2];
|
||||
}
|
||||
}
|
||||
if ( m == 1 ){
|
||||
acc_1 = *ps++;
|
||||
acc_2 = (acc_1<<4)&0x3f; /* base64 digit #2 */
|
||||
@ -122,7 +122,7 @@ namespace data
|
||||
}
|
||||
else if ( m == 2 ){
|
||||
acc_1 = *ps++;
|
||||
acc_2 = (acc_1<<4)&0x3f;
|
||||
acc_2 = (acc_1<<4)&0x3f;
|
||||
acc_1 >>= 2; /* base64 digit #1 */
|
||||
*pd++ = T64[acc_1];
|
||||
acc_1 = *ps++;
|
||||
@ -133,7 +133,7 @@ namespace data
|
||||
*pd++ = T64[acc_1];
|
||||
*pd++ = P64;
|
||||
}
|
||||
|
||||
|
||||
return outCount;
|
||||
}
|
||||
|
||||
@ -148,10 +148,10 @@ namespace data
|
||||
*/
|
||||
|
||||
size_t /* Number of output bytes */
|
||||
Base64ToByteStream (
|
||||
Base64ToByteStream (
|
||||
const char * InBuffer, /* BASE64 encoded buffer */
|
||||
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 */
|
||||
)
|
||||
{
|
||||
@ -159,28 +159,28 @@ namespace data
|
||||
unsigned char * pd;
|
||||
unsigned char acc_1;
|
||||
unsigned char acc_2;
|
||||
int i;
|
||||
int n;
|
||||
int m;
|
||||
int i;
|
||||
int n;
|
||||
int m;
|
||||
size_t outCount;
|
||||
|
||||
if (isFirstTime) iT64Build();
|
||||
n = InCount/4;
|
||||
m = InCount%4;
|
||||
if (InCount && !m)
|
||||
if (InCount && !m)
|
||||
outCount = 3*n;
|
||||
else {
|
||||
outCount = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ps = (unsigned char *)(InBuffer + InCount - 1);
|
||||
while ( *ps-- == P64 ) outCount--;
|
||||
ps = (unsigned char *)InBuffer;
|
||||
|
||||
|
||||
if (outCount > len) return -1;
|
||||
pd = OutBuffer;
|
||||
auto endOfOutBuffer = OutBuffer + outCount;
|
||||
auto endOfOutBuffer = OutBuffer + outCount;
|
||||
for ( i = 0; i < n; i++ ){
|
||||
acc_1 = iT64[*ps++];
|
||||
acc_2 = iT64[*ps++];
|
||||
@ -193,7 +193,7 @@ namespace data
|
||||
acc_1 = iT64[*ps++];
|
||||
acc_2 |= acc_1 >> 2;
|
||||
*pd++ = acc_2;
|
||||
if (pd >= endOfOutBuffer) break;
|
||||
if (pd >= endOfOutBuffer) break;
|
||||
|
||||
acc_2 = iT64[*ps++];
|
||||
acc_2 |= acc_1 << 6;
|
||||
@ -203,13 +203,13 @@ namespace data
|
||||
return outCount;
|
||||
}
|
||||
|
||||
size_t Base64EncodingBufferSize (const size_t input_size)
|
||||
size_t Base64EncodingBufferSize (const size_t input_size)
|
||||
{
|
||||
auto d = div (input_size, 3);
|
||||
if (d.rem) d.quot++;
|
||||
return 4*d.quot;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* iT64
|
||||
@ -228,20 +228,20 @@ namespace data
|
||||
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;
|
||||
size_t ret = 0;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
char ch = inBuf[i];
|
||||
char ch = inBuf[i];
|
||||
if (ch >= '2' && ch <= '7') // digit
|
||||
ch = (ch - '2') + 26; // 26 means a-z
|
||||
else if (ch >= 'a' && ch <= 'z')
|
||||
ch = ch - 'a'; // a = 0
|
||||
else
|
||||
return 0; // unexpected character
|
||||
|
||||
|
||||
tmp |= ch;
|
||||
bits += 5;
|
||||
if (bits >= 8)
|
||||
@ -261,7 +261,7 @@ namespace data
|
||||
size_t ret = 0, pos = 1;
|
||||
int bits = 8, tmp = inBuf[0];
|
||||
while (ret < outLen && (bits > 0 || pos < len))
|
||||
{
|
||||
{
|
||||
if (bits < 5)
|
||||
{
|
||||
if (pos < len)
|
||||
@ -276,8 +276,8 @@ namespace data
|
||||
tmp <<= (5 - bits);
|
||||
bits = 5;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bits -= 5;
|
||||
int ind = (tmp >> bits) & 0x1F;
|
||||
outBuf[ret] = (ind < 26) ? (ind + 'a') : ((ind - 26) + '2');
|
||||
|
@ -10,8 +10,8 @@ namespace data {
|
||||
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 );
|
||||
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 ByteStreamToBase32 (const uint8_t * InBuf, size_t len, char * outBuf, size_t outLen);
|
||||
|
||||
|
@ -79,10 +79,10 @@ namespace config {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetOptionAsAny(const char *name, boost::any& value);
|
||||
bool GetOptionAsAny(const std::string& name, boost::any& value);
|
||||
|
160
libi2pd/Crypto.h
160
libi2pd/Crypto.h
@ -24,7 +24,7 @@ namespace crypto
|
||||
bool bn2buf (const BIGNUM * bn, uint8_t * buf, size_t len);
|
||||
|
||||
// DSA
|
||||
DSA * CreateDSA ();
|
||||
DSA * CreateDSA ();
|
||||
|
||||
// RSA
|
||||
const BIGNUM * GetRSAE ();
|
||||
@ -33,20 +33,20 @@ namespace crypto
|
||||
class DHKeys
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
DHKeys ();
|
||||
~DHKeys ();
|
||||
|
||||
void GenerateKeys ();
|
||||
const uint8_t * GetPublicKey () const { return m_PublicKey; };
|
||||
void Agree (const uint8_t * pub, uint8_t * shared);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
DH * m_DH;
|
||||
uint8_t m_PublicKey[256];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// ElGamal
|
||||
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);
|
||||
@ -54,15 +54,15 @@ namespace crypto
|
||||
|
||||
// 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
|
||||
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);
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// AES
|
||||
struct ChipherBlock
|
||||
struct ChipherBlock
|
||||
{
|
||||
uint8_t buf[16];
|
||||
|
||||
@ -71,40 +71,40 @@ namespace crypto
|
||||
#if defined(__AVX__) // AVX
|
||||
__asm__
|
||||
(
|
||||
"vmovups (%[buf]), %%xmm0 \n"
|
||||
"vmovups (%[other]), %%xmm1 \n"
|
||||
"vmovups (%[buf]), %%xmm0 \n"
|
||||
"vmovups (%[other]), %%xmm1 \n"
|
||||
"vxorps %%xmm0, %%xmm1, %%xmm0 \n"
|
||||
"vmovups %%xmm0, (%[buf]) \n"
|
||||
:
|
||||
: [buf]"r"(buf), [other]"r"(other.buf)
|
||||
"vmovups %%xmm0, (%[buf]) \n"
|
||||
:
|
||||
: [buf]"r"(buf), [other]"r"(other.buf)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
);
|
||||
#elif defined(__SSE__) // SSE
|
||||
__asm__
|
||||
(
|
||||
"movups (%[buf]), %%xmm0 \n"
|
||||
"movups (%[other]), %%xmm1 \n"
|
||||
"movups (%[buf]), %%xmm0 \n"
|
||||
"movups (%[other]), %%xmm1 \n"
|
||||
"pxor %%xmm1, %%xmm0 \n"
|
||||
"movups %%xmm0, (%[buf]) \n"
|
||||
:
|
||||
: [buf]"r"(buf), [other]"r"(other.buf)
|
||||
:
|
||||
: [buf]"r"(buf), [other]"r"(other.buf)
|
||||
: "%xmm0", "%xmm1", "memory"
|
||||
);
|
||||
);
|
||||
#else
|
||||
// TODO: implement it better
|
||||
for (int i = 0; i < 16; i++)
|
||||
buf[i] ^= other.buf[i];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef i2p::data::Tag<32> AESKey;
|
||||
|
||||
|
||||
template<size_t sz>
|
||||
class AESAlignedBuffer // 16 bytes alignment
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
AESAlignedBuffer ()
|
||||
{
|
||||
m_Buf = m_UnalignedBuffer;
|
||||
@ -112,22 +112,22 @@ namespace crypto
|
||||
if (rem)
|
||||
m_Buf += (16 - rem);
|
||||
}
|
||||
|
||||
|
||||
operator uint8_t * () { return m_Buf; };
|
||||
operator const uint8_t * () const { return m_Buf; };
|
||||
ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; };
|
||||
const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment
|
||||
uint8_t * m_Buf;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#ifdef AESNI
|
||||
class ECBCryptoAESNI
|
||||
{
|
||||
{
|
||||
public:
|
||||
|
||||
uint8_t * GetKeySchedule () { return m_KeySchedule; };
|
||||
@ -135,27 +135,27 @@ namespace crypto
|
||||
protected:
|
||||
|
||||
void ExpandKey (const AESKey& key);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
AESAlignedBuffer<240> m_KeySchedule; // 14 rounds for AES-256, 240 bytes
|
||||
};
|
||||
};
|
||||
|
||||
class ECBEncryptionAESNI: public ECBCryptoAESNI
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
void SetKey (const AESKey& key);
|
||||
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
|
||||
};
|
||||
void Decrypt (const ChipherBlock * in, ChipherBlock * out);
|
||||
};
|
||||
|
||||
typedef ECBEncryptionAESNI ECBEncryption;
|
||||
typedef ECBDecryptionAESNI ECBDecryption;
|
||||
@ -165,46 +165,46 @@ namespace crypto
|
||||
class ECBEncryption
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey (const AESKey& key)
|
||||
{
|
||||
|
||||
void SetKey (const AESKey& key)
|
||||
{
|
||||
AES_set_encrypt_key (key, 256, &m_Key);
|
||||
}
|
||||
void Encrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
AES_encrypt (in->buf, out->buf, &m_Key);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
AES_KEY m_Key;
|
||||
};
|
||||
};
|
||||
|
||||
class ECBDecryption
|
||||
{
|
||||
public:
|
||||
|
||||
void SetKey (const AESKey& key)
|
||||
{
|
||||
AES_set_decrypt_key (key, 256, &m_Key);
|
||||
|
||||
void SetKey (const AESKey& key)
|
||||
{
|
||||
AES_set_decrypt_key (key, 256, &m_Key);
|
||||
}
|
||||
void Decrypt (const ChipherBlock * in, ChipherBlock * out)
|
||||
{
|
||||
AES_decrypt (in->buf, out->buf, &m_Key);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
AES_KEY m_Key;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class CBCEncryption
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); };
|
||||
|
||||
void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes
|
||||
@ -217,14 +217,14 @@ namespace crypto
|
||||
private:
|
||||
|
||||
AESAlignedBuffer<16> m_LastBlock;
|
||||
|
||||
|
||||
ECBEncryption m_ECBEncryption;
|
||||
};
|
||||
|
||||
class CBCDecryption
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); };
|
||||
|
||||
void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes
|
||||
@ -238,7 +238,7 @@ namespace crypto
|
||||
|
||||
AESAlignedBuffer<16> m_IV;
|
||||
ECBDecryption m_ECBDecryption;
|
||||
};
|
||||
};
|
||||
|
||||
class TunnelEncryption // with double IV encryption
|
||||
{
|
||||
@ -248,9 +248,9 @@ namespace crypto
|
||||
{
|
||||
m_LayerEncryption.SetKey (layerKey);
|
||||
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:
|
||||
|
||||
@ -270,9 +270,9 @@ namespace crypto
|
||||
{
|
||||
m_LayerDecryption.SetKey (layerKey);
|
||||
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:
|
||||
|
||||
@ -282,72 +282,72 @@ namespace crypto
|
||||
#else
|
||||
CBCDecryption m_LayerDecryption;
|
||||
#endif
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
void InitCrypto (bool precomputation);
|
||||
void TerminateCrypto ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// take care about openssl version
|
||||
#include <openssl/opensslv.h>
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x010100000) || defined(LIBRESSL_VERSION_NUMBER) // 1.1.0 or LibreSSL
|
||||
// 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->q) BN_free (d->q);
|
||||
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->priv_key) BN_free (d->priv_key);
|
||||
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)
|
||||
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)
|
||||
{ *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->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; }
|
||||
|
||||
inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
|
||||
{
|
||||
{
|
||||
if (sig->r) BN_free (sig->r);
|
||||
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)
|
||||
{ *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->e) BN_free (r->e);
|
||||
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)
|
||||
{ *n = r->n; *e = r->e; *d = r->d; }
|
||||
|
||||
inline int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
||||
{
|
||||
{
|
||||
if (dh->p) BN_free (dh->p);
|
||||
if (dh->q) BN_free (dh->q);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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)
|
||||
{ *pub_key = dh->pub_key; *priv_key = dh->priv_key; }
|
||||
|
@ -72,7 +72,7 @@ namespace crypto
|
||||
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
EC_GROUP * curve = EC_GROUP_new_by_curve_name (NID_X9_62_prime256v1);
|
||||
EC_POINT * p = nullptr;
|
||||
EC_POINT * p = nullptr;
|
||||
BIGNUM * key = nullptr;
|
||||
GenerateECIESKeyPair (curve, key, p);
|
||||
bn2buf (key, priv, 32);
|
||||
@ -81,11 +81,11 @@ namespace crypto
|
||||
BIGNUM * x = BN_new (), * y = BN_new ();
|
||||
EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, NULL);
|
||||
bn2buf (x, pub, 32);
|
||||
bn2buf (y, pub + 32, 32);
|
||||
bn2buf (y, pub + 32, 32);
|
||||
RAND_bytes (pub + 64, 192);
|
||||
EC_POINT_free (p);
|
||||
EC_POINT_free (p);
|
||||
BN_free (x); BN_free (y);
|
||||
EC_GROUP_free (curve);
|
||||
EC_GROUP_free (curve);
|
||||
}
|
||||
|
||||
ECIESGOSTR3410Encryptor::ECIESGOSTR3410Encryptor (const uint8_t * pub)
|
||||
@ -131,7 +131,7 @@ namespace crypto
|
||||
void CreateECIESGOSTR3410RandomKeys (uint8_t * priv, uint8_t * pub)
|
||||
{
|
||||
auto& curve = GetGOSTR3410Curve (eGOSTR3410CryptoProA);
|
||||
EC_POINT * p = nullptr;
|
||||
EC_POINT * p = nullptr;
|
||||
BIGNUM * key = nullptr;
|
||||
GenerateECIESKeyPair (curve->GetGroup (), key, p);
|
||||
bn2buf (key, priv, 32);
|
||||
@ -140,9 +140,9 @@ namespace crypto
|
||||
BIGNUM * x = BN_new (), * y = BN_new ();
|
||||
EC_POINT_get_affine_coordinates_GFp (curve->GetGroup (), p, x, y, NULL);
|
||||
bn2buf (x, pub, 32);
|
||||
bn2buf (y, pub + 32, 32);
|
||||
bn2buf (y, pub + 32, 32);
|
||||
RAND_bytes (pub + 64, 192);
|
||||
EC_POINT_free (p);
|
||||
EC_POINT_free (p);
|
||||
BN_free (x); BN_free (y);
|
||||
}
|
||||
|
||||
|
@ -8,15 +8,15 @@ namespace i2p
|
||||
{
|
||||
namespace crypto
|
||||
{
|
||||
class CryptoKeyEncryptor
|
||||
class CryptoKeyEncryptor
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~CryptoKeyEncryptor () {};
|
||||
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:
|
||||
|
||||
@ -30,7 +30,7 @@ namespace crypto
|
||||
public:
|
||||
|
||||
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:
|
||||
|
||||
@ -42,7 +42,7 @@ namespace crypto
|
||||
public:
|
||||
|
||||
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:
|
||||
|
||||
@ -51,13 +51,13 @@ namespace crypto
|
||||
|
||||
// ECIES P256
|
||||
|
||||
class ECIESP256Encryptor: public CryptoKeyEncryptor
|
||||
class ECIESP256Encryptor: public CryptoKeyEncryptor
|
||||
{
|
||||
public:
|
||||
|
||||
ECIESP256Encryptor (const uint8_t * pub);
|
||||
~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:
|
||||
|
||||
@ -72,7 +72,7 @@ namespace crypto
|
||||
|
||||
ECIESP256Decryptor (const uint8_t * priv);
|
||||
~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:
|
||||
|
||||
@ -80,17 +80,17 @@ namespace crypto
|
||||
BIGNUM * m_PrivateKey;
|
||||
};
|
||||
|
||||
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub);
|
||||
void CreateECIESP256RandomKeys (uint8_t * priv, uint8_t * pub);
|
||||
|
||||
// ECIES GOST R 34.10
|
||||
|
||||
class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor
|
||||
class ECIESGOSTR3410Encryptor: public CryptoKeyEncryptor
|
||||
{
|
||||
public:
|
||||
|
||||
ECIESGOSTR3410Encryptor (const uint8_t * pub);
|
||||
~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:
|
||||
|
||||
@ -104,7 +104,7 @@ namespace crypto
|
||||
|
||||
ECIESGOSTR3410Decryptor (const uint8_t * priv);
|
||||
~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:
|
||||
|
||||
|
@ -11,20 +11,20 @@ namespace i2p
|
||||
{
|
||||
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_Receiver (nullptr)
|
||||
{
|
||||
m_Identity.FromBase64 (owner->GetIdentity()->ToBase64());
|
||||
}
|
||||
|
||||
|
||||
DatagramDestination::~DatagramDestination ()
|
||||
{
|
||||
m_Sessions.clear();
|
||||
}
|
||||
|
||||
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;
|
||||
std::vector<uint8_t> v(MAX_DATAGRAM_SIZE);
|
||||
uint8_t * buf = v.data();
|
||||
@ -33,11 +33,11 @@ namespace datagram
|
||||
auto signatureLen = m_Identity.GetSignatureLen ();
|
||||
uint8_t * buf1 = signature + 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)
|
||||
{
|
||||
uint8_t hash[32];
|
||||
uint8_t hash[32];
|
||||
SHA256(buf1, len, hash);
|
||||
owner->Sign (hash, 32, signature);
|
||||
}
|
||||
@ -63,10 +63,10 @@ namespace datagram
|
||||
uint8_t hash[32];
|
||||
SHA256(buf + headerLen, len - headerLen, hash);
|
||||
verified = identity.Verify (hash, 32, signature);
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
verified = identity.Verify (buf + headerLen, len - headerLen, signature);
|
||||
|
||||
|
||||
if (verified)
|
||||
{
|
||||
auto h = identity.GetIdentHash();
|
||||
@ -79,7 +79,7 @@ namespace datagram
|
||||
LogPrint (eLogWarning, "DatagramDestination: no receiver for port ", toPort);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Datagram signature verification failed");
|
||||
LogPrint (eLogWarning, "Datagram signature verification failed");
|
||||
}
|
||||
|
||||
DatagramDestination::Receiver DatagramDestination::FindReceiver(uint16_t port)
|
||||
@ -113,24 +113,24 @@ namespace datagram
|
||||
{
|
||||
htobe32buf (msg->GetPayload (), size); // length
|
||||
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
|
||||
msg->len += size + 4;
|
||||
msg->len += size + 4;
|
||||
msg->FillI2NPMessageHeader (eI2NPData);
|
||||
}
|
||||
}
|
||||
else
|
||||
msg = nullptr;
|
||||
return msg;
|
||||
}
|
||||
|
||||
void DatagramDestination::CleanUp ()
|
||||
{
|
||||
{
|
||||
if (m_Sessions.empty ()) return;
|
||||
auto now = i2p::util::GetMillisecondsSinceEpoch();
|
||||
LogPrint(eLogDebug, "DatagramDestination: clean up sessions");
|
||||
std::unique_lock<std::mutex> lock(m_SessionsMutex);
|
||||
// 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
|
||||
if (now - it->second->LastActivity() >= DATAGRAM_SESSION_MAX_IDLE)
|
||||
@ -143,7 +143,7 @@ namespace datagram
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<DatagramSession> DatagramDestination::ObtainSession(const i2p::data::IdentHash & identity)
|
||||
{
|
||||
std::shared_ptr<DatagramSession> session = nullptr;
|
||||
@ -169,7 +169,7 @@ namespace datagram
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
DatagramSession::DatagramSession(i2p::client::ClientDestination * localDestination,
|
||||
const i2p::data::IdentHash & remoteIdent) :
|
||||
m_LocalDestination(localDestination),
|
||||
@ -203,7 +203,7 @@ namespace datagram
|
||||
{
|
||||
if(!m_RoutingSession)
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
|
||||
|
||||
auto routingPath = m_RoutingSession->GetSharedRoutingPath();
|
||||
if (!routingPath)
|
||||
return DatagramSession::Info(nullptr, nullptr, m_LastUse);
|
||||
@ -318,7 +318,7 @@ namespace datagram
|
||||
m_RoutingSession->SetSharedRoutingPath(path);
|
||||
}
|
||||
return path;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void DatagramSession::HandleLeaseSetUpdated(std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||
|
@ -24,9 +24,9 @@ namespace client
|
||||
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY;
|
||||
int numTags = DEFAULT_TAGS_TO_SEND;
|
||||
std::shared_ptr<std::vector<i2p::data::IdentHash> > explicitPeers;
|
||||
try
|
||||
try
|
||||
{
|
||||
if (params)
|
||||
if (params)
|
||||
{
|
||||
auto it = params->find (I2CP_PARAM_INBOUND_TUNNEL_LENGTH);
|
||||
if (it != params->end ())
|
||||
@ -59,16 +59,16 @@ namespace client
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception & ex)
|
||||
}
|
||||
catch (std::exception & ex)
|
||||
{
|
||||
LogPrint(eLogError, "Destination: unable to parse parameters for destination: ", ex.what());
|
||||
}
|
||||
@ -492,7 +492,7 @@ namespace client
|
||||
m_PublishReplyToken = 0;
|
||||
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 ();
|
||||
}
|
||||
else
|
||||
@ -503,7 +503,7 @@ namespace client
|
||||
m_PublishVerificationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_VERIFICATION_TIMEOUT));
|
||||
m_PublishVerificationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishVerificationTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -728,14 +728,14 @@ namespace client
|
||||
if (isPublic)
|
||||
PersistTemporaryKeys ();
|
||||
else
|
||||
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
|
||||
i2p::data::PrivateKeys::GenerateCryptoKeyPair(GetIdentity ()->GetCryptoKeyType (),
|
||||
m_EncryptionPrivateKey, m_EncryptionPublicKey);
|
||||
m_Decryptor = m_Keys.CreateDecryptor (m_EncryptionPrivateKey);
|
||||
m_Decryptor = m_Keys.CreateDecryptor (m_EncryptionPrivateKey);
|
||||
if (isPublic)
|
||||
LogPrint (eLogInfo, "Destination: Local address ", GetIdentHash().ToBase32 (), " created");
|
||||
|
||||
// extract streaming params
|
||||
if (params)
|
||||
if (params)
|
||||
{
|
||||
auto it = params->find (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY);
|
||||
if (it != params->end ())
|
||||
@ -956,7 +956,7 @@ namespace client
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
std::ofstream f1 (path, std::ofstream::binary | std::ofstream::out);
|
||||
|
@ -190,9 +190,9 @@ namespace client
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const { m_Keys.Sign (buf, len, signature); };
|
||||
|
||||
// ref counter
|
||||
int Acquire () { return ++m_RefCounter; };
|
||||
int Acquire () { return ++m_RefCounter; };
|
||||
int Release () { return --m_RefCounter; };
|
||||
int GetRefCounter () const { return m_RefCounter; };
|
||||
int GetRefCounter () const { return m_RefCounter; };
|
||||
|
||||
// streaming
|
||||
std::shared_ptr<i2p::stream::StreamingDestination> CreateStreamingDestination (int port, bool gzip = true); // additional
|
||||
|
@ -30,7 +30,7 @@ namespace i2p
|
||||
}
|
||||
m_collected[key].Val += val;
|
||||
}
|
||||
|
||||
|
||||
void EventCore::PumpCollected(EventListener * listener)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_collect_mutex);
|
||||
|
@ -29,7 +29,7 @@ namespace i2p
|
||||
void CollectEvent(const std::string & type, const std::string & ident, uint64_t val);
|
||||
void SetListener(EventListener * l);
|
||||
void PumpCollected(EventListener * l);
|
||||
|
||||
|
||||
private:
|
||||
std::mutex m_collect_mutex;
|
||||
struct CollectedEvent
|
||||
@ -41,7 +41,7 @@ namespace i2p
|
||||
std::map<std::string, CollectedEvent> m_collected;
|
||||
EventListener * m_listener = nullptr;
|
||||
};
|
||||
#ifdef WITH_EVENTS
|
||||
#ifdef WITH_EVENTS
|
||||
extern EventCore core;
|
||||
#endif
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ namespace fs {
|
||||
#else /* other unix */
|
||||
#if defined(ANDROID)
|
||||
const char * ext = getenv("EXTERNAL_STORAGE");
|
||||
if (!ext) ext = "/sdcard";
|
||||
if (!ext) ext = "/sdcard";
|
||||
if (boost::filesystem::exists(ext))
|
||||
{
|
||||
dataDir = std::string (ext) + "/" + appName;
|
||||
@ -123,12 +123,12 @@ namespace fs {
|
||||
}
|
||||
|
||||
uint32_t GetLastUpdateTime (const std::string & path)
|
||||
{
|
||||
{
|
||||
if (!boost::filesystem::exists(path)) return 0;
|
||||
boost::system::error_code ec;
|
||||
auto t = boost::filesystem::last_write_time (path, ec);
|
||||
return ec ? 0 : t;
|
||||
}
|
||||
}
|
||||
|
||||
bool Remove(const std::string & path) {
|
||||
if (!boost::filesystem::exists(path))
|
||||
|
10
libi2pd/FS.h
10
libi2pd/FS.h
@ -97,7 +97,7 @@ namespace fs {
|
||||
* @param files Vector to store found files
|
||||
* @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
|
||||
@ -113,9 +113,9 @@ namespace fs {
|
||||
*/
|
||||
bool Exists(const std::string & path);
|
||||
|
||||
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
|
||||
|
||||
bool CreateDirectory (const std::string& path);
|
||||
uint32_t GetLastUpdateTime (const std::string & path); // seconds since epoch
|
||||
|
||||
bool CreateDirectory (const std::string& path);
|
||||
|
||||
template<typename T>
|
||||
void _ExpandPath(std::stringstream & path, T c) {
|
||||
@ -153,7 +153,7 @@ namespace fs {
|
||||
_ExpandPath(s, filenames...);
|
||||
|
||||
return s.str();
|
||||
}
|
||||
}
|
||||
|
||||
} // fs
|
||||
} // i2p
|
||||
|
@ -21,24 +21,24 @@ namespace data
|
||||
void Families::LoadCertificate (const std::string& filename)
|
||||
{
|
||||
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)
|
||||
{
|
||||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
X509 * cert = SSL_get_certificate (ssl);
|
||||
if (cert)
|
||||
{
|
||||
{
|
||||
std::shared_ptr<i2p::crypto::Verifier> verifier;
|
||||
// extract issuer name
|
||||
char name[100];
|
||||
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
|
||||
char * cn = strstr (name, "CN=");
|
||||
if (cn)
|
||||
{
|
||||
{
|
||||
cn += 3;
|
||||
char * family = strstr (cn, ".family");
|
||||
if (family) family[0] = 0;
|
||||
}
|
||||
}
|
||||
auto pkey = X509_get_pubkey (cert);
|
||||
int keyType = EVP_PKEY_base_id (pkey);
|
||||
switch (keyType)
|
||||
@ -65,7 +65,7 @@ namespace data
|
||||
i2p::crypto::bn2buf (y, signingKey + 32, 32);
|
||||
BN_free (x); BN_free (y);
|
||||
verifier = std::make_shared<i2p::crypto::ECDSAP256Verifier>(signingKey);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
@ -79,12 +79,12 @@ namespace data
|
||||
EVP_PKEY_free (pkey);
|
||||
if (verifier && cn)
|
||||
m_SigningKeys[cn] = verifier;
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Family: Can't open certificate file ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
SSL_CTX_free (ctx);
|
||||
}
|
||||
|
||||
void Families::LoadCertificates ()
|
||||
@ -105,11 +105,11 @@ namespace data
|
||||
}
|
||||
LoadCertificate (file);
|
||||
numCertificates++;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
uint8_t buf[50], signatureBuf[64];
|
||||
@ -118,12 +118,12 @@ namespace data
|
||||
{
|
||||
LogPrint (eLogError, "Family: ", family, " is too long");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (buf, family.c_str (), len);
|
||||
memcpy (buf + len, (const uint8_t *)ident, 32);
|
||||
len += 32;
|
||||
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
|
||||
len += 32;
|
||||
Base64ToByteStream (signature, signatureLen, signatureBuf, 64);
|
||||
auto it = m_SigningKeys.find (family);
|
||||
if (it != m_SigningKeys.end ())
|
||||
return it->second->Verify (buf, len, signatureBuf);
|
||||
@ -136,7 +136,7 @@ namespace data
|
||||
auto filename = i2p::fs::DataDirPath("family", (family + ".key"));
|
||||
std::string sig;
|
||||
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)
|
||||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
@ -167,15 +167,15 @@ namespace data
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Family: elliptic curve ", curve, " is not supported");
|
||||
}
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
}
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Family: Can't open keys file: ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
SSL_CTX_free (ctx);
|
||||
return sig;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace data
|
||||
Families ();
|
||||
~Families ();
|
||||
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);
|
||||
|
||||
private:
|
||||
@ -28,7 +28,7 @@ namespace data
|
||||
private:
|
||||
|
||||
std::map<std::string, std::shared_ptr<i2p::crypto::Verifier> > m_SigningKeys;
|
||||
};
|
||||
};
|
||||
|
||||
std::string CreateFamilySignature (const std::string& family, const IdentHash& ident);
|
||||
// return base64 signature of empty string in case of failure
|
||||
|
@ -17,16 +17,16 @@ namespace i2p
|
||||
{
|
||||
namespace garlic
|
||||
{
|
||||
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner,
|
||||
GarlicRoutingSession::GarlicRoutingSession (GarlicDestination * owner,
|
||||
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_LeaseSetUpdateMsgID (0)
|
||||
{
|
||||
// create new session tags and session key
|
||||
RAND_bytes (m_SessionKey, 32);
|
||||
m_Encryption.SetKey (m_SessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag):
|
||||
m_Owner (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0)
|
||||
@ -35,10 +35,10 @@ namespace garlic
|
||||
m_Encryption.SetKey (m_SessionKey);
|
||||
m_SessionTags.push_back (sessionTag);
|
||||
m_SessionTags.back ().creationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
}
|
||||
|
||||
GarlicRoutingSession::~GarlicRoutingSession ()
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<GarlicRoutingPath> GarlicRoutingSession::GetSharedRoutingPath ()
|
||||
@ -53,56 +53,56 @@ namespace garlic
|
||||
if (m_SharedRoutingPath) m_SharedRoutingPath->numTimesUsed++;
|
||||
return m_SharedRoutingPath;
|
||||
}
|
||||
|
||||
|
||||
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->numTimesUsed = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
path = nullptr;
|
||||
m_SharedRoutingPath = path;
|
||||
}
|
||||
|
||||
|
||||
GarlicRoutingSession::UnconfirmedTags * GarlicRoutingSession::GenerateSessionTags ()
|
||||
{
|
||||
auto tags = new UnconfirmedTags (m_NumTags);
|
||||
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
tags->tagsCreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (int i = 0; i < m_NumTags; i++)
|
||||
{
|
||||
RAND_bytes (tags->sessionTags[i], 32);
|
||||
tags->sessionTags[i].creationTime = tags->tagsCreationTime;
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
void GarlicRoutingSession::MessageConfirmed (uint32_t msgID)
|
||||
{
|
||||
TagsConfirmed (msgID);
|
||||
if (msgID == m_LeaseSetUpdateMsgID)
|
||||
{
|
||||
{
|
||||
m_LeaseSetUpdateStatus = eLeaseSetUpToDate;
|
||||
m_LeaseSetUpdateMsgID = 0;
|
||||
LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed");
|
||||
}
|
||||
}
|
||||
else
|
||||
CleanupExpiredTags ();
|
||||
}
|
||||
|
||||
void GarlicRoutingSession::TagsConfirmed (uint32_t msgID)
|
||||
{
|
||||
}
|
||||
|
||||
void GarlicRoutingSession::TagsConfirmed (uint32_t msgID)
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
auto it = m_UnconfirmedTagsMsgs.find (msgID);
|
||||
if (it != m_UnconfirmedTagsMsgs.end ())
|
||||
{
|
||||
auto& tags = it->second;
|
||||
if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
|
||||
{
|
||||
{
|
||||
for (int i = 0; i < tags->numTags; i++)
|
||||
m_SessionTags.push_back (tags->sessionTags[i]);
|
||||
}
|
||||
}
|
||||
m_UnconfirmedTagsMsgs.erase (it);
|
||||
}
|
||||
}
|
||||
@ -114,7 +114,7 @@ namespace garlic
|
||||
{
|
||||
if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT)
|
||||
it = m_SessionTags.erase (it);
|
||||
else
|
||||
else
|
||||
++it;
|
||||
}
|
||||
CleanupUnconfirmedTags ();
|
||||
@ -123,7 +123,7 @@ namespace garlic
|
||||
if (m_Owner)
|
||||
m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID);
|
||||
m_LeaseSetUpdateMsgID = 0;
|
||||
}
|
||||
}
|
||||
return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty ();
|
||||
}
|
||||
|
||||
@ -140,10 +140,10 @@ namespace garlic
|
||||
m_Owner->RemoveDeliveryStatusSession (it->first);
|
||||
it = m_UnconfirmedTagsMsgs.erase (it);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -155,10 +155,10 @@ namespace garlic
|
||||
uint8_t * buf = m->GetPayload () + 4; // 4 bytes for length
|
||||
|
||||
// find non-expired tag
|
||||
bool tagFound = false;
|
||||
SessionTag tag;
|
||||
bool tagFound = false;
|
||||
SessionTag tag;
|
||||
if (m_NumTags > 0)
|
||||
{
|
||||
{
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
while (!m_SessionTags.empty ())
|
||||
{
|
||||
@ -168,11 +168,11 @@ namespace garlic
|
||||
m_SessionTags.pop_front (); // use same tag only once
|
||||
tagFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_SessionTags.pop_front (); // remove expired tag
|
||||
}
|
||||
}
|
||||
}
|
||||
// create message
|
||||
if (!tagFound) // new session
|
||||
{
|
||||
@ -184,34 +184,34 @@ namespace garlic
|
||||
}
|
||||
// create ElGamal block
|
||||
ElGamalBlock elGamal;
|
||||
memcpy (elGamal.sessionKey, m_SessionKey, 32);
|
||||
memcpy (elGamal.sessionKey, m_SessionKey, 32);
|
||||
RAND_bytes (elGamal.preIV, 32); // Pre-IV
|
||||
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 ();
|
||||
m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
m_Destination->Encrypt ((uint8_t *)&elGamal, buf, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
m_Encryption.SetIV (iv);
|
||||
buf += 514;
|
||||
len += 514;
|
||||
len += 514;
|
||||
}
|
||||
else // existing session
|
||||
{
|
||||
{
|
||||
// session tag
|
||||
memcpy (buf, tag, 32);
|
||||
memcpy (buf, tag, 32);
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
SHA256(tag, 32, iv);
|
||||
m_Encryption.SetIV (iv);
|
||||
buf += 32;
|
||||
len += 32;
|
||||
}
|
||||
len += 32;
|
||||
}
|
||||
// AES block
|
||||
len += CreateAESBlock (buf, msg);
|
||||
htobe32buf (m->GetPayload (), len);
|
||||
m->len += len + 4;
|
||||
m->FillI2NPMessageHeader (eI2NPGarlic);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
blockSize += 2;
|
||||
if (newTags) // session tags recreated
|
||||
{
|
||||
{
|
||||
for (int i = 0; i < newTags->numTags; i++)
|
||||
{
|
||||
memcpy (buf + blockSize, newTags->sessionTags[i], 32); // tags
|
||||
blockSize += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
uint32_t * payloadSize = (uint32_t *)(buf + blockSize);
|
||||
blockSize += 4;
|
||||
uint8_t * payloadHash = buf + blockSize;
|
||||
@ -243,7 +243,7 @@ namespace garlic
|
||||
blockSize += (16-rem); //padding
|
||||
m_Encryption.Encrypt(buf, blockSize, buf);
|
||||
return blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, std::shared_ptr<const I2NPMessage> msg, UnconfirmedTags * newTags)
|
||||
{
|
||||
@ -256,7 +256,7 @@ namespace garlic
|
||||
size++;
|
||||
|
||||
if (m_Owner)
|
||||
{
|
||||
{
|
||||
// resubmit non-confirmed LeaseSet
|
||||
if (m_LeaseSetUpdateStatus == eLeaseSetSubmitted && ts > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT)
|
||||
{
|
||||
@ -267,7 +267,7 @@ namespace garlic
|
||||
// attach DeviveryStatus if necessary
|
||||
if (newTags || m_LeaseSetUpdateStatus == eLeaseSetUpdated) // new tags created or leaseset updated
|
||||
{
|
||||
// clove is DeliveryStatus
|
||||
// clove is DeliveryStatus
|
||||
auto cloveSize = CreateDeliveryStatusClove (payload + size, msgID);
|
||||
if (cloveSize > 0) // successive?
|
||||
{
|
||||
@ -278,14 +278,14 @@ namespace garlic
|
||||
newTags->msgID = msgID;
|
||||
m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr<UnconfirmedTags>(newTags)));
|
||||
newTags = nullptr; // got acquired
|
||||
}
|
||||
}
|
||||
m_Owner->DeliveryStatusSent (shared_from_this (), msgID);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: DeliveryStatus clove was not created");
|
||||
}
|
||||
}
|
||||
// attach LeaseSet
|
||||
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
|
||||
if (m_LeaseSetUpdateStatus == eLeaseSetUpdated)
|
||||
{
|
||||
if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous
|
||||
m_LeaseSetUpdateStatus = eLeaseSetSubmitted;
|
||||
@ -293,25 +293,25 @@ namespace garlic
|
||||
m_LeaseSetSubmissionTime = ts;
|
||||
// clove if our leaseSet must be attached
|
||||
auto leaseSet = CreateDatabaseStoreMsg (m_Owner->GetLeaseSet ());
|
||||
size += CreateGarlicClove (payload + size, leaseSet, false);
|
||||
size += CreateGarlicClove (payload + size, leaseSet, false);
|
||||
(*numCloves)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (msg) // clove message ifself if presented
|
||||
{
|
||||
{
|
||||
size += CreateGarlicClove (payload + size, msg, m_Destination ? m_Destination->IsDestination () : false);
|
||||
(*numCloves)++;
|
||||
}
|
||||
}
|
||||
memset (payload + size, 0, 3); // certificate of message
|
||||
size += 3;
|
||||
htobe32buf (payload + size, msgID); // MessageID
|
||||
size += 4;
|
||||
htobe64buf (payload + size, ts + 8000); // Expiration of message, 8 sec
|
||||
size += 8;
|
||||
|
||||
if (newTags) delete newTags; // not acquired, delete
|
||||
|
||||
if (newTags) delete newTags; // not acquired, delete
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, std::shared_ptr<const I2NPMessage> msg, bool isDestination)
|
||||
{
|
||||
@ -323,13 +323,13 @@ namespace garlic
|
||||
size++;
|
||||
memcpy (buf + size, m_Destination->GetIdentHash (), 32);
|
||||
size += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[size] = 0;// delivery instructions flag local
|
||||
size++;
|
||||
}
|
||||
|
||||
|
||||
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
|
||||
size += msg->GetLength ();
|
||||
uint32_t cloveID;
|
||||
@ -341,34 +341,34 @@ namespace garlic
|
||||
memset (buf + size, 0, 3); // certificate of clove
|
||||
size += 3;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID)
|
||||
{
|
||||
{
|
||||
size_t size = 0;
|
||||
if (m_Owner)
|
||||
{
|
||||
auto inboundTunnel = m_Owner->GetTunnelPool ()->GetNextInboundTunnel ();
|
||||
if (inboundTunnel)
|
||||
{
|
||||
{
|
||||
buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel
|
||||
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
|
||||
size += 32;
|
||||
htobe32buf (buf + size, inboundTunnel->GetNextTunnelID ()); // tunnelID
|
||||
size += 4;
|
||||
// create msg
|
||||
size += 4;
|
||||
// create msg
|
||||
auto msg = CreateDeliveryStatusMsg (msgID);
|
||||
if (m_Owner)
|
||||
{
|
||||
//encrypt
|
||||
//encrypt
|
||||
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
|
||||
m_Owner->SubmitSessionKey (key, tag);
|
||||
GarlicRoutingSession garlic (key, tag);
|
||||
msg = garlic.WrapSingleMessage (msg);
|
||||
msg = garlic.WrapSingleMessage (msg);
|
||||
}
|
||||
memcpy (buf + size, msg->GetBuffer (), msg->GetLength ());
|
||||
size += msg->GetLength ();
|
||||
@ -383,7 +383,7 @@ namespace garlic
|
||||
memset (buf + size, 0, 3); // certificate of clove
|
||||
size += 3;
|
||||
}
|
||||
else
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: No inbound tunnels in the pool for DeliveryStatus");
|
||||
}
|
||||
else
|
||||
@ -395,19 +395,19 @@ namespace garlic
|
||||
GarlicDestination::GarlicDestination (): m_NumTags (32) // 32 tags by default
|
||||
{
|
||||
m_Ctx = BN_CTX_new ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GarlicDestination::~GarlicDestination ()
|
||||
{
|
||||
BN_CTX_free (m_Ctx);
|
||||
}
|
||||
|
||||
void GarlicDestination::CleanUp ()
|
||||
{
|
||||
{
|
||||
m_Sessions.clear ();
|
||||
m_DeliveryStatusSessions.clear ();
|
||||
m_Tags.clear ();
|
||||
}
|
||||
}
|
||||
void GarlicDestination::AddSessionKey (const uint8_t * key, const uint8_t * tag)
|
||||
{
|
||||
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);
|
||||
return true;
|
||||
@ -431,22 +431,22 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogWarning, "Garlic: message length ", length, " exceeds I2NP message length ", msg->GetLength ());
|
||||
return;
|
||||
}
|
||||
}
|
||||
buf += 4; // length
|
||||
auto it = m_Tags.find (SessionTag(buf));
|
||||
if (it != m_Tags.end ())
|
||||
{
|
||||
// tag found. Use AES
|
||||
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)
|
||||
{
|
||||
{
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
SHA256(buf, 32, iv);
|
||||
decryption->SetIV (iv);
|
||||
decryption->Decrypt (buf + 32, length - 32, buf + 32);
|
||||
HandleAESBlock (buf + 32, length - 32, decryption, msg->from);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: message length ", length, " is less than 32 bytes");
|
||||
}
|
||||
@ -455,35 +455,35 @@ namespace garlic
|
||||
// tag not found. Use ElGamal
|
||||
ElGamalBlock elGamal;
|
||||
if (length >= 514 && Decrypt (buf, (uint8_t *)&elGamal, m_Ctx))
|
||||
{
|
||||
{
|
||||
auto decryption = std::make_shared<AESDecryption>(elGamal.sessionKey);
|
||||
uint8_t iv[32]; // IV is first 16 bytes
|
||||
SHA256(elGamal.preIV, 32, iv);
|
||||
SHA256(elGamal.preIV, 32, iv);
|
||||
decryption->SetIV (iv);
|
||||
decryption->Decrypt(buf + 514, length - 514, buf + 514);
|
||||
HandleAESBlock (buf + 514, length - 514, decryption, msg->from);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Garlic: Failed to decrypt message");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GarlicDestination::HandleAESBlock (uint8_t * buf, size_t len, std::shared_ptr<AESDecryption> decryption,
|
||||
std::shared_ptr<i2p::tunnel::InboundTunnel> from)
|
||||
{
|
||||
uint16_t tagCount = bufbe16toh (buf);
|
||||
buf += 2; len -= 2;
|
||||
buf += 2; len -= 2;
|
||||
if (tagCount > 0)
|
||||
{
|
||||
if (tagCount*32 > len)
|
||||
{
|
||||
if (tagCount*32 > len)
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: Tag count ", tagCount, " exceeds length ", len);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
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;
|
||||
len -= tagCount*32;
|
||||
uint32_t payloadSize = bufbe32toh (buf);
|
||||
@ -491,10 +491,10 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: Unexpected payload size ", payloadSize);
|
||||
return;
|
||||
}
|
||||
}
|
||||
buf += 4;
|
||||
uint8_t * payloadHash = buf;
|
||||
buf += 32;// payload hash.
|
||||
buf += 32;// payload hash.
|
||||
if (*buf) // session key?
|
||||
buf += 32; // new session key
|
||||
buf++; // flag
|
||||
@ -506,9 +506,9 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: wrong payload hash");
|
||||
return;
|
||||
}
|
||||
}
|
||||
HandleGarlicPayload (buf, payloadSize, 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
|
||||
LogPrint (eLogWarning, "Garlic: clove encrypted");
|
||||
buf += 32;
|
||||
}
|
||||
buf += 32;
|
||||
}
|
||||
ptrdiff_t offset = buf - buf1;
|
||||
GarlicDeliveryType deliveryType = (GarlicDeliveryType)((flag >> 5) & 0x03);
|
||||
switch (deliveryType)
|
||||
@ -542,10 +542,10 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: message is too short");
|
||||
break;
|
||||
}
|
||||
}
|
||||
HandleI2NPMessage (buf, len - offset, from);
|
||||
break;
|
||||
case eGarlicDeliveryTypeDestination:
|
||||
break;
|
||||
case eGarlicDeliveryTypeDestination:
|
||||
LogPrint (eLogDebug, "Garlic: type destination");
|
||||
buf += 32; // destination. check it later or for multiple destinations
|
||||
offset = buf - buf1;
|
||||
@ -553,11 +553,11 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: message is too short");
|
||||
break;
|
||||
}
|
||||
HandleI2NPMessage (buf, len - offset, from);
|
||||
}
|
||||
HandleI2NPMessage (buf, len - offset, from);
|
||||
break;
|
||||
case eGarlicDeliveryTypeTunnel:
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "Garlic: type tunnel");
|
||||
// gwHash and gwTunnel sequence is reverted
|
||||
uint8_t * gwHash = buf;
|
||||
@ -591,7 +591,7 @@ namespace garlic
|
||||
{
|
||||
uint8_t * ident = buf;
|
||||
buf += 32;
|
||||
offset = buf - buf1;
|
||||
offset = buf - buf1;
|
||||
if (!from) // received directly
|
||||
{
|
||||
if (offset > (int)len)
|
||||
@ -604,7 +604,7 @@ namespace garlic
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "Garlic: type router for inbound tunnels not supported");
|
||||
break;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LogPrint (eLogWarning, "Garlic: unknown delivery type ", (int)deliveryType);
|
||||
@ -623,23 +623,23 @@ namespace garlic
|
||||
{
|
||||
LogPrint (eLogError, "Garlic: clove is too long");
|
||||
break;
|
||||
}
|
||||
}
|
||||
len -= offset;
|
||||
}
|
||||
}
|
||||
|
||||
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> GarlicDestination::WrapMessage (std::shared_ptr<const i2p::data::RoutingDestination> destination,
|
||||
std::shared_ptr<I2NPMessage> msg, bool attachLeaseSet)
|
||||
{
|
||||
auto session = GetRoutingSession (destination, attachLeaseSet);
|
||||
return session->WrapSingleMessage (msg);
|
||||
auto session = GetRoutingSession (destination, attachLeaseSet);
|
||||
return session->WrapSingleMessage (msg);
|
||||
}
|
||||
|
||||
std::shared_ptr<GarlicRoutingSession> GarlicDestination::GetRoutingSession (
|
||||
std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet)
|
||||
{
|
||||
GarlicRoutingSessionPtr session;
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
auto it = m_Sessions.find (destination->GetIdentHash ());
|
||||
if (it != m_Sessions.end ())
|
||||
@ -647,14 +647,14 @@ namespace garlic
|
||||
}
|
||||
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
|
||||
std::unique_lock<std::mutex> l(m_SessionsMutex);
|
||||
m_Sessions[destination->GetIdentHash ()] = session;
|
||||
}
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GarlicDestination::CleanupExpiredTags ()
|
||||
{
|
||||
// incoming
|
||||
@ -666,7 +666,7 @@ namespace garlic
|
||||
{
|
||||
numExpiredTags++;
|
||||
it = m_Tags.erase (it);
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
@ -690,7 +690,7 @@ namespace garlic
|
||||
}
|
||||
}
|
||||
// delivery status sessions
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_DeliveryStatusSessionsMutex);
|
||||
for (auto it = m_DeliveryStatusSessions.begin (); it != m_DeliveryStatusSessions.end (); )
|
||||
{
|
||||
@ -699,7 +699,7 @@ namespace garlic
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID)
|
||||
@ -756,7 +756,7 @@ namespace garlic
|
||||
if (m_Tags.empty ()) return;
|
||||
std::string ident = GetIdentHash().ToBase32();
|
||||
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 ();
|
||||
// 4 bytes timestamp, 32 bytes tag, 32 bytes key
|
||||
for (auto it: m_Tags)
|
||||
@ -766,7 +766,7 @@ namespace garlic
|
||||
f.write ((char *)&it.first.creationTime, 4);
|
||||
f.write ((char *)it.first.data (), 32);
|
||||
f.write ((char *)it.second->GetKey ().data (), 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -775,11 +775,11 @@ namespace garlic
|
||||
std::string ident = GetIdentHash().ToBase32();
|
||||
std::string path = i2p::fs::DataDirPath("tags", (ident + ".tags"));
|
||||
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
|
||||
std::ifstream f (path, std::ifstream::binary);
|
||||
if (f)
|
||||
if (f)
|
||||
{
|
||||
std::map<i2p::crypto::AESKey, std::shared_ptr<AESDecryption> > keys;
|
||||
// 4 bytes timestamp, 32 bytes tag, 32 bytes key
|
||||
@ -794,7 +794,7 @@ namespace garlic
|
||||
f.read ((char *)key, 32);
|
||||
}
|
||||
else
|
||||
f.seekg (64, std::ios::cur); // skip
|
||||
f.seekg (64, std::ios::cur); // skip
|
||||
if (f.eof ()) break;
|
||||
|
||||
std::shared_ptr<AESDecryption> decryption;
|
||||
@ -805,21 +805,21 @@ namespace garlic
|
||||
decryption = std::make_shared<AESDecryption>(key);
|
||||
m_Tags.insert (std::make_pair (SessionTag (tag, ts), decryption));
|
||||
}
|
||||
if (!m_Tags.empty ())
|
||||
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
|
||||
if (!m_Tags.empty ())
|
||||
LogPrint (eLogInfo, m_Tags.size (), " loaded for ", ident);
|
||||
}
|
||||
}
|
||||
i2p::fs::Remove (path);
|
||||
i2p::fs::Remove (path);
|
||||
}
|
||||
|
||||
void CleanUpTagsFiles ()
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
std::vector<std::string> files;
|
||||
i2p::fs::ReadDir (i2p::fs::DataDirPath("tags"), files);
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto it: files)
|
||||
if (ts >= i2p::fs::GetLastUpdateTime (it) + INCOMING_TAGS_EXPIRATION_TIMEOUT)
|
||||
i2p::fs::Remove (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
100
libi2pd/Garlic.h
100
libi2pd/Garlic.h
@ -17,46 +17,46 @@
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
{
|
||||
class OutboundTunnel;
|
||||
}
|
||||
|
||||
|
||||
namespace garlic
|
||||
{
|
||||
|
||||
enum GarlicDeliveryType
|
||||
{
|
||||
eGarlicDeliveryTypeLocal = 0,
|
||||
|
||||
enum GarlicDeliveryType
|
||||
{
|
||||
eGarlicDeliveryTypeLocal = 0,
|
||||
eGarlicDeliveryTypeDestination = 1,
|
||||
eGarlicDeliveryTypeRouter = 2,
|
||||
eGarlicDeliveryTypeRouter = 2,
|
||||
eGarlicDeliveryTypeTunnel = 3
|
||||
};
|
||||
};
|
||||
|
||||
struct ElGamalBlock
|
||||
{
|
||||
uint8_t sessionKey[32];
|
||||
uint8_t preIV[32];
|
||||
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_CONFIRMATION_TIMEOUT = 10; // 10 seconds
|
||||
const int OUTGOING_TAGS_CONFIRMATION_TIMEOUT = 10; // 10 seconds
|
||||
const int LEASET_CONFIRMATION_TIMEOUT = 4000; // in milliseconds
|
||||
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
|
||||
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
|
||||
|
||||
struct SessionTag: public i2p::data::Tag<32>
|
||||
const int ROUTING_PATH_EXPIRATION_TIMEOUT = 30; // 30 seconds
|
||||
const int ROUTING_PATH_MAX_NUM_TIMES_USED = 100; // how many times might be used
|
||||
|
||||
struct SessionTag: public i2p::data::Tag<32>
|
||||
{
|
||||
SessionTag (const uint8_t * buf, uint32_t ts = 0): Tag<32>(buf), creationTime (ts) {};
|
||||
SessionTag () = default;
|
||||
SessionTag (const SessionTag& ) = default;
|
||||
SessionTag& operator= (const SessionTag& ) = default;
|
||||
#ifndef _WIN32
|
||||
SessionTag (SessionTag&& ) = default;
|
||||
SessionTag& operator= (SessionTag&& ) = default;
|
||||
SessionTag (SessionTag&& ) = default;
|
||||
SessionTag& operator= (SessionTag&& ) = default;
|
||||
#endif
|
||||
uint32_t creationTime; // seconds since epoch
|
||||
uint32_t creationTime; // seconds since epoch
|
||||
};
|
||||
|
||||
// AESDecryption is associated with session tags and store key
|
||||
@ -67,7 +67,7 @@ namespace garlic
|
||||
AESDecryption (const uint8_t * key): m_Key (key)
|
||||
{
|
||||
SetKey (key);
|
||||
}
|
||||
}
|
||||
const i2p::crypto::AESKey& GetKey () const { return m_Key; };
|
||||
|
||||
private:
|
||||
@ -81,8 +81,8 @@ namespace garlic
|
||||
std::shared_ptr<const i2p::data::Lease> remoteLease;
|
||||
int rtt; // RTT
|
||||
uint32_t updateTime; // seconds since epoch
|
||||
int numTimesUsed;
|
||||
};
|
||||
int numTimesUsed;
|
||||
};
|
||||
|
||||
class GarlicDestination;
|
||||
class GarlicRoutingSession: public std::enable_shared_from_this<GarlicRoutingSession>
|
||||
@ -94,7 +94,7 @@ namespace garlic
|
||||
eLeaseSetSubmitted,
|
||||
eLeaseSetDoNotSend
|
||||
};
|
||||
|
||||
|
||||
struct UnconfirmedTags
|
||||
{
|
||||
UnconfirmedTags (int n): numTags (n), tagsCreationTime (0) { sessionTags = new SessionTag[numTags]; };
|
||||
@ -107,23 +107,23 @@ namespace garlic
|
||||
|
||||
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);
|
||||
GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag); // one time encryption
|
||||
~GarlicRoutingSession ();
|
||||
std::shared_ptr<I2NPMessage> WrapSingleMessage (std::shared_ptr<const I2NPMessage> msg);
|
||||
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
|
||||
|
||||
void SetLeaseSetUpdated ()
|
||||
{
|
||||
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
||||
void SetLeaseSetUpdated ()
|
||||
{
|
||||
if (m_LeaseSetUpdateStatus != eLeaseSetDoNotSend) m_LeaseSetUpdateStatus = eLeaseSetUpdated;
|
||||
};
|
||||
bool IsLeaseSetNonConfirmed () const { return m_LeaseSetUpdateStatus == eLeaseSetSubmitted; };
|
||||
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 ();
|
||||
void SetSharedRoutingPath (std::shared_ptr<GarlicRoutingPath> path);
|
||||
|
||||
@ -144,26 +144,26 @@ namespace garlic
|
||||
|
||||
GarlicDestination * m_Owner;
|
||||
std::shared_ptr<const i2p::data::RoutingDestination> m_Destination;
|
||||
|
||||
|
||||
i2p::crypto::AESKey m_SessionKey;
|
||||
std::list<SessionTag> m_SessionTags;
|
||||
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;
|
||||
uint32_t m_LeaseSetUpdateMsgID;
|
||||
uint64_t m_LeaseSetSubmissionTime; // in milliseconds
|
||||
|
||||
|
||||
i2p::crypto::CBCEncryption m_Encryption;
|
||||
|
||||
std::shared_ptr<GarlicRoutingPath> m_SharedRoutingPath;
|
||||
|
||||
|
||||
public:
|
||||
// for HTTP only
|
||||
size_t GetNumOutgoingTags () const { return m_SessionTags.size (); };
|
||||
};
|
||||
};
|
||||
//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
|
||||
{
|
||||
@ -173,36 +173,36 @@ namespace garlic
|
||||
~GarlicDestination ();
|
||||
|
||||
void CleanUp ();
|
||||
void SetNumTags (int numTags) { m_NumTags = numTags; };
|
||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
||||
void SetNumTags (int numTags) { m_NumTags = numTags; };
|
||||
std::shared_ptr<GarlicRoutingSession> GetRoutingSession (std::shared_ptr<const i2p::data::RoutingDestination> destination, bool attachLeaseSet);
|
||||
void CleanupExpiredTags ();
|
||||
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);
|
||||
|
||||
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
|
||||
void DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID);
|
||||
|
||||
|
||||
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 std::shared_ptr<const i2p::data::LocalLeaseSet> GetLeaseSet () = 0; // TODO
|
||||
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;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
void HandleGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void HandleDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void SaveTags ();
|
||||
void LoadTags ();
|
||||
void LoadTags ();
|
||||
|
||||
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);
|
||||
void HandleGarlicPayload (uint8_t * buf, size_t len, std::shared_ptr<i2p::tunnel::InboundTunnel> from);
|
||||
|
||||
@ -218,17 +218,17 @@ namespace garlic
|
||||
// DeliveryStatus
|
||||
std::mutex m_DeliveryStatusSessionsMutex;
|
||||
std::map<uint32_t, GarlicRoutingSessionPtr> m_DeliveryStatusSessions; // msgID -> session
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// 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; };
|
||||
};
|
||||
|
||||
void CleanUpTagsFiles ();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
134
libi2pd/Gost.cpp
134
libi2pd/Gost.cpp
@ -28,7 +28,7 @@ namespace crypto
|
||||
GOSTR3410Curve::~GOSTR3410Curve ()
|
||||
{
|
||||
EC_GROUP_free (m_Group);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
BIGNUM * z1 = BN_CTX_get (ctx);
|
||||
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_mod_mul (z2, z2, h, q, ctx); // z2 = -r/h
|
||||
EC_POINT * C = EC_POINT_new (m_Group);
|
||||
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
|
||||
BN_mod (x, x, q, ctx); // Cx % q
|
||||
bool ret = !BN_cmp (x, r); // Cx = r ?
|
||||
@ -94,9 +94,9 @@ namespace crypto
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
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
|
||||
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 * Q = nullptr;
|
||||
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_mul (m_Group, S, s, nullptr, nullptr, ctx);
|
||||
BIGNUM * q = BN_CTX_get (ctx);
|
||||
@ -112,28 +112,28 @@ namespace crypto
|
||||
BIGNUM * h = BN_CTX_get (ctx);
|
||||
BN_mod (h, digest, q, ctx); // h = digest % q
|
||||
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_add (m_Group, C, S, H, ctx); // s*P - h*C
|
||||
EC_POINT_free (H);
|
||||
EC_POINT_free (S);
|
||||
BIGNUM * r1 = BN_CTX_get (ctx);
|
||||
BN_mod_inverse (r1, r, q, ctx);
|
||||
Q = EC_POINT_new (m_Group);
|
||||
EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
|
||||
}
|
||||
Q = EC_POINT_new (m_Group);
|
||||
EC_POINT_mul (m_Group, Q, nullptr, C, r1, ctx); // (s*P - h*C)/r
|
||||
}
|
||||
EC_POINT_free (C);
|
||||
BN_CTX_end (ctx);
|
||||
BN_CTX_free (ctx);
|
||||
return Q;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static GOSTR3410Curve * CreateGOSTR3410Curve (GOSTR3410ParamSet paramSet)
|
||||
{
|
||||
// a, b, p, q, x, y
|
||||
static const char * params[eGOSTR3410NumParamSets][6] =
|
||||
// a, b, p, q, x, y
|
||||
static const char * params[eGOSTR3410NumParamSets][6] =
|
||||
{
|
||||
{
|
||||
{
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94",
|
||||
"A6",
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97",
|
||||
@ -147,10 +147,10 @@ namespace crypto
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",
|
||||
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",
|
||||
"3",
|
||||
"7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4"
|
||||
"7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4"
|
||||
} // tc26-2012-paramSetA-512
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
BIGNUM * a = nullptr, * b = nullptr, * p = nullptr, * q =nullptr, * x = nullptr, * y = nullptr;
|
||||
BN_hex2bn(&a, params[paramSet][0]);
|
||||
BN_hex2bn(&b, params[paramSet][1]);
|
||||
@ -161,25 +161,25 @@ namespace crypto
|
||||
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);
|
||||
return curve;
|
||||
}
|
||||
}
|
||||
|
||||
static std::array<std::unique_ptr<GOSTR3410Curve>, eGOSTR3410NumParamSets> g_GOSTR3410Curves;
|
||||
std::unique_ptr<GOSTR3410Curve>& GetGOSTR3410Curve (GOSTR3410ParamSet paramSet)
|
||||
{
|
||||
if (!g_GOSTR3410Curves[paramSet])
|
||||
{
|
||||
auto c = CreateGOSTR3410Curve (paramSet);
|
||||
auto c = CreateGOSTR3410Curve (paramSet);
|
||||
if (!g_GOSTR3410Curves[paramSet]) // make sure it was not created already
|
||||
g_GOSTR3410Curves[paramSet].reset (c);
|
||||
else
|
||||
delete c;
|
||||
}
|
||||
return g_GOSTR3410Curves[paramSet];
|
||||
}
|
||||
return g_GOSTR3410Curves[paramSet];
|
||||
}
|
||||
|
||||
// ГОСТ 34.11-2012
|
||||
|
||||
static const uint64_t T0[256] =
|
||||
static const uint64_t T0[256] =
|
||||
{
|
||||
0xE6F87E5C5B711FD0, 0x258377800924FA16, 0xC849E07E852EA4A8, 0x5B4686A18F06C16A,
|
||||
0x0B32E9A2D77B416E, 0xABDA37A467815C66, 0xF61796A81A686676, 0xF5DC0B706391954B,
|
||||
@ -246,7 +246,7 @@ namespace crypto
|
||||
0x92BDE697D67F3422, 0xC78933E10514BC61, 0xE1C1D9B975C9B54A, 0xD2266160CF1BCD80,
|
||||
0x9A4492ED78FD8671, 0xB3CCAB2A881A9793, 0x72CEBF667FE1D088, 0xD6D45B5D985A9427
|
||||
};
|
||||
static const uint64_t T1[256] =
|
||||
static const uint64_t T1[256] =
|
||||
{
|
||||
0xC811A8058C3F55DE, 0x65F5B43196B50619, 0xF74F96B1D6706E43, 0x859D1E8BCB43D336,
|
||||
0x5AAB8A85CCFA3D84, 0xF9C7BF99C295FCFD, 0xA21FD5A1DE4B630F, 0xCDB3EF763B8B456D,
|
||||
@ -313,7 +313,7 @@ namespace crypto
|
||||
0x57B69E77B57354A0, 0x3969441D8097D0B4, 0x3330CAFBF3E2F0CF, 0xE28E77DDE0BE8CC3,
|
||||
0x62B12E259C494F46, 0xA6CE726FB9DBD1CA, 0x41E242C1EED14DBA, 0x76032FF47AA30FB0
|
||||
};
|
||||
static const uint64_t T2[256] =
|
||||
static const uint64_t T2[256] =
|
||||
{
|
||||
0x45B268A93ACDE4CC, 0xAF7F0BE884549D08, 0x048354B3C1468263, 0x925435C2C80EFED2,
|
||||
0xEE4E37F27FDFFBA7, 0x167A33920C60F14D, 0xFB123B52EA03E584, 0x4A0CAB53FDBB9007,
|
||||
@ -380,7 +380,7 @@ namespace crypto
|
||||
0xF9DD11850420A43B, 0x4BE5BEB68A243ED6, 0x5584255F19C8D65D, 0x3B67404E633FA006,
|
||||
0xA68DB6766C472A1F, 0xF78AC79AB4C97E21, 0xC353442E1080AAEC, 0x9A4F9DB95782E714
|
||||
};
|
||||
static const uint64_t T3[256] =
|
||||
static const uint64_t T3[256] =
|
||||
{
|
||||
0x05BA7BC82C9B3220, 0x31A54665F8B65E4F, 0xB1B651F77547F4D4, 0x8BFA0D857BA46682,
|
||||
0x85A96C5AA16A98BB, 0x990FAEF908EB79C9, 0xA15E37A247F4A62D, 0x76857DCD5D27741E,
|
||||
@ -447,7 +447,7 @@ namespace crypto
|
||||
0x77059157F359DC47, 0x1D262E3907FF492B, 0xFB582233E59AC557, 0xDDB2BCE242F8B673,
|
||||
0x2577B76248E096CF, 0x6F99C4A6D83DA74C, 0xC1147E41EB795701, 0xF48BAF76912A9337
|
||||
};
|
||||
static const uint64_t T4[256] =
|
||||
static const uint64_t T4[256] =
|
||||
{
|
||||
0x3EF29D249B2C0A19, 0xE9E16322B6F8622F, 0x5536994047757F7A, 0x9F4D56D5A47B0B33,
|
||||
0x822567466AA1174C, 0xB8F5057DEB082FB2, 0xCC48C10BF4475F53, 0x373088D4275DEC3A,
|
||||
@ -514,7 +514,7 @@ namespace crypto
|
||||
0x6853032B59F3EE6E, 0x65B3E9C4FF073AAA, 0x772AC3399AE5EBEC, 0x87816E97F842A75B,
|
||||
0x110E2DB2E0484A4B, 0x331277CB3DD8DEDD, 0xBD510CAC79EB9FA5, 0x352179552A91F5C7
|
||||
};
|
||||
static const uint64_t T5[256] =
|
||||
static const uint64_t T5[256] =
|
||||
{
|
||||
0x8AB0A96846E06A6D, 0x43C7E80B4BF0B33A, 0x08C9B3546B161EE5, 0x39F1C235EBA990BE,
|
||||
0xC1BEF2376606C7B2, 0x2C209233614569AA, 0xEB01523B6FC3289A, 0x946953AB935ACEDD,
|
||||
@ -581,7 +581,7 @@ namespace crypto
|
||||
0xEFEB8511D4C82766, 0x961CB6BE40D147A3, 0xAAB35F25F7B812DE, 0x76154E407044329D,
|
||||
0x513D76B64E570693, 0xF3479AC7D2F90AA8, 0x9B8B2E4477079C85, 0x297EB99D3D85AC69
|
||||
};
|
||||
static const uint64_t T6[256] =
|
||||
static const uint64_t T6[256] =
|
||||
{
|
||||
0x7E37E62DFC7D40C3, 0x776F25A4EE939E5B, 0xE045C850DD8FB5AD, 0x86ED5BA711FF1952,
|
||||
0xE91D0BD9CF616B35, 0x37E0AB256E408FFB, 0x9607F6C031025A7A, 0x0B02F5E116D23C9D,
|
||||
@ -648,7 +648,7 @@ namespace crypto
|
||||
0xE6AB92E8D1CB8EA2, 0x3354C7F5663856F1, 0xD93EE170AF7BAE4D, 0x616BD27BC22AE67C,
|
||||
0x92B39A10397A8370, 0xABC8B3304B8E9890, 0xBF967287630B02B2, 0x5B67D607B6FC6E15
|
||||
};
|
||||
static uint64_t T7[256] =
|
||||
static uint64_t T7[256] =
|
||||
{
|
||||
0xD031C397CE553FE6, 0x16BA5B01B006B525, 0xA89BADE6296E70C8, 0x6A1F525D77D3435B,
|
||||
0x6E103570573DFA0B, 0x660EFB2A17FC95AB, 0x76327A9E97634BF6, 0x4BAD9D6462458BF5,
|
||||
@ -716,59 +716,59 @@ namespace crypto
|
||||
0x717E7067AF4F499A, 0x938290A9ECD1DBB3, 0x88E3B293344DD172, 0x2734158C250FA3D6
|
||||
};
|
||||
|
||||
static const uint64_t C_[12][8] =
|
||||
static const uint64_t C_[12][8] =
|
||||
{
|
||||
{
|
||||
0xe9daca1eda5b08b1, 0x1f7c65c0812fcbeb, 0x16d0452e43766a2f, 0xfcc485758db84e71,
|
||||
0x0169679291e07c4b, 0x15d360a4082a42a2, 0x234d74cc36747605, 0x0745a6f2596580dd
|
||||
},
|
||||
},
|
||||
{
|
||||
0x1a2f9da98ab5a36f, 0xd7b5700f469de34f, 0x982b230a72eafef3, 0x3101b5160f5ed561,
|
||||
0x5899d6126b17b59a, 0xcaa70adbc261b55c, 0x56cdcbd71ba2dd55, 0xb79bb121700479e6
|
||||
},
|
||||
},
|
||||
{
|
||||
0xc72fce2bacdc74f5, 0x35843d6a28fc390a, 0x8b1f9c525f5ef106, 0x7b7b29b11475eaf2,
|
||||
0xb19e3590e40fe2d3, 0x09db6260373ac9c1, 0x31db7a8643f4b6c2, 0xb20aba0af5961e99
|
||||
},
|
||||
},
|
||||
{
|
||||
0xd26615e8b3df1fef, 0xdde4715da0e148f9, 0x7d3c5c337e858e48, 0x3f355e68ad1c729d,
|
||||
0x75d603ed822cd7a9, 0xbe0352933313b7d8, 0xf137e893a1ea5334, 0x2ed1e384bcbe0c22
|
||||
},
|
||||
},
|
||||
{
|
||||
0x994747adac6bea4b, 0x6323a96c0c413f9a, 0x4a1086161f1c157f, 0xbdff0f80d7359e35,
|
||||
0xa3f53a254717cdbf, 0x161a2723b700ffdf, 0xf563eaa97ea2567a, 0x57fe6c7cfd581760
|
||||
},
|
||||
},
|
||||
{
|
||||
0xd9d33a1daeae4fae, 0xc039307a3bc3a46f, 0x6ca44251f9c4662d, 0xc68ef09ab49a7f18,
|
||||
0xb4b79a1cb7a6facf, 0xb6c6bec2661ff20a, 0x354f903672c571bf, 0x6e7d64467a4068fa
|
||||
},
|
||||
},
|
||||
{
|
||||
0xecc5aaee160ec7f4, 0x540924bffe86ac51, 0xc987bfe6c7c69e39, 0xc9937a19333e47d3,
|
||||
0x372c822dc5ab9209, 0x04054a2883694706, 0xf34a3ca24c451735, 0x93d4143a4d568688
|
||||
},
|
||||
},
|
||||
{
|
||||
0xa7c9934d425b1f9b, 0x41416e0c02aae703, 0x1ede369c71f8b74e, 0x9ac4db4d3b44b489,
|
||||
0x90069b92cb2b89f4, 0x2fc4a5d12b8dd169, 0xd9a8515935c2ac36, 0x1ee702bfd40d7fa4
|
||||
},
|
||||
},
|
||||
{
|
||||
0x9b223116545a8f37, 0xde5f16ecd89a4c94, 0x244289251b3a7d3a, 0x84090de0b755d93c,
|
||||
0xb1ceb2db0b440a80, 0x549c07a69a8a2b7b, 0x602a1fcb92dc380e, 0xdb5a238351446172
|
||||
},
|
||||
},
|
||||
{
|
||||
0x526f0580a6debeab, 0xf3f3e4b248e52a38, 0xdb788aff1ce74189, 0x0361331b8ae1ff1f,
|
||||
0x4b3369af0267e79f, 0xf452763b306c1e7a, 0xc3b63b15d1fa9836, 0xed9c4598fbc7b474
|
||||
},
|
||||
},
|
||||
{
|
||||
0xfb89c8efd09ecd7b, 0x94fe5a63cdc60230, 0x6107abebbb6bfad8, 0x7966841421800120,
|
||||
0xcab948eaef711d8a, 0x986e477d1dcdbaef, 0x5dd86fc04a59a2de, 0x1b2df381cda4ca6b
|
||||
},
|
||||
},
|
||||
{
|
||||
0xba3116f167e78e37, 0x7ab14904b08013d2, 0x771ddfbc323ca4cd, 0x9b9f2130d41220f8,
|
||||
0x86cc91189def805d, 0x5228e188aaa41de7, 0x991bb2d9d517f4fa, 0x20d71bf14a92bc48
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
union GOST3411Block // 8 bytes aligned
|
||||
{
|
||||
uint8_t buf[64];
|
||||
@ -780,15 +780,15 @@ namespace crypto
|
||||
for (int i = 0; i < 8; i++)
|
||||
ret.ll[i] = ll[i]^other.ll[i];
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GOST3411Block operator^(const uint64_t * other) const
|
||||
{
|
||||
GOST3411Block ret;
|
||||
for (int i = 0; i < 8; i++)
|
||||
ret.ll[i] = ll[i]^other[i];
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
GOST3411Block operator+(const GOST3411Block& other) const
|
||||
{
|
||||
@ -799,7 +799,7 @@ namespace crypto
|
||||
uint16_t sum = buf[i] + other.buf[i] + carry;
|
||||
ret.buf[i] = sum;
|
||||
carry = sum >> 8;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -807,17 +807,17 @@ namespace crypto
|
||||
{
|
||||
for (int i = 63; i >= 0; i--)
|
||||
{
|
||||
if (!c) return;
|
||||
if (!c) return;
|
||||
c += buf[i];
|
||||
buf[i] = c;
|
||||
c >>= 8;
|
||||
c >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void F ()
|
||||
{
|
||||
uint64_t res[8];
|
||||
for (int b=0; b<8; b++)
|
||||
for (int b=0; b<8; b++)
|
||||
{
|
||||
uint64_t r;
|
||||
r = T0[buf[b+56]];
|
||||
@ -843,11 +843,11 @@ namespace crypto
|
||||
k = k^C_[i];
|
||||
k.F ();
|
||||
res = k^res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static GOST3411Block gN (const GOST3411Block& N, const GOST3411Block& h, const GOST3411Block& m)
|
||||
{
|
||||
GOST3411Block res = N ^ h;
|
||||
@ -855,12 +855,12 @@ namespace crypto
|
||||
res = res.E (m);
|
||||
res = res^h;
|
||||
res = res^m;
|
||||
return res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
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;
|
||||
memcpy (h.buf, iv, 64);
|
||||
memset (N.buf, 0, 64);
|
||||
@ -885,15 +885,15 @@ namespace crypto
|
||||
memcpy (m.buf + padding, buf, l);
|
||||
|
||||
h = gN (N, h, m);
|
||||
N.Add (l*8);
|
||||
N.Add (l*8);
|
||||
s = m + s;
|
||||
|
||||
|
||||
GOST3411Block N0;
|
||||
memset (N0.buf, 0, 64);
|
||||
h = gN (N0, h, N);
|
||||
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)
|
||||
@ -919,7 +919,7 @@ namespace crypto
|
||||
size_t len;
|
||||
bool is512;
|
||||
};
|
||||
|
||||
|
||||
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ()
|
||||
{
|
||||
return new GOSTR3411_2012_CTX;
|
||||
@ -949,7 +949,7 @@ namespace crypto
|
||||
size_t l = 64 - ctx->len;
|
||||
if (len < l) l = len;
|
||||
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->h = gN (ctx->N, ctx->h, ctx->m);
|
||||
@ -959,7 +959,7 @@ namespace crypto
|
||||
while (len >= 64)
|
||||
{
|
||||
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;
|
||||
ctx->h = gN (ctx->N, ctx->h, ctx->m);
|
||||
ctx->N.Add (512);
|
||||
@ -975,7 +975,7 @@ namespace crypto
|
||||
|
||||
void GOSTR3411_2012_CTX_Finish (uint8_t * digest, GOSTR3411_2012_CTX * ctx)
|
||||
{
|
||||
GOST3411Block m;
|
||||
GOST3411Block m;
|
||||
size_t padding = 64 - ctx->len;
|
||||
if (padding)
|
||||
{
|
||||
@ -985,14 +985,14 @@ namespace crypto
|
||||
memcpy (m.buf + padding, ctx->m.buf, ctx->len);
|
||||
|
||||
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;
|
||||
|
||||
|
||||
GOST3411Block N0;
|
||||
memset (N0.buf, 0, 64);
|
||||
ctx->h = gN (N0, ctx->h, ctx->N);
|
||||
ctx->h = gN (N0, ctx->h, ctx->s);
|
||||
|
||||
|
||||
size_t sz = ctx->is512 ? 64 : 32;
|
||||
for (size_t i = 0; i < sz; i++)
|
||||
digest[i] = ctx->h.buf[sz - i - 1];
|
||||
|
@ -10,25 +10,25 @@ namespace crypto
|
||||
{
|
||||
|
||||
// ГОСТ Р 34.10
|
||||
|
||||
|
||||
enum GOSTR3410ParamSet
|
||||
{
|
||||
eGOSTR3410CryptoProA = 0, // 1.2.643.2.2.35.1
|
||||
// XchA = A, XchB = C
|
||||
//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
|
||||
eGOSTR3410NumParamSets
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class GOSTR3410Curve
|
||||
{
|
||||
public:
|
||||
|
||||
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; };
|
||||
EC_POINT * MulP (const BIGNUM * n) 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);
|
||||
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;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EC_GROUP * m_Group;
|
||||
@ -47,14 +47,14 @@ namespace crypto
|
||||
|
||||
// Big Endian
|
||||
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
|
||||
struct GOSTR3411_2012_CTX;
|
||||
GOSTR3411_2012_CTX * GOSTR3411_2012_CTX_new ();
|
||||
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_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);
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,9 @@
|
||||
#include "Log.h"
|
||||
#include "Gzip.h"
|
||||
|
||||
namespace i2p
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
namespace data
|
||||
{
|
||||
const size_t GZIP_CHUNK_SIZE = 16384;
|
||||
|
||||
@ -38,7 +38,7 @@ namespace data
|
||||
m_Inflator.next_out = out;
|
||||
m_Inflator.avail_out = outLen;
|
||||
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;
|
||||
// else
|
||||
LogPrint (eLogError, "Gzip: Inflate error ", err);
|
||||
@ -52,19 +52,19 @@ namespace data
|
||||
m_Inflator.next_in = const_cast<uint8_t *>(in);
|
||||
m_Inflator.avail_in = inLen;
|
||||
int ret;
|
||||
do
|
||||
do
|
||||
{
|
||||
m_Inflator.next_out = out;
|
||||
m_Inflator.avail_out = GZIP_CHUNK_SIZE;
|
||||
ret = inflate (&m_Inflator, Z_NO_FLUSH);
|
||||
if (ret < 0)
|
||||
if (ret < 0)
|
||||
{
|
||||
inflateEnd (&m_Inflator);
|
||||
os.setstate(std::ios_base::failbit);
|
||||
break;
|
||||
}
|
||||
os.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out);
|
||||
}
|
||||
}
|
||||
while (!m_Inflator.avail_out); // more data to read
|
||||
delete[] out;
|
||||
}
|
||||
@ -105,7 +105,7 @@ namespace data
|
||||
m_Deflator.next_out = out;
|
||||
m_Deflator.avail_out = outLen;
|
||||
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;
|
||||
// else
|
||||
LogPrint (eLogError, "Gzip: Deflate error ", err);
|
||||
|
@ -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 len = 2; /* strlen(": ") */
|
||||
@ -251,14 +251,14 @@ namespace http {
|
||||
uri = tokens[1];
|
||||
version = tokens[2];
|
||||
expect = HEADER_LINE;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
auto p = parse_header_line(line);
|
||||
if (p.first.length () > 0)
|
||||
headers.push_back (p);
|
||||
else
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
pos = eol + strlen(CRLF);
|
||||
@ -268,10 +268,10 @@ namespace http {
|
||||
return eoh + strlen(HTTP_EOH);
|
||||
}
|
||||
|
||||
void HTTPReq::write(std::ostream & o)
|
||||
void HTTPReq::write(std::ostream & o)
|
||||
{
|
||||
o << method << " " << uri << " " << version << CRLF;
|
||||
for (auto & h : headers)
|
||||
for (auto & h : headers)
|
||||
o << h.first << ": " << h.second << CRLF;
|
||||
o << CRLF;
|
||||
}
|
||||
@ -284,7 +284,7 @@ namespace http {
|
||||
}
|
||||
|
||||
void HTTPReq::AddHeader (const std::string& name, const std::string& value)
|
||||
{
|
||||
{
|
||||
headers.push_back (std::make_pair(name, value));
|
||||
}
|
||||
|
||||
@ -295,28 +295,28 @@ namespace http {
|
||||
{
|
||||
it.second = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPReq::RemoveHeader (const std::string& name, const std::string& exempt)
|
||||
{
|
||||
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);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string HTTPReq::GetHeader (const std::string& name) const
|
||||
std::string HTTPReq::GetHeader (const std::string& name) const
|
||||
{
|
||||
for (auto& it : headers)
|
||||
if (it.first == name)
|
||||
return it.second;
|
||||
return it.second;
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool HTTPRes::is_chunked() const
|
||||
{
|
||||
auto it = headers.find("Transfer-Encoding");
|
||||
@ -335,10 +335,10 @@ namespace http {
|
||||
if (it->second.find("gzip") != std::string::npos)
|
||||
return true; /* gotcha! */
|
||||
if (includingI2PGzip && it->second.find("x-i2p-gzip") != std::string::npos)
|
||||
return true;
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
long int HTTPMsg::content_length() const
|
||||
{
|
||||
unsigned long int length = 0;
|
||||
@ -385,8 +385,8 @@ namespace http {
|
||||
std::string line = str.substr(pos, eol - pos);
|
||||
auto p = parse_header_line(line);
|
||||
if (p.first.length () > 0)
|
||||
headers.insert (p);
|
||||
else
|
||||
headers.insert (p);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
pos = eol + strlen(CRLF);
|
||||
|
@ -16,16 +16,16 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace i2p
|
||||
namespace i2p
|
||||
{
|
||||
namespace http
|
||||
namespace http
|
||||
{
|
||||
const char CRLF[] = "\r\n"; /**< HTTP line terminator */
|
||||
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_VERSIONS; /**< list of valid HTTP versions */
|
||||
|
||||
struct URL
|
||||
struct URL
|
||||
{
|
||||
std::string schema;
|
||||
std::string user;
|
||||
@ -63,7 +63,7 @@ namespace http
|
||||
bool is_i2p() const;
|
||||
};
|
||||
|
||||
struct HTTPMsg
|
||||
struct HTTPMsg
|
||||
{
|
||||
std::map<std::string, std::string> headers;
|
||||
|
||||
@ -75,9 +75,9 @@ namespace http
|
||||
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 method;
|
||||
std::string uri;
|
||||
@ -97,10 +97,10 @@ namespace http
|
||||
void write(std::ostream & o);
|
||||
|
||||
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) { RemoveHeader (name, ""); };
|
||||
std::string GetHeader (const std::string& name) const;
|
||||
std::string GetHeader (const std::string& name) const;
|
||||
};
|
||||
|
||||
struct HTTPRes : HTTPMsg {
|
||||
|
@ -21,7 +21,7 @@ namespace i2p
|
||||
{
|
||||
return std::make_shared<I2NPMessageBuffer<I2NP_MAX_MESSAGE_SIZE> >();
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ()
|
||||
{
|
||||
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
|
||||
msg->Align (12);
|
||||
return std::shared_ptr<I2NPMessage>(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> NewI2NPMessage (size_t len)
|
||||
{
|
||||
return (len < I2NP_MAX_SHORT_MESSAGE_SIZE/2) ? NewI2NPShortMessage () : NewI2NPMessage ();
|
||||
}
|
||||
}
|
||||
|
||||
void I2NPMessage::FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID)
|
||||
{
|
||||
SetTypeID (msgType);
|
||||
if (!replyMsgID) RAND_bytes ((uint8_t *)&replyMsgID, 4);
|
||||
SetMsgID (replyMsgID);
|
||||
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
|
||||
SetMsgID (replyMsgID);
|
||||
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
|
||||
UpdateSize ();
|
||||
UpdateChks ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void I2NPMessage::RenewI2NPMessageHeader ()
|
||||
{
|
||||
uint32_t msgID;
|
||||
RAND_bytes ((uint8_t *)&msgID, 4);
|
||||
SetMsgID (msgID);
|
||||
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
|
||||
SetExpiration (i2p::util::GetMillisecondsSinceEpoch () + I2NP_MESSAGE_EXPIRATION_TIMEOUT);
|
||||
}
|
||||
|
||||
bool I2NPMessage::IsExpired () const
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, size_t len, uint32_t replyMsgID)
|
||||
{
|
||||
auto msg = NewI2NPMessage (len);
|
||||
@ -71,7 +71,7 @@ namespace i2p
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length ", msg->maxLen);
|
||||
msg->FillI2NPMessageHeader (msgType, replyMsgID);
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " exceeds max length");
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
@ -94,8 +94,8 @@ namespace i2p
|
||||
newMsg->offset = msg->offset;
|
||||
*newMsg = *msg;
|
||||
return newMsg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDeliveryStatusMsg (uint32_t msgID)
|
||||
{
|
||||
auto m = NewI2NPShortMessage ();
|
||||
@ -109,14 +109,14 @@ namespace i2p
|
||||
{
|
||||
RAND_bytes ((uint8_t *)&msgID, 4);
|
||||
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->FillI2NPMessageHeader (eI2NPDeliveryStatus);
|
||||
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)
|
||||
{
|
||||
auto m = excludedPeers ? NewI2NPMessage () : NewI2NPShortMessage ();
|
||||
@ -125,7 +125,7 @@ namespace i2p
|
||||
buf += 32;
|
||||
memcpy (buf, from, 32); // from
|
||||
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)
|
||||
{
|
||||
*buf = flag | DATABASE_LOOKUP_DELIVERY_FLAG; // set delivery flag
|
||||
@ -133,11 +133,11 @@ namespace i2p
|
||||
buf += 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
*buf = flag; // flag
|
||||
buf++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (excludedPeers)
|
||||
{
|
||||
int cnt = excludedPeers->size ();
|
||||
@ -147,21 +147,21 @@ namespace i2p
|
||||
{
|
||||
memcpy (buf, it, 32);
|
||||
buf += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
// nothing to exclude
|
||||
htobuf16 (buf, 0);
|
||||
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,
|
||||
std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel, const uint8_t * replyKey, const uint8_t * replyTag)
|
||||
{
|
||||
@ -176,7 +176,7 @@ namespace i2p
|
||||
buf ++;
|
||||
htobe32buf (buf, replyTunnel->GetNextTunnelID ()); // reply tunnel ID
|
||||
buf += 4;
|
||||
|
||||
|
||||
// excluded
|
||||
htobe16buf (buf, cnt);
|
||||
buf += 2;
|
||||
@ -187,19 +187,19 @@ namespace i2p
|
||||
memcpy (buf, it, 32);
|
||||
buf += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
// encryption
|
||||
memcpy (buf, replyKey, 32);
|
||||
buf[32] = uint8_t( 1 ); // 1 tag
|
||||
memcpy (buf + 33, replyTag, 32);
|
||||
buf += 65;
|
||||
|
||||
m->len += (buf - m->GetPayload ());
|
||||
m->len += (buf - m->GetPayload ());
|
||||
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)
|
||||
{
|
||||
auto m = NewI2NPShortMessage ();
|
||||
@ -207,27 +207,27 @@ namespace i2p
|
||||
size_t len = 0;
|
||||
memcpy (buf, ident, 32);
|
||||
len += 32;
|
||||
buf[len] = routers.size ();
|
||||
buf[len] = routers.size ();
|
||||
len++;
|
||||
for (const auto& it: routers)
|
||||
{
|
||||
memcpy (buf + len, it, 32);
|
||||
len += 32;
|
||||
}
|
||||
}
|
||||
memcpy (buf + len, i2p::context.GetRouterInfo ().GetIdentHash (), 32);
|
||||
len += 32;
|
||||
len += 32;
|
||||
m->len += len;
|
||||
m->FillI2NPMessageHeader (eI2NPDatabaseSearchReply);
|
||||
return m;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::RouterInfo> router, uint32_t replyToken)
|
||||
{
|
||||
if (!router) // we send own RouterInfo
|
||||
router = context.GetSharedRouterInfo ();
|
||||
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
|
||||
memcpy (payload + DATABASE_STORE_KEY_OFFSET, router->GetIdentHash (), 32);
|
||||
payload[DATABASE_STORE_TYPE_OFFSET] = 0; // RouterInfo
|
||||
@ -239,7 +239,7 @@ namespace i2p
|
||||
buf += 4;
|
||||
memcpy (buf, router->GetIdentHash (), 32);
|
||||
buf += 32;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t * sizePtr = buf;
|
||||
buf += 2;
|
||||
@ -247,22 +247,22 @@ namespace i2p
|
||||
i2p::data::GzipDeflator deflator;
|
||||
size_t size = deflator.Deflate (router->GetBuffer (), router->GetBufferLen (), buf, m->maxLen -m->len);
|
||||
if (size)
|
||||
{
|
||||
{
|
||||
htobe16buf (sizePtr, size); // size
|
||||
m->len += size;
|
||||
}
|
||||
}
|
||||
else
|
||||
m = nullptr;
|
||||
if (m)
|
||||
m->FillI2NPMessageHeader (eI2NPDatabaseStore);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateDatabaseStoreMsg (std::shared_ptr<const i2p::data::LeaseSet> leaseSet)
|
||||
{
|
||||
if (!leaseSet) return nullptr;
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
|
||||
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
|
||||
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, 0);
|
||||
@ -278,7 +278,7 @@ namespace i2p
|
||||
{
|
||||
if (!leaseSet) return nullptr;
|
||||
auto m = NewI2NPShortMessage ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
uint8_t * payload = m->GetPayload ();
|
||||
memcpy (payload + DATABASE_STORE_KEY_OFFSET, leaseSet->GetIdentHash (), 32);
|
||||
payload[DATABASE_STORE_TYPE_OFFSET] = 1; // LeaseSet
|
||||
htobe32buf (payload + DATABASE_STORE_REPLY_TOKEN_OFFSET, replyToken);
|
||||
@ -306,8 +306,8 @@ namespace i2p
|
||||
{
|
||||
if (!msg || msg->GetTypeID () != eI2NPDatabaseStore) return false;
|
||||
return !msg->GetPayload ()[DATABASE_STORE_TYPE_OFFSET]; // 0- RouterInfo
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uint16_t g_MaxNumTransitTunnels = DEFAULT_MAX_NUM_TRANSIT_TUNNELS; // TODO:
|
||||
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels)
|
||||
{
|
||||
@ -321,37 +321,37 @@ namespace i2p
|
||||
bool HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText)
|
||||
{
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
{
|
||||
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))
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours");
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
i2p::crypto::ElGamalDecrypt (i2p::context.GetPrivateKeys ().GetPrivateKey () , record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
// replace record to reply
|
||||
if (i2p::context.AcceptsTunnels () &&
|
||||
// replace record to reply
|
||||
if (i2p::context.AcceptsTunnels () &&
|
||||
i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels &&
|
||||
!i2p::transport::transports.IsBandwidthExceeded () &&
|
||||
!i2p::transport::transports.IsTransitBandwidthExceeded ())
|
||||
{
|
||||
{
|
||||
auto transitTunnel = i2p::tunnel::CreateTransitTunnel (
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET),
|
||||
clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
|
||||
clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET,
|
||||
clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET,
|
||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80,
|
||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40);
|
||||
i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel);
|
||||
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0;
|
||||
}
|
||||
else
|
||||
record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30)
|
||||
|
||||
|
||||
//TODO: fill filler
|
||||
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
|
||||
i2p::crypto::CBCEncryption encryption;
|
||||
for (int j = 0; j < num; j++)
|
||||
@ -359,23 +359,23 @@ namespace i2p
|
||||
encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET);
|
||||
encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET);
|
||||
uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE;
|
||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||
encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HandleVariableTunnelBuildMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
||||
{
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records");
|
||||
if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingInboundTunnel (replyMsgID);
|
||||
if (tunnel)
|
||||
@ -385,34 +385,34 @@ namespace i2p
|
||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Inbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
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 (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
eI2NPVariableTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleTunnelBuildMsg (uint8_t * buf, size_t len)
|
||||
@ -421,51 +421,51 @@ namespace i2p
|
||||
{
|
||||
LogPrint (eLogError, "TunnelBuild message is too short ", len);
|
||||
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 (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outbound tunnel
|
||||
{
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
// so we send it to reply tunnel
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET),
|
||||
eI2NPTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
|
||||
eI2NPTunnelBuildReply, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
else
|
||||
transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET,
|
||||
CreateI2NPMessage (eI2NPTunnelBuild, buf, len,
|
||||
bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleVariableTunnelBuildReplyMsg (uint32_t replyMsgID, uint8_t * buf, size_t len)
|
||||
{
|
||||
{
|
||||
int num = buf[0];
|
||||
LogPrint (eLogDebug, "I2NP: VariableTunnelBuildReplyMsg of ", num, " records replyMsgID=", replyMsgID);
|
||||
if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1)
|
||||
{
|
||||
LogPrint (eLogError, "VaribleTunnelBuildReply message of ", num, " records is too short ", len);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
auto tunnel = i2p::tunnel::tunnels.GetPendingOutboundTunnel (replyMsgID);
|
||||
if (tunnel)
|
||||
{
|
||||
{
|
||||
// reply for outbound tunnel
|
||||
if (tunnel->HandleTunnelBuildResponse (buf, len))
|
||||
{
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "I2NP: Outbound tunnel ", tunnel->GetTunnelID (), " has been declined");
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
tunnel->SetState (i2p::tunnel::eTunnelStateBuildFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
auto msg = NewI2NPTunnelMessage ();
|
||||
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
|
||||
msg->Concat (buf, i2p::tunnel::TUNNEL_DATA_MSG_SIZE);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
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 ();
|
||||
htobe32buf (msg->GetPayload (), tunnelID);
|
||||
@ -487,15 +487,15 @@ namespace i2p
|
||||
msg->Concat (payload, i2p::tunnel::TUNNEL_DATA_MSG_SIZE - 4);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateEmptyTunnelDataMsg ()
|
||||
{
|
||||
auto msg = NewI2NPTunnelMessage ();
|
||||
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
|
||||
msg->len += i2p::tunnel::TUNNEL_DATA_MSG_SIZE;
|
||||
return msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, const uint8_t * buf, size_t len)
|
||||
{
|
||||
auto msg = NewI2NPMessage (len);
|
||||
@ -504,10 +504,10 @@ namespace i2p
|
||||
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
|
||||
msg->len += TUNNEL_GATEWAY_HEADER_SIZE;
|
||||
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);
|
||||
return 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);
|
||||
msg->offset -= (I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE);
|
||||
msg->len = msg->offset + I2NP_HEADER_SIZE + TUNNEL_GATEWAY_HEADER_SIZE +len;
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelGateway);
|
||||
return msg;
|
||||
}
|
||||
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)
|
||||
{
|
||||
auto msg = NewI2NPMessage (len);
|
||||
@ -544,7 +544,7 @@ namespace i2p
|
||||
htobe16buf (payload + TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET, len);
|
||||
msg->FillI2NPMessageHeader (eI2NPTunnelGateway); // gateway message
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
return len;
|
||||
}
|
||||
}
|
||||
auto l = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET) + I2NP_HEADER_SIZE;
|
||||
if (l > len)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: message length ", l, " exceeds buffer length ", len);
|
||||
l = len;
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HandleI2NPMessage (uint8_t * msg, size_t len)
|
||||
{
|
||||
if (len < I2NP_HEADER_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "I2NP: message length ", len, " is smaller than header");
|
||||
return;
|
||||
}
|
||||
}
|
||||
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);
|
||||
uint8_t * buf = msg + I2NP_HEADER_SIZE;
|
||||
auto size = bufbe16toh (msg + I2NP_HEADER_SIZE_OFFSET);
|
||||
@ -581,35 +581,35 @@ namespace i2p
|
||||
size = len;
|
||||
}
|
||||
switch (typeID)
|
||||
{
|
||||
{
|
||||
case eI2NPVariableTunnelBuild:
|
||||
HandleVariableTunnelBuildMsg (msgID, buf, size);
|
||||
break;
|
||||
break;
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
HandleVariableTunnelBuildReplyMsg (msgID, buf, size);
|
||||
break;
|
||||
break;
|
||||
case eI2NPTunnelBuild:
|
||||
HandleTunnelBuildMsg (buf, size);
|
||||
break;
|
||||
break;
|
||||
case eI2NPTunnelBuildReply:
|
||||
// TODO:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogWarning, "I2NP: Unexpected message ", (int)typeID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HandleI2NPMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
{
|
||||
uint8_t typeID = msg->GetTypeID ();
|
||||
LogPrint (eLogDebug, "I2NP: Handling message with type ", (int)typeID);
|
||||
switch (typeID)
|
||||
{
|
||||
{
|
||||
case eI2NPTunnelData:
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
break;
|
||||
case eI2NPTunnelGateway:
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
@ -623,7 +623,7 @@ namespace i2p
|
||||
LogPrint (eLogInfo, "I2NP: Local destination for garlic doesn't exist anymore");
|
||||
}
|
||||
else
|
||||
i2p::context.ProcessGarlicMessage (msg);
|
||||
i2p::context.ProcessGarlicMessage (msg);
|
||||
break;
|
||||
}
|
||||
case eI2NPDatabaseStore:
|
||||
@ -638,55 +638,55 @@ namespace i2p
|
||||
msg->from->GetTunnelPool ()->ProcessDeliveryStatus (msg);
|
||||
else
|
||||
i2p::context.ProcessDeliveryStatusMessage (msg);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case eI2NPVariableTunnelBuild:
|
||||
case eI2NPVariableTunnelBuild:
|
||||
case eI2NPVariableTunnelBuildReply:
|
||||
case eI2NPTunnelBuild:
|
||||
case eI2NPTunnelBuildReply:
|
||||
case eI2NPTunnelBuildReply:
|
||||
// forward to tunnel thread
|
||||
i2p::tunnel::tunnels.PostTunnelData (msg);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
I2NPMessagesHandler::~I2NPMessagesHandler ()
|
||||
{
|
||||
Flush ();
|
||||
}
|
||||
|
||||
|
||||
void I2NPMessagesHandler::PutNextMessage (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
if (msg)
|
||||
{
|
||||
switch (msg->GetTypeID ())
|
||||
{
|
||||
{
|
||||
case eI2NPTunnelData:
|
||||
m_TunnelMsgs.push_back (msg);
|
||||
break;
|
||||
case eI2NPTunnelGateway:
|
||||
case eI2NPTunnelGateway:
|
||||
m_TunnelGatewayMsgs.push_back (msg);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
HandleI2NPMessage (msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void I2NPMessagesHandler::Flush ()
|
||||
{
|
||||
if (!m_TunnelMsgs.empty ())
|
||||
{
|
||||
{
|
||||
i2p::tunnel::tunnels.PostTunnelData (m_TunnelMsgs);
|
||||
m_TunnelMsgs.clear ();
|
||||
}
|
||||
}
|
||||
if (!m_TunnelGatewayMsgs.empty ())
|
||||
{
|
||||
{
|
||||
i2p::tunnel::tunnels.PostTunnelData (m_TunnelGatewayMsgs);
|
||||
m_TunnelGatewayMsgs.clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "LeaseSet.h"
|
||||
|
||||
namespace i2p
|
||||
{
|
||||
{
|
||||
// I2NP header
|
||||
const size_t I2NP_HEADER_TYPEID_OFFSET = 0;
|
||||
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_EXPIRATION_OFFSET = I2NP_SHORT_HEADER_TYPEID_OFFSET + 1;
|
||||
const size_t I2NP_SHORT_HEADER_SIZE = I2NP_SHORT_HEADER_EXPIRATION_OFFSET + 4;
|
||||
|
||||
|
||||
// Tunnel Gateway header
|
||||
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_SIZE = TUNNEL_GATEWAY_HEADER_LENGTH_OFFSET + 2;
|
||||
|
||||
// DeliveryStatus
|
||||
// DeliveryStatus
|
||||
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_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_HEADER_SIZE = DATABASE_STORE_REPLY_TOKEN_OFFSET + 4;
|
||||
|
||||
// TunnelBuild
|
||||
// TunnelBuild
|
||||
const size_t TUNNEL_BUILD_RECORD_SIZE = 528;
|
||||
|
||||
//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_PADDING_OFFSET = BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET + 4;
|
||||
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_ENCRYPTED_OFFSET = BUILD_REQUEST_RECORD_TO_PEER_OFFSET + 16;
|
||||
|
||||
|
||||
// BuildResponseRecord
|
||||
const size_t BUILD_RESPONSE_RECORD_HASH_OFFSET = 0;
|
||||
const size_t BUILD_RESPONSE_RECORD_PADDING_OFFSET = 32;
|
||||
@ -83,40 +83,40 @@ namespace i2p
|
||||
eI2NPTunnelBuild = 21,
|
||||
eI2NPTunnelBuildReply = 22,
|
||||
eI2NPVariableTunnelBuild = 23,
|
||||
eI2NPVariableTunnelBuildReply = 24
|
||||
};
|
||||
eI2NPVariableTunnelBuildReply = 24
|
||||
};
|
||||
|
||||
const int NUM_TUNNEL_BUILD_RECORDS = 8;
|
||||
const int NUM_TUNNEL_BUILD_RECORDS = 8;
|
||||
|
||||
// DatabaseLookup flags
|
||||
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_NORMAL_LOOKUP = 0;
|
||||
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
|
||||
|
||||
namespace tunnel
|
||||
{
|
||||
{
|
||||
class InboundTunnel;
|
||||
class TunnelPool;
|
||||
}
|
||||
|
||||
const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
|
||||
const size_t I2NP_MAX_SHORT_MESSAGE_SIZE = 4096;
|
||||
const size_t I2NP_MAX_MESSAGE_SIZE = 32768;
|
||||
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_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
|
||||
const unsigned int I2NP_MESSAGE_CLOCK_SKEW = 60*1000; // 1 minute in milliseconds
|
||||
|
||||
struct I2NPMessage
|
||||
{
|
||||
uint8_t * buf;
|
||||
{
|
||||
uint8_t * buf;
|
||||
size_t len, offset, maxLen;
|
||||
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
|
||||
|
||||
|
||||
// header accessors
|
||||
uint8_t * GetHeader () { 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); };
|
||||
void SetSize (uint16_t size) { htobe16buf (GetHeader () + I2NP_HEADER_SIZE_OFFSET, size); };
|
||||
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 UpdateChks ()
|
||||
void UpdateChks ()
|
||||
{
|
||||
uint8_t hash[32];
|
||||
SHA256(GetPayload (), GetPayloadLength (), hash);
|
||||
GetHeader ()[I2NP_HEADER_CHKS_OFFSET] = hash[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// payload
|
||||
uint8_t * GetPayload () { return GetBuffer () + I2NP_HEADER_SIZE; };
|
||||
const uint8_t * GetPayload () const { return GetBuffer () + I2NP_HEADER_SIZE; };
|
||||
uint8_t * GetBuffer () { return buf + offset; };
|
||||
const uint8_t * GetBuffer () const { return buf + offset; };
|
||||
size_t GetLength () const { return len - offset; };
|
||||
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
|
||||
|
||||
void Align (size_t alignment)
|
||||
size_t GetLength () const { return len - offset; };
|
||||
size_t GetPayloadLength () const { return GetLength () - I2NP_HEADER_SIZE; };
|
||||
|
||||
void Align (size_t alignment)
|
||||
{
|
||||
if (len + alignment > maxLen) return;
|
||||
size_t rem = ((size_t)GetBuffer ()) % alignment;
|
||||
@ -153,7 +153,7 @@ namespace tunnel
|
||||
{
|
||||
offset += (alignment - rem);
|
||||
len += (alignment - rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Concat (const uint8_t * buf1, size_t len1)
|
||||
@ -171,10 +171,10 @@ namespace tunnel
|
||||
len = offset + other.GetLength ();
|
||||
from = other.from;
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
{
|
||||
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);
|
||||
len = offset + I2NP_SHORT_HEADER_SIZE + bufbe16toh (header + I2NP_HEADER_SIZE_OFFSET);
|
||||
return bufbe32toh (header + I2NP_HEADER_MSGID_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
void FillI2NPMessageHeader (I2NPMessageType msgType, uint32_t replyMsgID = 0);
|
||||
void RenewI2NPMessageHeader ();
|
||||
bool IsExpired () const;
|
||||
};
|
||||
};
|
||||
|
||||
template<int sz>
|
||||
struct I2NPMessageBuffer: public I2NPMessage
|
||||
@ -211,35 +211,35 @@ namespace tunnel
|
||||
std::shared_ptr<I2NPMessage> NewI2NPShortMessage ();
|
||||
std::shared_ptr<I2NPMessage> NewI2NPTunnelMessage ();
|
||||
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> CopyI2NPMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
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);
|
||||
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,
|
||||
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> 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::LocalLeaseSet> leaseSet, uint32_t replyToken = 0, std::shared_ptr<const i2p::tunnel::InboundTunnel> replyTunnel = nullptr);
|
||||
bool IsRouterInfoMsg (std::shared_ptr<I2NPMessage> msg);
|
||||
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 HandleBuildRequestRecords (int num, uint8_t * records, uint8_t * clearText);
|
||||
void HandleVariableTunnelBuildMsg (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 (uint32_t tunnelID, const uint8_t * payload);
|
||||
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> CreateEmptyTunnelDataMsg ();
|
||||
|
||||
|
||||
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);
|
||||
std::shared_ptr<I2NPMessage> CreateTunnelGatewayMsg (uint32_t tunnelID, std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
@ -254,7 +254,7 @@ namespace tunnel
|
||||
~I2NPMessagesHandler ();
|
||||
void PutNextMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void Flush ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
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;
|
||||
void SetMaxNumTransitTunnels (uint16_t maxNumTransitTunnels);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -41,7 +41,7 @@ namespace data
|
||||
|
||||
IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType):
|
||||
m_IsVerifierCreated (false)
|
||||
{
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -450,7 +450,7 @@ namespace data
|
||||
|
||||
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 ())
|
||||
{
|
||||
case CRYPTO_KEY_TYPE_ELGAMAL:
|
||||
@ -596,12 +596,12 @@ namespace data
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> PrivateKeys::CreateDecryptor (CryptoKeyType cryptoType, const uint8_t * key)
|
||||
{
|
||||
{
|
||||
if (!key) return nullptr;
|
||||
switch (cryptoType)
|
||||
{
|
||||
@ -618,7 +618,7 @@ namespace data
|
||||
default:
|
||||
LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType);
|
||||
};
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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_SHA512_4096:
|
||||
LogPrint (eLogWarning, "Identity: RSA signature type is not supported. Create EdDSA");
|
||||
// no break here
|
||||
// no break here
|
||||
case SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519:
|
||||
i2p::crypto::CreateEDDSA25519RandomKeys (keys.m_SigningPrivateKey, signingPublicKey);
|
||||
break;
|
||||
@ -685,7 +685,7 @@ namespace data
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "Identity: Crypto key type ", (int)type, " is not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys CreateRandomKeys ()
|
||||
|
@ -96,7 +96,7 @@ namespace data
|
||||
const IdentHash& GetIdentHash () const { return m_IdentHash; };
|
||||
const uint8_t * GetEncryptionPublicKey () const { 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 GetSigningPublicKeyLen () const;
|
||||
size_t GetSigningPrivateKeyLen () const;
|
||||
|
@ -11,7 +11,7 @@ namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
|
||||
|
||||
LeaseSet::LeaseSet (const uint8_t * buf, size_t len, bool storeLeases):
|
||||
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)
|
||||
{
|
||||
{
|
||||
if (len > m_BufferLen)
|
||||
{
|
||||
auto oldBuffer = m_Buffer;
|
||||
m_Buffer = new uint8_t[len];
|
||||
delete[] oldBuffer;
|
||||
}
|
||||
}
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
ReadFromBuffer (false);
|
||||
@ -38,10 +38,10 @@ namespace data
|
||||
{
|
||||
m_StoreLeases = true;
|
||||
ReadFromBuffer (false);
|
||||
}
|
||||
|
||||
void LeaseSet::ReadFromBuffer (bool readIdentity)
|
||||
{
|
||||
}
|
||||
|
||||
void LeaseSet::ReadFromBuffer (bool readIdentity)
|
||||
{
|
||||
if (readIdentity || !m_Identity)
|
||||
m_Identity = std::make_shared<IdentityEx>(m_Buffer, m_BufferLen);
|
||||
size_t size = m_Identity->GetFullLen ();
|
||||
@ -58,17 +58,17 @@ namespace data
|
||||
size++; // num
|
||||
LogPrint (eLogDebug, "LeaseSet: read num=", (int)num);
|
||||
if (!num || num > MAX_NUM_LEASES)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogError, "LeaseSet: incorrect number of leases", (int)num);
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// reset existing leases
|
||||
if (m_StoreLeases)
|
||||
for (auto& it: m_Leases)
|
||||
it->isUpdated = false;
|
||||
else
|
||||
else
|
||||
m_Leases.clear ();
|
||||
|
||||
// process leases
|
||||
@ -82,14 +82,14 @@ namespace data
|
||||
leases += 32; // gateway
|
||||
lease.tunnelID = bufbe32toh (leases);
|
||||
leases += 4; // tunnel ID
|
||||
lease.endDate = bufbe64toh (leases);
|
||||
lease.endDate = bufbe64toh (leases);
|
||||
leases += 8; // end date
|
||||
if (ts < lease.endDate + LEASE_ENDDATE_THRESHOLD)
|
||||
{
|
||||
{
|
||||
if (lease.endDate > m_ExpirationTime)
|
||||
m_ExpirationTime = lease.endDate;
|
||||
if (m_StoreLeases)
|
||||
{
|
||||
{
|
||||
auto ret = m_Leases.insert (std::make_shared<Lease>(lease));
|
||||
if (!ret.second) (*ret.first)->endDate = lease.endDate; // update existing
|
||||
(*ret.first)->isUpdated = true;
|
||||
@ -100,28 +100,28 @@ namespace data
|
||||
LogPrint (eLogInfo, "LeaseSet: Lease's tunnel gateway not found, requesting");
|
||||
netdb.RequestDestination (lease.tunnelGateway);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "LeaseSet: Lease is expired already ");
|
||||
}
|
||||
}
|
||||
if (!m_ExpirationTime)
|
||||
{
|
||||
LogPrint (eLogWarning, "LeaseSet: all leases are expired. Dropped");
|
||||
m_IsValid = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_ExpirationTime += LEASE_ENDDATE_THRESHOLD;
|
||||
// delete old leases
|
||||
// delete old leases
|
||||
if (m_StoreLeases)
|
||||
{
|
||||
{
|
||||
for (auto it = m_Leases.begin (); it != m_Leases.end ();)
|
||||
{
|
||||
{
|
||||
if (!(*it)->isUpdated)
|
||||
{
|
||||
(*it)->endDate = 0; // somebody might still hold it
|
||||
m_Leases.erase (it++);
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
@ -133,9 +133,9 @@ namespace data
|
||||
LogPrint (eLogWarning, "LeaseSet: verification failed");
|
||||
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;
|
||||
size_t size = m_Identity->GetFullLen ();
|
||||
@ -150,18 +150,18 @@ namespace data
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
size += 36; // gateway (32) + tunnelId(4)
|
||||
auto endDate = bufbe64toh (buf + size);
|
||||
auto endDate = bufbe64toh (buf + size);
|
||||
size += 8; // end date
|
||||
if (!timestamp || endDate < timestamp)
|
||||
timestamp = endDate;
|
||||
}
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
bool LeaseSet::IsNewer (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
return ExtractTimestamp (buf, len) > ExtractTimestamp (m_Buffer, m_BufferLen);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
const std::vector<std::shared_ptr<const Lease> > LeaseSet::GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold) const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
@ -189,9 +189,9 @@ namespace data
|
||||
endDate -= LEASE_ENDDATE_THRESHOLD;
|
||||
if (ts < endDate && !exclude(*it))
|
||||
leases.push_back (it);
|
||||
}
|
||||
return leases;
|
||||
}
|
||||
}
|
||||
return leases;
|
||||
}
|
||||
|
||||
bool LeaseSet::HasExpiredLeases () const
|
||||
{
|
||||
@ -199,7 +199,7 @@ namespace data
|
||||
for (const auto& it: m_Leases)
|
||||
if (ts >= it->endDate) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LeaseSet::IsExpired () const
|
||||
{
|
||||
@ -222,15 +222,15 @@ namespace data
|
||||
if (num > MAX_NUM_LEASES) num = MAX_NUM_LEASES;
|
||||
// identity
|
||||
auto signingKeyLen = m_Identity->GetSigningPublicKeyLen ();
|
||||
m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen ();
|
||||
m_Buffer = new uint8_t[m_BufferLen];
|
||||
m_BufferLen = m_Identity->GetFullLen () + 256 + signingKeyLen + 1 + num*LEASE_SIZE + m_Identity->GetSignatureLen ();
|
||||
m_Buffer = new uint8_t[m_BufferLen];
|
||||
auto offset = m_Identity->ToBuffer (m_Buffer, m_BufferLen);
|
||||
memcpy (m_Buffer + offset, encryptionPublicKey, 256);
|
||||
offset += 256;
|
||||
memset (m_Buffer + offset, 0, signingKeyLen);
|
||||
offset += signingKeyLen;
|
||||
// num leases
|
||||
m_Buffer[offset] = num;
|
||||
m_Buffer[offset] = num;
|
||||
offset++;
|
||||
// leases
|
||||
m_Leases = m_Buffer + offset;
|
||||
@ -257,13 +257,13 @@ namespace data
|
||||
{
|
||||
m_BufferLen = len;
|
||||
m_Buffer = new uint8_t[m_BufferLen];
|
||||
memcpy (m_Buffer, buf, len);
|
||||
memcpy (m_Buffer, buf, len);
|
||||
}
|
||||
|
||||
bool LocalLeaseSet::IsExpired () const
|
||||
{
|
||||
auto ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
return ts > m_ExpirationTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,11 +14,11 @@ namespace i2p
|
||||
|
||||
namespace tunnel
|
||||
{
|
||||
class InboundTunnel;
|
||||
class InboundTunnel;
|
||||
}
|
||||
|
||||
namespace data
|
||||
{
|
||||
{
|
||||
const int LEASE_ENDDATE_THRESHOLD = 51000; // in milliseconds
|
||||
struct Lease
|
||||
{
|
||||
@ -33,24 +33,24 @@ namespace data
|
||||
if (endDate < expire) return true;
|
||||
return (endDate - expire) < t;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct LeaseCmp
|
||||
{
|
||||
bool operator() (std::shared_ptr<const Lease> l1, std::shared_ptr<const Lease> l2) const
|
||||
{
|
||||
{
|
||||
if (l1->tunnelID != l2->tunnelID)
|
||||
return l1->tunnelID < l2->tunnelID;
|
||||
return l1->tunnelID < l2->tunnelID;
|
||||
else
|
||||
return l1->tunnelGateway < l2->tunnelGateway;
|
||||
return l1->tunnelGateway < l2->tunnelGateway;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
typedef std::function<bool(const Lease & l)> LeaseInspectFunc;
|
||||
|
||||
|
||||
const size_t MAX_LS_BUFFER_SIZE = 3072;
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -59,10 +59,10 @@ namespace data
|
||||
~LeaseSet () { delete[] m_Buffer; };
|
||||
void Update (const uint8_t * buf, size_t len);
|
||||
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; };
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
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> > GetNonExpiredLeasesExcluding (LeaseInspectFunc exclude, bool withThreshold = true) const;
|
||||
@ -71,8 +71,8 @@ namespace data
|
||||
bool IsEmpty () const { return m_Leases.empty (); };
|
||||
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
|
||||
bool ExpiresSoon(const uint64_t dlt=1000 * 5, const uint64_t fudge = 0) const ;
|
||||
bool operator== (const LeaseSet& other) const
|
||||
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
|
||||
bool operator== (const LeaseSet& other) const
|
||||
{ return m_BufferLen == other.m_BufferLen && !memcmp (m_Buffer, other.m_Buffer, m_BufferLen); };
|
||||
|
||||
// implements RoutingDestination
|
||||
std::shared_ptr<const IdentityEx> GetIdentity () const { return m_Identity; };
|
||||
@ -83,7 +83,7 @@ namespace data
|
||||
|
||||
void ReadFromBuffer (bool readIdentity = true);
|
||||
uint64_t ExtractTimestamp (const uint8_t * buf, size_t len) const; // min expiration time
|
||||
|
||||
|
||||
private:
|
||||
|
||||
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_Buffer;
|
||||
size_t m_BufferLen;
|
||||
};
|
||||
};
|
||||
|
||||
class LocalLeaseSet
|
||||
{
|
||||
@ -104,27 +104,27 @@ namespace data
|
||||
~LocalLeaseSet () { delete[] m_Buffer; };
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||
uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); };
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
uint8_t * GetSignature () { return m_Buffer + m_BufferLen - GetSignatureLen (); };
|
||||
size_t GetBufferLen () const { return m_BufferLen; };
|
||||
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 (); };
|
||||
bool IsExpired () const;
|
||||
uint64_t GetExpirationTime () const { return m_ExpirationTime; };
|
||||
void SetExpirationTime (uint64_t expirationTime) { m_ExpirationTime = expirationTime; };
|
||||
bool operator== (const LeaseSet& other) const
|
||||
{ return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); };
|
||||
bool operator== (const LeaseSet& other) const
|
||||
{ return m_BufferLen == other.GetBufferLen () && !memcmp (other.GetBuffer (), other.GetBuffer (), m_BufferLen); };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
uint64_t m_ExpirationTime; // in milliseconds
|
||||
std::shared_ptr<const IdentityEx> m_Identity;
|
||||
uint8_t * m_Buffer, * m_Leases;
|
||||
size_t m_BufferLen;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -44,7 +44,7 @@ enum LogType {
|
||||
|
||||
namespace i2p {
|
||||
namespace log {
|
||||
|
||||
|
||||
struct LogMsg; /* forward declaration */
|
||||
|
||||
class Log
|
||||
@ -146,7 +146,7 @@ namespace log {
|
||||
std::string text; /**< message text as single string */
|
||||
LogLevel level; /**< message level */
|
||||
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) {};
|
||||
};
|
||||
|
||||
@ -185,7 +185,7 @@ void LogPrint (LogLevel level, TArgs&&... args) noexcept
|
||||
std::stringstream ss("");
|
||||
|
||||
LogPrint (ss, std::forward<TArgs>(args)...);
|
||||
|
||||
|
||||
auto msg = std::make_shared<i2p::log::LogMsg>(level, std::time(nullptr), ss.str());
|
||||
msg->tid = std::this_thread::get_id();
|
||||
log.Append(msg);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
{
|
||||
const int NETDB_MIN_ROUTERS = 90;
|
||||
const int NETDB_FLOODFILL_EXPIRATION_TIMEOUT = 60*60; // 1 hour, in seconds
|
||||
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;
|
||||
|
||||
/** 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 */
|
||||
typedef std::function<bool(std::shared_ptr<const i2p::data::RouterInfo>)> RouterInfoFilter;
|
||||
|
||||
|
||||
class NetDb
|
||||
{
|
||||
public:
|
||||
@ -51,7 +51,7 @@ namespace data
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
|
||||
bool AddRouterInfo (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);
|
||||
@ -59,12 +59,12 @@ namespace data
|
||||
std::shared_ptr<LeaseSet> FindLeaseSet (const IdentHash& destination) const;
|
||||
std::shared_ptr<RouterProfile> FindRouterProfile (const IdentHash& ident) const;
|
||||
|
||||
void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr);
|
||||
void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, 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 HandleDatabaseStoreMsg (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 (std::shared_ptr<const RouterInfo> compatibleWith) const;
|
||||
@ -76,13 +76,13 @@ namespace data
|
||||
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> 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);
|
||||
|
||||
/** 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 ();
|
||||
Families& GetFamilies () { return m_Families; };
|
||||
|
||||
@ -108,28 +108,28 @@ namespace data
|
||||
bool LoadRouterInfo (const std::string & path);
|
||||
void SaveUpdated ();
|
||||
void Run (); // exploratory thread
|
||||
void Explore (int numDestinations);
|
||||
void Explore (int numDestinations);
|
||||
void Publish ();
|
||||
void ManageLeaseSets ();
|
||||
void ManageRequests ();
|
||||
|
||||
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
|
||||
|
||||
|
||||
template<typename Filter>
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
||||
|
||||
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
mutable std::mutex m_LeaseSetsMutex;
|
||||
std::map<IdentHash, std::shared_ptr<LeaseSet> > m_LeaseSets;
|
||||
mutable std::mutex m_RouterInfosMutex;
|
||||
std::map<IdentHash, std::shared_ptr<RouterInfo> > m_RouterInfos;
|
||||
mutable std::mutex m_FloodfillsMutex;
|
||||
std::list<std::shared_ptr<RouterInfo> > m_Floodfills;
|
||||
|
||||
|
||||
bool m_IsRunning;
|
||||
uint64_t m_LastLoad;
|
||||
std::thread * m_Thread;
|
||||
std::thread * m_Thread;
|
||||
i2p::util::Queue<std::shared_ptr<const I2NPMessage> > m_Queue; // of I2NPDatabaseStoreMsg
|
||||
|
||||
GzipInflator m_Inflator;
|
||||
@ -137,12 +137,12 @@ namespace data
|
||||
Families m_Families;
|
||||
i2p::fs::HashedStorage m_Storage;
|
||||
|
||||
friend class NetDbRequests;
|
||||
friend class NetDbRequests;
|
||||
NetDbRequests m_Requests;
|
||||
|
||||
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/
|
||||
std::shared_ptr<RouterInfo> m_FloodfillBootstrap;
|
||||
|
||||
|
||||
|
||||
/** true if in hidden mode */
|
||||
bool m_HiddenMode;
|
||||
|
@ -13,8 +13,8 @@ namespace data
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> msg;
|
||||
if(replyTunnel)
|
||||
msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
|
||||
msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination,
|
||||
replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory,
|
||||
&m_ExcludedPeers);
|
||||
else
|
||||
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_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
m_ExcludedPeers.insert (floodfill);
|
||||
m_CreationTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
void RequestedDestination::ClearExcludedPeers ()
|
||||
{
|
||||
m_ExcludedPeers.clear ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RequestedDestination::Success (std::shared_ptr<RouterInfo> r)
|
||||
{
|
||||
if (m_RequestComplete)
|
||||
@ -69,15 +69,15 @@ namespace data
|
||||
std::shared_ptr<RequestedDestination> NetDbRequests::CreateRequest (const IdentHash& destination, bool isExploratory, RequestedDestination::RequestComplete requestComplete)
|
||||
{
|
||||
// request RouterInfo directly
|
||||
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
|
||||
auto dest = std::make_shared<RequestedDestination> (destination, isExploratory);
|
||||
dest->SetRequestComplete (requestComplete);
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
if (!m_RequestedDestinations.insert (std::make_pair (destination, dest)).second) // not inserted
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
auto it = m_RequestedDestinations.find (ident);
|
||||
if (it != m_RequestedDestinations.end ())
|
||||
{
|
||||
{
|
||||
request = it->second;
|
||||
m_RequestedDestinations.erase (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (request)
|
||||
{
|
||||
if (r)
|
||||
request->Success (r);
|
||||
else
|
||||
request->Fail ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<RequestedDestination> NetDbRequests::FindRequest (const IdentHash& ident) const
|
||||
@ -107,12 +107,12 @@ namespace data
|
||||
if (it != m_RequestedDestinations.end ())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NetDbRequests::ManageRequests ()
|
||||
{
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
std::unique_lock<std::mutex> l(m_RequestedDestinationsMutex);
|
||||
for (auto it = m_RequestedDestinations.begin (); it != m_RequestedDestinations.end ();)
|
||||
{
|
||||
auto& dest = it->second;
|
||||
@ -126,7 +126,7 @@ namespace data
|
||||
{
|
||||
auto pool = i2p::tunnel::tunnels.GetExploratoryPool ();
|
||||
auto outbound = pool->GetNextOutboundTunnel ();
|
||||
auto inbound = pool->GetNextInboundTunnel ();
|
||||
auto inbound = pool->GetNextInboundTunnel ();
|
||||
auto nextFloodfill = netdb.GetClosestFloodfill (dest->GetDestination (), dest->GetExcludedPeers ());
|
||||
if (nextFloodfill && outbound && inbound)
|
||||
outbound->SendTunnelDataMsg (nextFloodfill->GetIdentHash (), 0,
|
||||
@ -138,15 +138,15 @@ namespace data
|
||||
if (!outbound) LogPrint (eLogWarning, "NetDbReq: No outbound tunnels");
|
||||
if (!nextFloodfill) LogPrint (eLogWarning, "NetDbReq: No more floodfills");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!dest->IsExploratory ())
|
||||
LogPrint (eLogWarning, "NetDbReq: ", dest->GetDestination ().ToBase64 (), " not found after 7 attempts");
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // delete obsolete request
|
||||
done = true;
|
||||
|
||||
@ -154,7 +154,7 @@ namespace data
|
||||
it = m_RequestedDestinations.erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,14 +12,14 @@ namespace i2p
|
||||
namespace data
|
||||
{
|
||||
class RequestedDestination
|
||||
{
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::function<void (std::shared_ptr<RouterInfo>)> RequestComplete;
|
||||
|
||||
RequestedDestination (const IdentHash& destination, bool isExploratory = false):
|
||||
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; };
|
||||
int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); };
|
||||
@ -30,12 +30,12 @@ namespace data
|
||||
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 (const IdentHash& floodfill);
|
||||
|
||||
|
||||
void SetRequestComplete (const RequestComplete& requestComplete) { m_RequestComplete = requestComplete; };
|
||||
bool IsRequestComplete () const { return m_RequestComplete != nullptr; };
|
||||
void Success (std::shared_ptr<RouterInfo> r);
|
||||
void Fail ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
IdentHash m_Destination;
|
||||
@ -43,7 +43,7 @@ namespace data
|
||||
std::set<IdentHash> m_ExcludedPeers;
|
||||
uint64_t m_CreationTime;
|
||||
RequestComplete m_RequestComplete;
|
||||
};
|
||||
};
|
||||
|
||||
class NetDbRequests
|
||||
{
|
||||
|
@ -15,20 +15,20 @@ namespace data
|
||||
RouterProfile::RouterProfile ():
|
||||
m_LastUpdateTime (boost::posix_time::second_clock::local_time()),
|
||||
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
|
||||
{
|
||||
return boost::posix_time::second_clock::local_time();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RouterProfile::UpdateTime ()
|
||||
{
|
||||
m_LastUpdateTime = GetTime ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RouterProfile::Save (const IdentHash& identHash)
|
||||
{
|
||||
// fill sections
|
||||
@ -63,57 +63,57 @@ namespace data
|
||||
std::string path = m_ProfilesStorage.Path(ident);
|
||||
boost::property_tree::ptree pt;
|
||||
|
||||
if (!i2p::fs::Exists(path))
|
||||
if (!i2p::fs::Exists(path))
|
||||
{
|
||||
LogPrint(eLogWarning, "Profiling: no profile yet for ", ident);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
boost::property_tree::read_ini (path, pt);
|
||||
} catch (std::exception& ex)
|
||||
} catch (std::exception& ex)
|
||||
{
|
||||
/* boost exception verbose enough */
|
||||
LogPrint (eLogError, "Profiling: ", ex.what ());
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
auto t = pt.get (PEER_PROFILE_LAST_UPDATE_TIME, "");
|
||||
if (t.length () > 0)
|
||||
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
|
||||
auto participations = pt.get_child (PEER_PROFILE_SECTION_PARTICIPATION);
|
||||
m_NumTunnelsAgreed = participations.get (PEER_PROFILE_PARTICIPATION_AGREED, 0);
|
||||
m_NumTunnelsDeclined = participations.get (PEER_PROFILE_PARTICIPATION_DECLINED, 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);
|
||||
}
|
||||
try
|
||||
}
|
||||
try
|
||||
{
|
||||
// read usage
|
||||
auto usage = pt.get_child (PEER_PROFILE_SECTION_USAGE);
|
||||
m_NumTimesTaken = usage.get (PEER_PROFILE_USAGE_TAKEN, 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);
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
*this = RouterProfile ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "Profiling: Can't read profile ", ident, " :", ex.what ());
|
||||
}
|
||||
@ -126,46 +126,46 @@ namespace data
|
||||
m_NumTunnelsDeclined++;
|
||||
else
|
||||
m_NumTunnelsAgreed++;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterProfile::TunnelNonReplied ()
|
||||
{
|
||||
m_NumTunnelsNonReplied++;
|
||||
UpdateTime ();
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterProfile::IsLowPartcipationRate () const
|
||||
{
|
||||
return 4*m_NumTunnelsAgreed < m_NumTunnelsDeclined; // < 20% rate
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterProfile::IsLowReplyRate () const
|
||||
{
|
||||
auto total = m_NumTunnelsAgreed + m_NumTunnelsDeclined;
|
||||
return m_NumTunnelsNonReplied > 10*(total + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool RouterProfile::IsBad ()
|
||||
{
|
||||
{
|
||||
auto isBad = IsAlwaysDeclining () || IsLowPartcipationRate () /*|| IsLowReplyRate ()*/;
|
||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||
if (isBad && m_NumTimesRejected > 10*(m_NumTimesTaken + 1))
|
||||
{
|
||||
// reset profile
|
||||
m_NumTunnelsAgreed = 0;
|
||||
m_NumTunnelsDeclined = 0;
|
||||
m_NumTunnelsNonReplied = 0;
|
||||
isBad = false;
|
||||
}
|
||||
}
|
||||
if (isBad) m_NumTimesRejected++; else m_NumTimesTaken++;
|
||||
return isBad;
|
||||
return isBad;
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<RouterProfile> GetRouterProfile (const IdentHash& identHash)
|
||||
{
|
||||
auto profile = std::make_shared<RouterProfile> ();
|
||||
profile->Load (identHash); // if possible
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
|
||||
void InitProfilesStorage ()
|
||||
{
|
||||
@ -191,5 +191,5 @@ namespace data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,32 +8,32 @@
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
{
|
||||
// sections
|
||||
const char PEER_PROFILE_SECTION_PARTICIPATION[] = "participation";
|
||||
const char PEER_PROFILE_SECTION_USAGE[] = "usage";
|
||||
// params
|
||||
// params
|
||||
const char PEER_PROFILE_LAST_UPDATE_TIME[] = "lastupdatetime";
|
||||
const char PEER_PROFILE_PARTICIPATION_AGREED[] = "agreed";
|
||||
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_REJECTED[] = "rejected";
|
||||
|
||||
const int PEER_PROFILE_EXPIRATION_TIMEOUT = 72; // in hours (3 days)
|
||||
|
||||
|
||||
class RouterProfile
|
||||
{
|
||||
public:
|
||||
|
||||
RouterProfile ();
|
||||
RouterProfile& operator= (const RouterProfile& ) = default;
|
||||
|
||||
|
||||
void Save (const IdentHash& identHash);
|
||||
void Load (const IdentHash& identHash);
|
||||
|
||||
bool IsBad ();
|
||||
|
||||
|
||||
void TunnelBuildResponse (uint8_t ret);
|
||||
void TunnelNonReplied ();
|
||||
|
||||
@ -45,23 +45,23 @@ namespace data
|
||||
bool IsAlwaysDeclining () const { return !m_NumTunnelsAgreed && m_NumTunnelsDeclined >= 5; };
|
||||
bool IsLowPartcipationRate () const;
|
||||
bool IsLowReplyRate () const;
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
|
||||
boost::posix_time::ptime m_LastUpdateTime;
|
||||
// participation
|
||||
uint32_t m_NumTunnelsAgreed;
|
||||
uint32_t m_NumTunnelsDeclined;
|
||||
uint32_t m_NumTunnelsDeclined;
|
||||
uint32_t m_NumTunnelsNonReplied;
|
||||
// usage
|
||||
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 DeleteObsoleteProfiles ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -15,7 +15,7 @@ namespace util
|
||||
{
|
||||
template<typename Element>
|
||||
class Queue
|
||||
{
|
||||
{
|
||||
public:
|
||||
|
||||
void Put (Element e)
|
||||
@ -29,14 +29,14 @@ namespace util
|
||||
void Put (const Container<Element, R...>& vec)
|
||||
{
|
||||
if (!vec.empty ())
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
for (const auto& it: vec)
|
||||
m_Queue.push (it);
|
||||
m_Queue.push (it);
|
||||
m_NonEmpty.notify_one ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Element GetNext ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
@ -45,7 +45,7 @@ namespace util
|
||||
{
|
||||
m_NonEmpty.wait (l);
|
||||
el = GetNonThreadSafe ();
|
||||
}
|
||||
}
|
||||
return el;
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ namespace util
|
||||
{
|
||||
m_NonEmpty.wait_for (l, std::chrono::milliseconds (usec));
|
||||
el = GetNonThreadSafe ();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
bool IsEmpty ()
|
||||
{
|
||||
bool IsEmpty ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.empty ();
|
||||
}
|
||||
|
||||
int GetSize ()
|
||||
int GetSize ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return m_Queue.size ();
|
||||
}
|
||||
}
|
||||
|
||||
void WakeUp () { m_NonEmpty.notify_all (); };
|
||||
|
||||
@ -91,14 +91,14 @@ namespace util
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe ();
|
||||
}
|
||||
}
|
||||
|
||||
Element Peek ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_QueueMutex);
|
||||
return GetNonThreadSafe (true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
Element GetNonThreadSafe (bool peek = false)
|
||||
@ -109,17 +109,17 @@ namespace util
|
||||
if (!peek)
|
||||
m_Queue.pop ();
|
||||
return el;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
std::queue<Element> m_Queue;
|
||||
std::mutex m_QueueMutex;
|
||||
std::condition_variable m_NonEmpty;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
@ -23,7 +23,7 @@ namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
|
||||
|
||||
Reseeder::Reseeder()
|
||||
{
|
||||
}
|
||||
@ -114,11 +114,11 @@ namespace data
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Reseeder::ProcessSU3File (const char * filename)
|
||||
{
|
||||
std::ifstream s(filename, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
if (s.is_open ())
|
||||
return ProcessSU3Stream (s);
|
||||
else
|
||||
{
|
||||
@ -130,21 +130,21 @@ namespace data
|
||||
int Reseeder::ProcessZIPFile (const char * filename)
|
||||
{
|
||||
std::ifstream s(filename, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
{
|
||||
if (s.is_open ())
|
||||
{
|
||||
s.seekg (0, std::ios::end);
|
||||
auto len = s.tellg ();
|
||||
s.seekg (0, std::ios::beg);
|
||||
return ProcessZIPStream (s, len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Can't open file ", filename);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
const char SU3_MAGIC_NUMBER[]="I2Psu3";
|
||||
}
|
||||
|
||||
const char SU3_MAGIC_NUMBER[]="I2Psu3";
|
||||
int Reseeder::ProcessSU3Stream (std::istream& s)
|
||||
{
|
||||
char magicNumber[7];
|
||||
@ -153,7 +153,7 @@ namespace data
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Unexpected SU3 magic number");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // su3 file format version
|
||||
SigningKeyType signatureType;
|
||||
s.read ((char *)&signatureType, 2); // signature type
|
||||
@ -163,16 +163,16 @@ namespace data
|
||||
signatureLength = be16toh (signatureLength);
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t versionLength;
|
||||
s.read ((char *)&versionLength, 1); // version length
|
||||
s.read ((char *)&versionLength, 1); // version length
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t signerIDLength;
|
||||
s.read ((char *)&signerIDLength, 1); // signer ID length
|
||||
s.read ((char *)&signerIDLength, 1); // signer ID length
|
||||
uint64_t contentLength;
|
||||
s.read ((char *)&contentLength, 8); // content length
|
||||
s.read ((char *)&contentLength, 8); // content length
|
||||
contentLength = be64toh (contentLength);
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t fileType;
|
||||
s.read ((char *)&fileType, 1); // file type
|
||||
s.read ((char *)&fileType, 1); // file type
|
||||
if (fileType != 0x00) // zip file
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Can't handle file type ", (int)fileType);
|
||||
@ -180,7 +180,7 @@ namespace data
|
||||
}
|
||||
s.seekg (1, std::ios::cur); // unused
|
||||
uint8_t contentType;
|
||||
s.read ((char *)&contentType, 1); // content type
|
||||
s.read ((char *)&contentType, 1); // content type
|
||||
if (contentType != 0x03) // reseed data
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: Unexpected content type ", (int)contentType);
|
||||
@ -192,10 +192,10 @@ namespace data
|
||||
char signerID[256];
|
||||
s.read (signerID, signerIDLength); // signerID
|
||||
signerID[signerIDLength] = 0;
|
||||
|
||||
|
||||
bool verify; i2p::config::GetOption("reseed.verify", verify);
|
||||
if (verify)
|
||||
{
|
||||
{
|
||||
//try to verify signature
|
||||
auto it = m_SigningKeys.find (signerID);
|
||||
if (it != m_SigningKeys.end ())
|
||||
@ -220,7 +220,7 @@ namespace data
|
||||
BIGNUM * s = BN_new (), * n = BN_new ();
|
||||
BN_bin2bn (signature, signatureLength, s);
|
||||
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];
|
||||
i2p::crypto::bn2buf (s, enSigBuf, signatureLength);
|
||||
// digest is right aligned
|
||||
@ -232,8 +232,8 @@ namespace data
|
||||
delete[] enSigBuf;
|
||||
BN_free (s); BN_free (n);
|
||||
BN_CTX_free (bnctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete[] signature;
|
||||
delete[] tbs;
|
||||
s.seekg (pos, std::ios::beg);
|
||||
@ -249,21 +249,21 @@ namespace data
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: SU3 verification failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// handle content
|
||||
return ProcessZIPStream (s, contentLength);
|
||||
}
|
||||
|
||||
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;
|
||||
int Reseeder::ProcessZIPStream (std::istream& s, uint64_t contentLength)
|
||||
{
|
||||
{
|
||||
int numFiles = 0;
|
||||
size_t contentPos = s.tellg ();
|
||||
while (!s.eof ())
|
||||
{
|
||||
{
|
||||
uint32_t signature;
|
||||
s.read ((char *)&signature, 4);
|
||||
signature = le32toh (signature);
|
||||
@ -272,22 +272,22 @@ namespace data
|
||||
// next local file
|
||||
s.seekg (2, std::ios::cur); // version
|
||||
uint16_t bitFlag;
|
||||
s.read ((char *)&bitFlag, 2);
|
||||
s.read ((char *)&bitFlag, 2);
|
||||
bitFlag = le16toh (bitFlag);
|
||||
uint16_t compressionMethod;
|
||||
s.read ((char *)&compressionMethod, 2);
|
||||
s.read ((char *)&compressionMethod, 2);
|
||||
compressionMethod = le16toh (compressionMethod);
|
||||
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;
|
||||
s.read ((char *)&crc_32, 4);
|
||||
crc_32 = le32toh (crc_32);
|
||||
s.read ((char *)&compressedSize, 4);
|
||||
compressedSize = le32toh (compressedSize);
|
||||
s.read ((char *)&compressedSize, 4);
|
||||
compressedSize = le32toh (compressedSize);
|
||||
s.read ((char *)&uncompressedSize, 4);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
uint16_t fileNameLength, extraFieldLength;
|
||||
s.read ((char *)&fileNameLength, 2);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
uint16_t fileNameLength, extraFieldLength;
|
||||
s.read ((char *)&fileNameLength, 2);
|
||||
fileNameLength = le16toh (fileNameLength);
|
||||
if ( fileNameLength > 255 ) {
|
||||
// too big
|
||||
@ -308,13 +308,13 @@ namespace data
|
||||
{
|
||||
LogPrint (eLogError, "Reseed: SU3 archive data descriptor not found");
|
||||
return numFiles;
|
||||
}
|
||||
s.read ((char *)&crc_32, 4);
|
||||
}
|
||||
s.read ((char *)&crc_32, 4);
|
||||
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
|
||||
s.read ((char *)&uncompressedSize, 4);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
uncompressedSize = le32toh (uncompressedSize);
|
||||
|
||||
// now we know compressed and uncompressed size
|
||||
s.seekg (pos, std::ios::beg); // back to compressed data
|
||||
@ -325,8 +325,8 @@ namespace data
|
||||
{
|
||||
LogPrint (eLogWarning, "Reseed: Unexpected size 0. Skipped");
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint8_t * compressed = new uint8_t[compressedSize];
|
||||
s.read ((char *)compressed, compressedSize);
|
||||
if (compressionMethod) // we assume Deflate
|
||||
@ -338,29 +338,29 @@ namespace data
|
||||
inflator.next_in = compressed;
|
||||
inflator.avail_in = compressedSize;
|
||||
inflator.next_out = uncompressed;
|
||||
inflator.avail_out = uncompressedSize;
|
||||
inflator.avail_out = uncompressedSize;
|
||||
int err;
|
||||
if ((err = inflate (&inflator, Z_SYNC_FLUSH)) >= 0)
|
||||
{
|
||||
{
|
||||
uncompressedSize -= inflator.avail_out;
|
||||
if (crc32 (0, uncompressed, uncompressedSize) == crc_32)
|
||||
{
|
||||
i2p::data::netdb.AddRouterInfo (uncompressed, uncompressedSize);
|
||||
numFiles++;
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: CRC32 verification failed");
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: SU3 decompression error ", err);
|
||||
delete[] uncompressed;
|
||||
delete[] uncompressed;
|
||||
inflateEnd (&inflator);
|
||||
}
|
||||
else // no compression
|
||||
{
|
||||
i2p::data::netdb.AddRouterInfo (compressed, compressedSize);
|
||||
numFiles++;
|
||||
}
|
||||
}
|
||||
delete[] compressed;
|
||||
if (bitFlag & ZIP_BIT_FLAG_DATA_DESCRIPTOR)
|
||||
s.seekg (12, std::ios::cur); // skip data descriptor section if presented (12 = 16 - 4)
|
||||
@ -406,15 +406,15 @@ namespace data
|
||||
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)
|
||||
{
|
||||
size_t nextInd = 0;
|
||||
size_t nextInd = 0;
|
||||
while (!s.eof ())
|
||||
{
|
||||
uint8_t nextByte;
|
||||
s.read ((char *)&nextByte, 1);
|
||||
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
|
||||
if (nextByte == ZIP_DATA_DESCRIPTOR_SIGNATURE[nextInd])
|
||||
{
|
||||
nextInd++;
|
||||
if (nextInd >= sizeof (ZIP_DATA_DESCRIPTOR_SIGNATURE))
|
||||
@ -429,24 +429,24 @@ namespace data
|
||||
void Reseeder::LoadCertificate (const std::string& filename)
|
||||
{
|
||||
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)
|
||||
{
|
||||
{
|
||||
SSL * ssl = SSL_new (ctx);
|
||||
X509 * cert = SSL_get_certificate (ssl);
|
||||
// verify
|
||||
if (cert)
|
||||
{
|
||||
{
|
||||
// extract issuer name
|
||||
char name[100];
|
||||
X509_NAME_oneline (X509_get_issuer_name(cert), name, 100);
|
||||
char * cn = strstr (name, "CN=");
|
||||
if (cn)
|
||||
{
|
||||
{
|
||||
cn += 3;
|
||||
char * terminator = strchr (cn, '/');
|
||||
if (terminator) terminator[0] = 0;
|
||||
}
|
||||
}
|
||||
// extract RSA key (we need n only, e = 65537)
|
||||
RSA * key = EVP_PKEY_get0_RSA (X509_get_pubkey (cert));
|
||||
const BIGNUM * n, * e, * d;
|
||||
@ -457,12 +457,12 @@ namespace data
|
||||
m_SigningKeys[cn] = value;
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Can't find CN field in ", filename);
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
}
|
||||
SSL_free (ssl);
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "Reseed: Can't open certificate file ", filename);
|
||||
SSL_CTX_free (ctx);
|
||||
SSL_CTX_free (ctx);
|
||||
}
|
||||
|
||||
void Reseeder::LoadCertificates ()
|
||||
@ -483,9 +483,9 @@ namespace data
|
||||
}
|
||||
LoadCertificate (file);
|
||||
numCertificates++;
|
||||
}
|
||||
}
|
||||
LogPrint (eLogInfo, "Reseed: ", numCertificates, " certificates loaded");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Reseeder::HttpsRequest (const std::string& address)
|
||||
{
|
||||
|
@ -15,10 +15,10 @@ namespace data
|
||||
|
||||
class Reseeder
|
||||
{
|
||||
typedef Tag<512> PublicKey;
|
||||
|
||||
typedef Tag<512> PublicKey;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
Reseeder();
|
||||
~Reseeder();
|
||||
void Bootstrap ();
|
||||
@ -28,19 +28,19 @@ namespace data
|
||||
int ProcessZIPFile (const char * filename);
|
||||
|
||||
void LoadCertificates ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void LoadCertificate (const std::string& filename);
|
||||
|
||||
int ProcessSU3Stream (std::istream& s);
|
||||
int ProcessZIPStream (std::istream& s, uint64_t contentLength);
|
||||
|
||||
|
||||
int ProcessSU3Stream (std::istream& s);
|
||||
int ProcessZIPStream (std::istream& s, uint64_t contentLength);
|
||||
|
||||
bool FindZipDataDescriptor (std::istream& s);
|
||||
|
||||
|
||||
std::string HttpsRequest (const std::string& address);
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
std::map<std::string, PublicKey> m_SigningKeys;
|
||||
};
|
||||
|
@ -28,7 +28,7 @@ namespace i2p
|
||||
m_StartupTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (!Load ())
|
||||
CreateNewRouter ();
|
||||
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
||||
m_Decryptor = m_Keys.CreateDecryptor (nullptr);
|
||||
UpdateRouterInfo ();
|
||||
}
|
||||
|
||||
@ -204,7 +204,7 @@ namespace i2p
|
||||
}
|
||||
}
|
||||
|
||||
void RouterContext::SetBandwidth (char L)
|
||||
void RouterContext::SetBandwidth (char L)
|
||||
{
|
||||
uint32_t limit = 0;
|
||||
enum { low, high, extra, unlim } type = high;
|
||||
|
@ -13,7 +13,7 @@
|
||||
namespace i2p
|
||||
{
|
||||
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
|
||||
|
||||
enum RouterStatus
|
||||
@ -21,16 +21,16 @@ namespace i2p
|
||||
eRouterStatusOK = 0,
|
||||
eRouterStatusTesting = 1,
|
||||
eRouterStatusFirewalled = 2,
|
||||
eRouterStatusError = 3
|
||||
};
|
||||
eRouterStatusError = 3
|
||||
};
|
||||
|
||||
enum RouterError
|
||||
{
|
||||
eRouterErrorNone = 0,
|
||||
eRouterErrorClockSkew = 1
|
||||
};
|
||||
|
||||
class RouterContext: public i2p::garlic::GarlicDestination
|
||||
};
|
||||
|
||||
class RouterContext: public i2p::garlic::GarlicDestination
|
||||
{
|
||||
public:
|
||||
|
||||
@ -39,17 +39,17 @@ namespace i2p
|
||||
|
||||
const i2p::data::PrivateKeys& GetPrivateKeys () const { return m_Keys; };
|
||||
i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; };
|
||||
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
|
||||
{
|
||||
return std::shared_ptr<const i2p::data::RouterInfo> (&m_RouterInfo,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> GetSharedRouterInfo () const
|
||||
{
|
||||
return std::shared_ptr<const i2p::data::RouterInfo> (&m_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 *) {});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint32_t GetUptime () const;
|
||||
uint32_t GetStartupTime () const { return m_StartupTime; };
|
||||
uint64_t GetLastUpdateTime () const { return m_LastUpdateTime; };
|
||||
@ -60,17 +60,17 @@ namespace i2p
|
||||
RouterError GetError () const { return m_Error; };
|
||||
void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; };
|
||||
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 UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon
|
||||
bool AddIntroducer (const i2p::data::RouterInfo::Introducer& introducer);
|
||||
void RemoveIntroducer (const boost::asio::ip::udp::endpoint& e);
|
||||
bool IsUnreachable () const;
|
||||
void SetUnreachable ();
|
||||
void SetUnreachable ();
|
||||
void SetReachable ();
|
||||
bool IsFloodfill () const { return m_IsFloodfill; };
|
||||
void SetFloodfill (bool floodfill);
|
||||
bool IsFloodfill () const { return m_IsFloodfill; };
|
||||
void SetFloodfill (bool floodfill);
|
||||
void SetFamily (const std::string& family);
|
||||
std::string GetFamily () const;
|
||||
void SetBandwidth (int limit); /* in kilobytes */
|
||||
@ -83,14 +83,14 @@ namespace i2p
|
||||
void SetSupportsV6 (bool supportsV6);
|
||||
void SetSupportsV4 (bool supportsV4);
|
||||
|
||||
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
|
||||
void UpdateStats ();
|
||||
void UpdateNTCPV6Address (const boost::asio::ip::address& host); // called from NTCP session
|
||||
void UpdateStats ();
|
||||
void CleanupDestination (); // garlic destination
|
||||
|
||||
// implements LocalDestination
|
||||
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;
|
||||
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 () {};
|
||||
|
||||
// implements GarlicDestination
|
||||
@ -100,8 +100,8 @@ namespace i2p
|
||||
|
||||
// override GarlicDestination
|
||||
void ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
void ProcessDeliveryStatusMessage (std::shared_ptr<I2NPMessage> msg);
|
||||
|
||||
private:
|
||||
|
||||
void CreateNewRouter ();
|
||||
@ -109,11 +109,11 @@ namespace i2p
|
||||
void UpdateRouterInfo ();
|
||||
bool Load ();
|
||||
void SaveKeys ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
i2p::data::RouterInfo m_RouterInfo;
|
||||
i2p::data::PrivateKeys m_Keys;
|
||||
i2p::data::PrivateKeys m_Keys;
|
||||
std::shared_ptr<i2p::crypto::CryptoKeyDecryptor> m_Decryptor;
|
||||
uint64_t m_LastUpdateTime;
|
||||
bool m_AcceptsTunnels, m_IsFloodfill;
|
||||
@ -127,6 +127,6 @@ namespace i2p
|
||||
};
|
||||
|
||||
extern RouterContext context;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -19,20 +19,20 @@
|
||||
namespace i2p
|
||||
{
|
||||
namespace data
|
||||
{
|
||||
RouterInfo::RouterInfo (): m_Buffer (nullptr)
|
||||
{
|
||||
{
|
||||
RouterInfo::RouterInfo (): m_Buffer (nullptr)
|
||||
{
|
||||
m_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||
}
|
||||
|
||||
|
||||
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_Addresses = boost::make_shared<Addresses>(); // create empty list
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
ReadFromFile ();
|
||||
}
|
||||
}
|
||||
|
||||
RouterInfo::RouterInfo (const uint8_t * buf, int len):
|
||||
m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0)
|
||||
@ -42,13 +42,13 @@ namespace data
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
ReadFromBuffer (true);
|
||||
}
|
||||
}
|
||||
|
||||
RouterInfo::~RouterInfo ()
|
||||
{
|
||||
delete[] m_Buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RouterInfo::Update (const uint8_t * buf, int len)
|
||||
{
|
||||
// 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
|
||||
m_Properties.clear ();
|
||||
// copy buffer
|
||||
if (!m_Buffer)
|
||||
if (!m_Buffer)
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
memcpy (m_Buffer, buf, len);
|
||||
m_BufferLen = len;
|
||||
// skip identity
|
||||
size_t identityLen = m_RouterIdentity->GetFullLen ();
|
||||
// read new RI
|
||||
// read new RI
|
||||
std::stringstream str (std::string ((char *)m_Buffer + identityLen, m_BufferLen - identityLen));
|
||||
ReadFromStream (str);
|
||||
// don't delete buffer until saved to the file
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: signature verification failed");
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RouterInfo::SetRouterIdentity (std::shared_ptr<const IdentityEx> identity)
|
||||
{
|
||||
{
|
||||
m_RouterIdentity = identity;
|
||||
m_Timestamp = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
}
|
||||
|
||||
|
||||
bool RouterInfo::LoadFile ()
|
||||
{
|
||||
std::ifstream s(m_FullPath, std::ifstream::binary);
|
||||
if (s.is_open ())
|
||||
{
|
||||
if (s.is_open ())
|
||||
{
|
||||
s.seekg (0,std::ios::end);
|
||||
m_BufferLen = s.tellg ();
|
||||
if (m_BufferLen < 40 || m_BufferLen > MAX_RI_BUFFER_SIZE)
|
||||
@ -103,22 +103,22 @@ namespace data
|
||||
if (!m_Buffer)
|
||||
m_Buffer = new uint8_t[MAX_RI_BUFFER_SIZE];
|
||||
s.read((char *)m_Buffer, m_BufferLen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Can't open file ", m_FullPath);
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::ReadFromFile ()
|
||||
{
|
||||
if (LoadFile ())
|
||||
ReadFromBuffer (false);
|
||||
ReadFromBuffer (false);
|
||||
else
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
|
||||
void RouterInfo::ReadFromBuffer (bool verifySignature)
|
||||
{
|
||||
@ -131,7 +131,7 @@ namespace data
|
||||
return;
|
||||
}
|
||||
if (verifySignature)
|
||||
{
|
||||
{
|
||||
// reject RSA signatures
|
||||
if (m_RouterIdentity->IsRSA ())
|
||||
{
|
||||
@ -140,15 +140,15 @@ namespace data
|
||||
return;
|
||||
}
|
||||
// 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))
|
||||
{
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: signature verification failed");
|
||||
m_IsUnreachable = true;
|
||||
return;
|
||||
}
|
||||
m_RouterIdentity->DropVerifier ();
|
||||
}
|
||||
}
|
||||
// parse RI
|
||||
std::stringstream str;
|
||||
str.write ((const char *)m_Buffer + identityLen, m_BufferLen - identityLen);
|
||||
@ -158,17 +158,17 @@ namespace data
|
||||
LogPrint (eLogError, "RouterInfo: malformed message");
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void RouterInfo::ReadFromStream (std::istream& s)
|
||||
{
|
||||
s.read ((char *)&m_Timestamp, sizeof (m_Timestamp));
|
||||
m_Timestamp = be64toh (m_Timestamp);
|
||||
// read addresses
|
||||
auto addresses = boost::make_shared<Addresses>();
|
||||
auto addresses = boost::make_shared<Addresses>();
|
||||
uint8_t numAddresses;
|
||||
s.read ((char *)&numAddresses, sizeof (numAddresses)); if (!s) return;
|
||||
s.read ((char *)&numAddresses, sizeof (numAddresses)); if (!s) return;
|
||||
bool introducers = false;
|
||||
for (int i = 0; i < numAddresses; i++)
|
||||
{
|
||||
@ -181,11 +181,11 @@ namespace data
|
||||
if (!strcmp (transportStyle, "NTCP"))
|
||||
address->transportStyle = eTransportNTCP;
|
||||
else if (!strcmp (transportStyle, "SSU"))
|
||||
{
|
||||
{
|
||||
address->transportStyle = eTransportSSU;
|
||||
address->ssu.reset (new SSUExt ());
|
||||
address->ssu->mtu = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
address->transportStyle = eTransportUnknown;
|
||||
address->port = 0;
|
||||
@ -197,35 +197,35 @@ namespace data
|
||||
char key[255], value[255];
|
||||
r += ReadString (key, 255, s);
|
||||
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++; // ;
|
||||
if (!s) return;
|
||||
if (!strcmp (key, "host"))
|
||||
{
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
address->host = boost::asio::ip::address::from_string (value, ecode);
|
||||
if (ecode)
|
||||
{
|
||||
{
|
||||
if (address->transportStyle == eTransportNTCP)
|
||||
{
|
||||
supportedTransports |= eNTCPV4; // TODO:
|
||||
address->addressString = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
supportedTransports |= eSSUV4; // TODO:
|
||||
address->addressString = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// add supported protocol
|
||||
if (address->host.is_v4 ())
|
||||
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
||||
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV4 : eSSUV4;
|
||||
else
|
||||
supportedTransports |= (address->transportStyle == eTransportNTCP) ? eNTCPV6 : eSSUV6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "port"))
|
||||
address->port = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "mtu"))
|
||||
@ -234,21 +234,21 @@ namespace data
|
||||
address->ssu->mtu = boost::lexical_cast<int>(value);
|
||||
else
|
||||
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'mtu' for NTCP");
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "key"))
|
||||
{
|
||||
{
|
||||
if (address->ssu)
|
||||
Base64ToByteStream (value, strlen (value), address->ssu->key, 32);
|
||||
else
|
||||
LogPrint (eLogWarning, "RouterInfo: Unexpected field 'key' for NTCP");
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "caps"))
|
||||
ExtractCaps (value);
|
||||
else if (key[0] == 'i')
|
||||
{
|
||||
{
|
||||
// introducers
|
||||
introducers = true;
|
||||
size_t l = strlen(key);
|
||||
size_t l = strlen(key);
|
||||
unsigned char index = key[l-1] - '0'; // TODO:
|
||||
key[l-1] = 0;
|
||||
if (index > 9)
|
||||
@ -257,13 +257,13 @@ namespace data
|
||||
if (s) continue; else return;
|
||||
}
|
||||
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);
|
||||
if (!strcmp (key, "ihost"))
|
||||
{
|
||||
boost::system::error_code ecode;
|
||||
introducer.iHost = boost::asio::ip::address::from_string (value, ecode);
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "iport"))
|
||||
introducer.iPort = boost::lexical_cast<int>(value);
|
||||
else if (!strcmp (key, "itag"))
|
||||
@ -274,19 +274,19 @@ namespace data
|
||||
introducer.iExp = boost::lexical_cast<uint32_t>(value);
|
||||
}
|
||||
if (!s) return;
|
||||
}
|
||||
}
|
||||
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
|
||||
if (supportedTransports)
|
||||
{
|
||||
addresses->push_back(address);
|
||||
m_SupportedTransports |= supportedTransports;
|
||||
}
|
||||
}
|
||||
#if (BOOST_VERSION >= 105300)
|
||||
}
|
||||
#if (BOOST_VERSION >= 105300)
|
||||
boost::atomic_store (&m_Addresses, addresses);
|
||||
#else
|
||||
m_Addresses = addresses; // race condition
|
||||
#endif
|
||||
#endif
|
||||
// read peers
|
||||
uint8_t numPeers;
|
||||
s.read ((char *)&numPeers, sizeof (numPeers)); if (!s) return;
|
||||
@ -297,23 +297,23 @@ namespace data
|
||||
size = be16toh (size);
|
||||
while (r < size)
|
||||
{
|
||||
char key[255], value[255];
|
||||
char key[255], value[255];
|
||||
r += ReadString (key, 255, s);
|
||||
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++; // ;
|
||||
if (!s) return;
|
||||
m_Properties[key] = value;
|
||||
|
||||
// extract caps
|
||||
|
||||
// extract caps
|
||||
if (!strcmp (key, "caps"))
|
||||
ExtractCaps (value);
|
||||
// check netId
|
||||
else if (!strcmp (key, ROUTER_INFO_PROPERTY_NETID) && atoi (value) != i2p::context.GetNetID ())
|
||||
{
|
||||
LogPrint (eLogError, "RouterInfo: Unexpected ", ROUTER_INFO_PROPERTY_NETID, "=", value);
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
m_IsUnreachable = true;
|
||||
}
|
||||
// family
|
||||
else if (!strcmp (key, ROUTER_INFO_PROPERTY_FAMILY))
|
||||
{
|
||||
@ -327,10 +327,10 @@ namespace data
|
||||
LogPrint (eLogWarning, "RouterInfo: family signature verification failed");
|
||||
m_Family.clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!s) return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_SupportedTransports || !m_Addresses->size() || (UsesIntroducer () && !introducers))
|
||||
SetUnreachable (true);
|
||||
@ -358,56 +358,56 @@ namespace data
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH1:
|
||||
case CAPS_FLAG_EXTRA_BANDWIDTH2:
|
||||
m_Caps |= Caps::eExtraBandwidth;
|
||||
break;
|
||||
break;
|
||||
case CAPS_FLAG_HIDDEN:
|
||||
m_Caps |= Caps::eHidden;
|
||||
break;
|
||||
break;
|
||||
case CAPS_FLAG_REACHABLE:
|
||||
m_Caps |= Caps::eReachable;
|
||||
break;
|
||||
case CAPS_FLAG_UNREACHABLE:
|
||||
m_Caps |= Caps::eUnreachable;
|
||||
break;
|
||||
break;
|
||||
case CAPS_FLAG_SSU_TESTING:
|
||||
m_Caps |= Caps::eSSUTesting;
|
||||
break;
|
||||
break;
|
||||
case CAPS_FLAG_SSU_INTRODUCER:
|
||||
m_Caps |= Caps::eSSUIntroducer;
|
||||
break;
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
cap++;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::UpdateCapsProperty ()
|
||||
{
|
||||
{
|
||||
std::string caps;
|
||||
if (m_Caps & eFloodfill)
|
||||
if (m_Caps & eFloodfill)
|
||||
{
|
||||
if (m_Caps & eExtraBandwidth) caps += (m_Caps & eHighBandwidth) ?
|
||||
CAPS_FLAG_EXTRA_BANDWIDTH2 : // 'X'
|
||||
CAPS_FLAG_EXTRA_BANDWIDTH1; // 'P'
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
|
||||
caps += CAPS_FLAG_FLOODFILL; // floodfill
|
||||
}
|
||||
else
|
||||
caps += CAPS_FLAG_FLOODFILL; // floodfill
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Caps & eExtraBandwidth)
|
||||
{
|
||||
if (m_Caps & eExtraBandwidth)
|
||||
{
|
||||
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_EXTRA_BANDWIDTH2 /* 'X' */ : CAPS_FLAG_EXTRA_BANDWIDTH1; /*'P' */
|
||||
caps += CAPS_FLAG_HIGH_BANDWIDTH3; // 'O'
|
||||
}
|
||||
else
|
||||
caps += (m_Caps & eHighBandwidth) ? CAPS_FLAG_HIGH_BANDWIDTH3 /* 'O' */: CAPS_FLAG_LOW_BANDWIDTH2 /* 'L' */; // bandwidth
|
||||
}
|
||||
else
|
||||
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 & eReachable) caps += CAPS_FLAG_REACHABLE; // reachable
|
||||
if (m_Caps & eUnreachable) caps += CAPS_FLAG_UNREACHABLE; // unreachable
|
||||
|
||||
SetProperty ("caps", caps);
|
||||
}
|
||||
|
||||
|
||||
void RouterInfo::WriteToStream (std::ostream& s) const
|
||||
{
|
||||
uint64_t ts = htobe64 (m_Timestamp);
|
||||
@ -425,7 +425,7 @@ namespace data
|
||||
if (address.transportStyle == eTransportNTCP)
|
||||
WriteString ("NTCP", s);
|
||||
else if (address.transportStyle == eTransportSSU)
|
||||
{
|
||||
{
|
||||
WriteString ("SSU", s);
|
||||
// caps
|
||||
WriteString ("caps", properties);
|
||||
@ -435,7 +435,7 @@ namespace data
|
||||
if (IsIntroducer ()) caps += CAPS_FLAG_SSU_INTRODUCER;
|
||||
WriteString (caps, properties);
|
||||
properties << ';';
|
||||
}
|
||||
}
|
||||
else
|
||||
WriteString ("", s);
|
||||
|
||||
@ -447,7 +447,7 @@ namespace data
|
||||
{
|
||||
// write introducers if any
|
||||
if (address.ssu->introducers.size () > 0)
|
||||
{
|
||||
{
|
||||
int i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
@ -456,7 +456,7 @@ namespace data
|
||||
WriteString (introducer.iHost.to_string (), properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
@ -468,7 +468,7 @@ namespace data
|
||||
WriteString (value, properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
@ -477,7 +477,7 @@ namespace data
|
||||
WriteString (boost::lexical_cast<std::string>(introducer.iPort), properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
@ -486,7 +486,7 @@ namespace data
|
||||
WriteString (boost::lexical_cast<std::string>(introducer.iTag), properties);
|
||||
properties << ';';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
i = 0;
|
||||
for (const auto& introducer: address.ssu->introducers)
|
||||
{
|
||||
@ -498,8 +498,8 @@ namespace data
|
||||
properties << ';';
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// write intro key
|
||||
WriteString ("key", properties);
|
||||
properties << '=';
|
||||
@ -515,17 +515,17 @@ namespace data
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(address.ssu->mtu), properties);
|
||||
properties << ';';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteString ("port", properties);
|
||||
properties << '=';
|
||||
WriteString (boost::lexical_cast<std::string>(address.port), properties);
|
||||
properties << ';';
|
||||
|
||||
|
||||
uint16_t size = htobe16 (properties.str ().size ());
|
||||
s.write ((char *)&size, sizeof (size));
|
||||
s.write (properties.str ().c_str (), properties.str ().size ());
|
||||
}
|
||||
}
|
||||
|
||||
// peers
|
||||
uint8_t numPeers = 0;
|
||||
@ -539,18 +539,18 @@ namespace data
|
||||
properties << '=';
|
||||
WriteString (p.second, properties);
|
||||
properties << ';';
|
||||
}
|
||||
}
|
||||
uint16_t size = htobe16 (properties.str ().size ());
|
||||
s.write ((char *)&size, sizeof (size));
|
||||
s.write (properties.str ().c_str (), properties.str ().size ());
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNewer (const uint8_t * buf, size_t len) const
|
||||
{
|
||||
if (!m_RouterIdentity) return false;
|
||||
size_t size = m_RouterIdentity->GetFullLen ();
|
||||
if (size + 8 > len) return false;
|
||||
return bufbe64toh (buf + size) > m_Timestamp;
|
||||
return bufbe64toh (buf + size) > m_Timestamp;
|
||||
}
|
||||
|
||||
const uint8_t * RouterInfo::LoadBuffer ()
|
||||
@ -559,8 +559,8 @@ namespace data
|
||||
{
|
||||
if (LoadFile ())
|
||||
LogPrint (eLogDebug, "RouterInfo: Buffer for ", GetIdentHashAbbreviation (GetIdentHash ()), " loaded from file");
|
||||
}
|
||||
return m_Buffer;
|
||||
}
|
||||
return m_Buffer;
|
||||
}
|
||||
|
||||
void RouterInfo::CreateBuffer (const PrivateKeys& privateKeys)
|
||||
@ -569,7 +569,7 @@ namespace data
|
||||
std::stringstream s;
|
||||
uint8_t ident[1024];
|
||||
auto identLen = privateKeys.GetPublic ()->ToBuffer (ident, 1024);
|
||||
s.write ((char *)ident, identLen);
|
||||
s.write ((char *)ident, identLen);
|
||||
WriteToStream (s);
|
||||
m_BufferLen = s.str ().size ();
|
||||
if (!m_Buffer)
|
||||
@ -578,7 +578,7 @@ namespace data
|
||||
// signature
|
||||
privateKeys.Sign ((uint8_t *)m_Buffer, m_BufferLen, (uint8_t *)m_Buffer + m_BufferLen);
|
||||
m_BufferLen += privateKeys.GetPublic ()->GetSignatureLen ();
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterInfo::SaveToFile (const std::string& fullPath)
|
||||
{
|
||||
@ -595,13 +595,13 @@ namespace data
|
||||
f.write ((char *)m_Buffer, m_BufferLen);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
size_t RouterInfo::ReadString (char * str, size_t len, std::istream& s) const
|
||||
{
|
||||
uint8_t l;
|
||||
s.read ((char *)&l, 1);
|
||||
if (l < len)
|
||||
{
|
||||
{
|
||||
s.read (str, l);
|
||||
if (!s) l = 0; // failed, return empty string
|
||||
str[l] = 0;
|
||||
@ -611,16 +611,16 @@ namespace data
|
||||
LogPrint (eLogWarning, "RouterInfo: string length ", (int)l, " exceeds buffer size ", len);
|
||||
s.seekg (l, std::ios::cur); // skip
|
||||
str[0] = 0;
|
||||
}
|
||||
}
|
||||
return l+1;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::WriteString (const std::string& str, std::ostream& s) const
|
||||
{
|
||||
uint8_t len = str.size ();
|
||||
s.write ((char *)&len, 1);
|
||||
s.write (str.c_str (), len);
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::AddNTCPAddress (const char * host, int port)
|
||||
{
|
||||
@ -634,7 +634,7 @@ namespace data
|
||||
if (*it == *addr) return;
|
||||
m_SupportedTransports |= addr->host.is_v6 () ? eNTCPV6 : eNTCPV4;
|
||||
m_Addresses->push_back(std::move(addr));
|
||||
}
|
||||
}
|
||||
|
||||
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->date = 0;
|
||||
addr->ssu.reset (new SSUExt ());
|
||||
addr->ssu->mtu = mtu;
|
||||
addr->ssu->mtu = mtu;
|
||||
memcpy (addr->ssu->key, key, 32);
|
||||
for (const auto& it: *m_Addresses) // don't insert same address twice
|
||||
if (*it == *addr) return;
|
||||
@ -654,37 +654,37 @@ namespace data
|
||||
|
||||
m_Caps |= eSSUTesting;
|
||||
m_Caps |= eSSUIntroducer;
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterInfo::AddIntroducer (const Introducer& introducer)
|
||||
{
|
||||
for (auto& addr : *m_Addresses)
|
||||
{
|
||||
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
|
||||
{
|
||||
{
|
||||
for (auto& intro: addr->ssu->introducers)
|
||||
if (intro.iTag == introducer.iTag) return false; // already presented
|
||||
addr->ssu->introducers.push_back (introducer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterInfo::RemoveIntroducer (const boost::asio::ip::udp::endpoint& e)
|
||||
{
|
||||
{
|
||||
for (auto& addr: *m_Addresses)
|
||||
{
|
||||
if (addr->transportStyle == eTransportSSU && addr->host.is_v4 ())
|
||||
{
|
||||
{
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -693,39 +693,39 @@ namespace data
|
||||
m_Caps = caps;
|
||||
UpdateCapsProperty ();
|
||||
}
|
||||
|
||||
|
||||
void RouterInfo::SetCaps (const char * caps)
|
||||
{
|
||||
SetProperty ("caps", caps);
|
||||
m_Caps = 0;
|
||||
ExtractCaps (caps);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RouterInfo::SetProperty (const std::string& key, const std::string& value)
|
||||
{
|
||||
m_Properties[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::DeleteProperty (const std::string& 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);
|
||||
if (it != m_Properties.end ())
|
||||
return it->second;
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool RouterInfo::IsNTCP (bool v4only) const
|
||||
{
|
||||
if (v4only)
|
||||
return m_SupportedTransports & eNTCPV4;
|
||||
else
|
||||
return m_SupportedTransports & (eNTCPV4 | eNTCPV6);
|
||||
}
|
||||
}
|
||||
|
||||
bool RouterInfo::IsSSU (bool v4only) const
|
||||
{
|
||||
@ -744,7 +744,7 @@ namespace data
|
||||
{
|
||||
return m_SupportedTransports & (eNTCPV4 | eSSUV4);
|
||||
}
|
||||
|
||||
|
||||
void RouterInfo::EnableV6 ()
|
||||
{
|
||||
if (!IsV6 ())
|
||||
@ -756,13 +756,13 @@ namespace data
|
||||
if (!IsV4 ())
|
||||
m_SupportedTransports |= eNTCPV4 | eSSUV4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RouterInfo::DisableV6 ()
|
||||
{
|
||||
{
|
||||
if (IsV6 ())
|
||||
{
|
||||
m_SupportedTransports &= ~(eNTCPV6 | eSSUV6);
|
||||
{
|
||||
m_SupportedTransports &= ~(eNTCPV6 | eSSUV6);
|
||||
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
|
||||
{
|
||||
auto addr = *it;
|
||||
@ -770,15 +770,15 @@ namespace data
|
||||
it = m_Addresses->erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::DisableV4 ()
|
||||
{
|
||||
{
|
||||
if (IsV4 ())
|
||||
{
|
||||
m_SupportedTransports &= ~(eNTCPV4 | eSSUV4);
|
||||
{
|
||||
m_SupportedTransports &= ~(eNTCPV4 | eSSUV4);
|
||||
for (auto it = m_Addresses->begin (); it != m_Addresses->end ();)
|
||||
{
|
||||
auto addr = *it;
|
||||
@ -786,55 +786,55 @@ namespace data
|
||||
it = m_Addresses->erase (it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool RouterInfo::UsesIntroducer () const
|
||||
{
|
||||
return m_Caps & Caps::eUnreachable; // non-reachable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetNTCPAddress (bool v4only) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetSSUV6Address () const
|
||||
{
|
||||
return GetAddress (eTransportSSU, false, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<const RouterInfo::Address> RouterInfo::GetAddress (TransportStyle s, bool v4only, bool v6only) const
|
||||
{
|
||||
#if (BOOST_VERSION >= 105300)
|
||||
auto addresses = boost::atomic_load (&m_Addresses);
|
||||
#else
|
||||
#else
|
||||
auto addresses = m_Addresses;
|
||||
#endif
|
||||
#endif
|
||||
for (const auto& address : *addresses)
|
||||
{
|
||||
if (address->transportStyle == s)
|
||||
{
|
||||
{
|
||||
if ((!v4only || address->host.is_v4 ()) && (!v6only || address->host.is_v6 ()))
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
|
||||
std::shared_ptr<RouterProfile> RouterInfo::GetProfile () const
|
||||
{
|
||||
if (!m_Profile)
|
||||
m_Profile = GetRouterProfile (GetIdentHash ());
|
||||
return m_Profile;
|
||||
}
|
||||
}
|
||||
|
||||
void RouterInfo::Encrypt (const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx) const
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "Identity.h"
|
||||
#include "Profiling.h"
|
||||
|
||||
@ -17,15 +17,15 @@ namespace i2p
|
||||
namespace data
|
||||
{
|
||||
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_FAMILY[] = "family";
|
||||
const char ROUTER_INFO_PROPERTY_FAMILY[] = "family";
|
||||
const char ROUTER_INFO_PROPERTY_FAMILY_SIG[] = "family.sig";
|
||||
|
||||
|
||||
const char CAPS_FLAG_FLOODFILL = 'f';
|
||||
const char CAPS_FLAG_HIDDEN = 'H';
|
||||
const char CAPS_FLAG_REACHABLE = 'R';
|
||||
const char CAPS_FLAG_UNREACHABLE = 'U';
|
||||
const char CAPS_FLAG_UNREACHABLE = 'U';
|
||||
/* bandwidth flags */
|
||||
const char CAPS_FLAG_LOW_BANDWIDTH1 = 'K'; /* < 12 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_EXTRA_BANDWIDTH1 = 'P'; /* 256-2000 KBps */
|
||||
const char CAPS_FLAG_EXTRA_BANDWIDTH2 = 'X'; /* > 2000 KBps */
|
||||
|
||||
|
||||
const char CAPS_FLAG_SSU_TESTING = 'B';
|
||||
const char CAPS_FLAG_SSU_INTRODUCER = 'C';
|
||||
|
||||
@ -44,13 +44,13 @@ namespace data
|
||||
public:
|
||||
|
||||
enum SupportedTranports
|
||||
{
|
||||
{
|
||||
eNTCPV4 = 0x01,
|
||||
eNTCPV6 = 0x02,
|
||||
eSSUV4 = 0x04,
|
||||
eSSUV6 = 0x08
|
||||
};
|
||||
|
||||
|
||||
enum Caps
|
||||
{
|
||||
eFloodfill = 0x01,
|
||||
@ -71,7 +71,7 @@ namespace data
|
||||
};
|
||||
|
||||
typedef Tag<32> IntroKey; // should be castable to MacKey and AESKey
|
||||
struct Introducer
|
||||
struct Introducer
|
||||
{
|
||||
Introducer (): iExp (0) {};
|
||||
boost::asio::ip::address iHost;
|
||||
@ -85,9 +85,9 @@ namespace data
|
||||
{
|
||||
int mtu;
|
||||
IntroKey key; // intro key for SSU
|
||||
std::vector<Introducer> introducers;
|
||||
std::vector<Introducer> introducers;
|
||||
};
|
||||
|
||||
|
||||
struct Address
|
||||
{
|
||||
TransportStyle transportStyle;
|
||||
@ -98,23 +98,23 @@ namespace data
|
||||
uint8_t cost;
|
||||
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 ()) ||
|
||||
(host.is_v6 () && other.is_v6 ());
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Address& other) const
|
||||
{
|
||||
return transportStyle == other.transportStyle && host == other.host && port == other.port;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator!=(const Address& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
}
|
||||
};
|
||||
typedef std::list<std::shared_ptr<Address> > Addresses;
|
||||
typedef std::list<std::shared_ptr<Address> > Addresses;
|
||||
|
||||
RouterInfo ();
|
||||
RouterInfo (const std::string& fullPath);
|
||||
@ -122,7 +122,7 @@ namespace data
|
||||
RouterInfo& operator=(const RouterInfo& ) = default;
|
||||
RouterInfo (const uint8_t * buf, int len);
|
||||
~RouterInfo ();
|
||||
|
||||
|
||||
std::shared_ptr<const IdentityEx> GetRouterIdentity () const { return m_RouterIdentity; };
|
||||
void SetRouterIdentity (std::shared_ptr<const IdentityEx> identity);
|
||||
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> GetSSUAddress (bool v4only = true) const;
|
||||
std::shared_ptr<const Address> GetSSUV6Address () const;
|
||||
|
||||
|
||||
void AddNTCPAddress (const char * host, int port);
|
||||
void AddSSUAddress (const char * host, int port, const uint8_t * key, int mtu = 0);
|
||||
bool AddIntroducer (const Introducer& introducer);
|
||||
@ -156,37 +156,37 @@ namespace data
|
||||
bool IsPeerTesting () const { return m_Caps & eSSUTesting; };
|
||||
bool IsHidden () const { return m_Caps & eHidden; };
|
||||
bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; };
|
||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; };
|
||||
|
||||
uint8_t GetCaps () const { return m_Caps; };
|
||||
void SetCaps (uint8_t 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; };
|
||||
|
||||
const uint8_t * GetBuffer () const { return m_Buffer; };
|
||||
const uint8_t * LoadBuffer (); // load if necessary
|
||||
int GetBufferLen () const { return m_BufferLen; };
|
||||
int GetBufferLen () const { return m_BufferLen; };
|
||||
void CreateBuffer (const PrivateKeys& privateKeys);
|
||||
|
||||
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);
|
||||
|
||||
std::shared_ptr<RouterProfile> GetProfile () const;
|
||||
void SaveProfile () { if (m_Profile) m_Profile->Save (GetIdentHash ()); };
|
||||
|
||||
|
||||
void Update (const uint8_t * buf, int len);
|
||||
void DeleteBuffer () { delete[] m_Buffer; m_Buffer = nullptr; };
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
bool IsNewer (const uint8_t * buf, size_t len) const;
|
||||
|
||||
/** return true if we are in a router family and the signature is valid */
|
||||
bool IsFamily(const std::string & fam) const;
|
||||
|
||||
|
||||
// implements RoutingDestination
|
||||
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; };
|
||||
|
||||
@ -201,7 +201,7 @@ namespace data
|
||||
void WriteString (const std::string& str, std::ostream& s) const;
|
||||
void ExtractCaps (const char * value);
|
||||
std::shared_ptr<const Address> GetAddress (TransportStyle s, bool v4only, bool v6only = false) const;
|
||||
void UpdateCapsProperty ();
|
||||
void UpdateCapsProperty ();
|
||||
|
||||
private:
|
||||
|
||||
@ -210,13 +210,13 @@ namespace data
|
||||
uint8_t * m_Buffer;
|
||||
size_t m_BufferLen;
|
||||
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;
|
||||
bool m_IsUpdated, m_IsUnreachable;
|
||||
uint8_t m_SupportedTransports, m_Caps;
|
||||
mutable std::shared_ptr<RouterProfile> m_Profile;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
300
libi2pd/SSU.cpp
300
libi2pd/SSU.cpp
@ -13,32 +13,32 @@ namespace transport
|
||||
|
||||
SSUServer::SSUServer (const boost::asio::ip::address & addr, int port):
|
||||
m_OnlyV6(true), m_IsRunning(false),
|
||||
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
|
||||
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
|
||||
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
|
||||
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
|
||||
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
|
||||
m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
|
||||
m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
|
||||
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
|
||||
m_TerminationTimerV6 (m_ServiceV6)
|
||||
m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
|
||||
m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
|
||||
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
|
||||
m_TerminationTimerV6 (m_ServiceV6)
|
||||
{
|
||||
OpenSocketV6 ();
|
||||
}
|
||||
|
||||
|
||||
SSUServer::SSUServer (int port):
|
||||
m_OnlyV6(false), m_IsRunning(false),
|
||||
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_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
|
||||
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
|
||||
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_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service),
|
||||
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6)
|
||||
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6)
|
||||
{
|
||||
OpenSocket ();
|
||||
if (context.SupportsV6 ())
|
||||
OpenSocketV6 ();
|
||||
}
|
||||
|
||||
|
||||
SSUServer::~SSUServer ()
|
||||
{
|
||||
}
|
||||
@ -46,11 +46,11 @@ namespace transport
|
||||
void SSUServer::OpenSocket ()
|
||||
{
|
||||
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.bind (m_Endpoint);
|
||||
}
|
||||
|
||||
|
||||
void SSUServer::OpenSocketV6 ()
|
||||
{
|
||||
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::send_buffer_size (SSU_SOCKET_SEND_BUFFER_SIZE));
|
||||
m_SocketV6.bind (m_EndpointV6);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSUServer::Start ()
|
||||
{
|
||||
m_IsRunning = true;
|
||||
@ -68,16 +68,16 @@ namespace transport
|
||||
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
|
||||
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
|
||||
m_ReceiversService.post (std::bind (&SSUServer::Receive, this));
|
||||
ScheduleTermination ();
|
||||
ScheduleTermination ();
|
||||
}
|
||||
if (context.SupportsV6 ())
|
||||
{
|
||||
{
|
||||
m_ReceiversThreadV6 = new std::thread (std::bind (&SSUServer::RunReceiversV6, this));
|
||||
m_ThreadV6 = new std::thread (std::bind (&SSUServer::RunV6, this));
|
||||
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
|
||||
ScheduleTerminationV6 ();
|
||||
m_ReceiversServiceV6.post (std::bind (&SSUServer::ReceiveV6, this));
|
||||
ScheduleTerminationV6 ();
|
||||
}
|
||||
SchedulePeerTestsCleanupTimer ();
|
||||
SchedulePeerTestsCleanupTimer ();
|
||||
ScheduleIntroducersUpdateTimer (); // wait for 30 seconds and decide if we need introducers
|
||||
}
|
||||
|
||||
@ -94,135 +94,135 @@ namespace transport
|
||||
m_ReceiversService.stop ();
|
||||
m_ReceiversServiceV6.stop ();
|
||||
if (m_ReceiversThread)
|
||||
{
|
||||
m_ReceiversThread->join ();
|
||||
{
|
||||
m_ReceiversThread->join ();
|
||||
delete m_ReceiversThread;
|
||||
m_ReceiversThread = nullptr;
|
||||
}
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
if (m_ReceiversThreadV6)
|
||||
{
|
||||
m_ReceiversThreadV6->join ();
|
||||
{
|
||||
m_ReceiversThreadV6->join ();
|
||||
delete m_ReceiversThreadV6;
|
||||
m_ReceiversThreadV6 = nullptr;
|
||||
}
|
||||
if (m_ThreadV6)
|
||||
{
|
||||
m_ThreadV6->join ();
|
||||
{
|
||||
m_ThreadV6->join ();
|
||||
delete m_ThreadV6;
|
||||
m_ThreadV6 = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::Run ()
|
||||
{
|
||||
void SSUServer::Run ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
m_Service.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: server runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::RunV6 ()
|
||||
{
|
||||
void SSUServer::RunV6 ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
m_ServiceV6.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: v6 server runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::RunReceivers ()
|
||||
{
|
||||
void SSUServer::RunReceivers ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
m_ReceiversService.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: receivers runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::RunReceiversV6 ()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::RunReceiversV6 ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
m_ReceiversServiceV6.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: v6 receivers runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay)
|
||||
{
|
||||
m_Relays[tag] = relay;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::RemoveRelay (uint32_t tag)
|
||||
{
|
||||
m_Relays.erase (tag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<SSUSession> SSUServer::FindRelaySession (uint32_t tag)
|
||||
{
|
||||
auto it = m_Relays.find (tag);
|
||||
if (it != m_Relays.end ())
|
||||
{
|
||||
{
|
||||
if (it->second->GetState () == eSessionStateEstablished)
|
||||
return it->second;
|
||||
else
|
||||
m_Relays.erase (it);
|
||||
}
|
||||
m_Relays.erase (it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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);
|
||||
else
|
||||
m_SocketV6.send_to (boost::asio::buffer (buf, len), to);
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::Receive ()
|
||||
{
|
||||
SSUPacket * packet = new SSUPacket ();
|
||||
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 ()
|
||||
{
|
||||
SSUPacket * packet = new SSUPacket ();
|
||||
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)
|
||||
{
|
||||
@ -235,13 +235,13 @@ namespace transport
|
||||
boost::system::error_code ec;
|
||||
size_t moreBytes = m_Socket.available(ec);
|
||||
if (!ec)
|
||||
{
|
||||
{
|
||||
while (moreBytes && packets.size () < 25)
|
||||
{
|
||||
packet = new SSUPacket ();
|
||||
packet->len = m_Socket.receive_from (boost::asio::buffer (packet->buf, SSU_MTU_V4), packet->from, 0, ec);
|
||||
if (!ec)
|
||||
{
|
||||
{
|
||||
packets.push_back (packet);
|
||||
moreBytes = m_Socket.available(ec);
|
||||
if (ec) break;
|
||||
@ -251,15 +251,15 @@ namespace transport
|
||||
LogPrint (eLogError, "SSU: receive_from error: ", ec.message ());
|
||||
delete packet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Service.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_Sessions));
|
||||
Receive ();
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
delete packet;
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
@ -268,7 +268,7 @@ namespace transport
|
||||
OpenSocket ();
|
||||
Receive ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 ());
|
||||
delete packet;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_ServiceV6.post (std::bind (&SSUServer::HandleReceivedPackets, this, packets, &m_SessionsV6));
|
||||
ReceiveV6 ();
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
delete packet;
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
@ -315,17 +315,17 @@ namespace transport
|
||||
OpenSocketV6 ();
|
||||
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::shared_ptr<SSUSession> session;
|
||||
std::shared_ptr<SSUSession> session;
|
||||
for (auto& packet: packets)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous
|
||||
{
|
||||
if (session) session->FlushData ();
|
||||
@ -341,13 +341,13 @@ namespace transport
|
||||
}
|
||||
}
|
||||
session->ProcessNextMessage (packet->buf, packet->len, packet->from);
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: HandleReceivedPackets ", ex.what ());
|
||||
if (session) session->FlushData ();
|
||||
session = nullptr;
|
||||
}
|
||||
}
|
||||
delete packet;
|
||||
}
|
||||
if (session) session->FlushData ();
|
||||
@ -362,21 +362,21 @@ namespace transport
|
||||
if (session || !context.SupportsV6 ())
|
||||
return session;
|
||||
// try v6
|
||||
address = router->GetSSUV6Address ();
|
||||
address = router->GetSSUV6Address ();
|
||||
if (!address) return nullptr;
|
||||
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
|
||||
{
|
||||
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);
|
||||
if (it != sessions.end ())
|
||||
return it->second;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void SSUServer::CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest, bool v4only)
|
||||
{
|
||||
auto address = router->GetSSUAddress (v4only || !context.SupportsV6 ());
|
||||
@ -385,7 +385,7 @@ namespace transport
|
||||
else
|
||||
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,
|
||||
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)
|
||||
{
|
||||
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);
|
||||
if (it != sessions.end ())
|
||||
{
|
||||
{
|
||||
auto session = it->second;
|
||||
if (peerTest && session->GetState () == eSessionStateEstablished)
|
||||
session->SendPeerTest ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise create new session
|
||||
// otherwise create new session
|
||||
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
||||
sessions[remoteEndpoint] = session;
|
||||
// connect
|
||||
// connect
|
||||
LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
|
||||
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());
|
||||
session->Connect ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SSUServer::CreateSessionThroughIntroducer (std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest)
|
||||
{
|
||||
if (router && router->UsesIntroducer ())
|
||||
@ -435,13 +435,13 @@ namespace transport
|
||||
auto it = m_Sessions.find (remoteEndpoint);
|
||||
// check if session is presented already
|
||||
if (it != m_Sessions.end ())
|
||||
{
|
||||
{
|
||||
auto session = it->second;
|
||||
if (peerTest && session->GetState () == eSessionStateEstablished)
|
||||
session->SendPeerTest ();
|
||||
return;
|
||||
}
|
||||
// create new session
|
||||
return;
|
||||
}
|
||||
// create new session
|
||||
int numIntroducers = address->ssu->introducers.size ();
|
||||
if (numIntroducers > 0)
|
||||
{
|
||||
@ -455,52 +455,52 @@ namespace transport
|
||||
if (intr->iExp > 0 && ts > intr->iExp) continue; // skip expired introducer
|
||||
boost::asio::ip::udp::endpoint ep (intr->iHost, intr->iPort);
|
||||
if (ep.address ().is_v4 ()) // ipv4 only
|
||||
{
|
||||
{
|
||||
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 ())
|
||||
{
|
||||
introducerSession = it->second;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!introducer)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no ipv4 non-expired introducers presented");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (introducerSession) // session found
|
||||
if (introducerSession) // session found
|
||||
LogPrint (eLogWarning, "SSU: Session to introducer already exists");
|
||||
else // create new
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: Creating new session to introducer ", introducer->iHost);
|
||||
boost::asio::ip::udp::endpoint introducerEndpoint (introducer->iHost, introducer->iPort);
|
||||
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)
|
||||
#endif
|
||||
{
|
||||
// create session
|
||||
// create session
|
||||
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
|
||||
m_Sessions[remoteEndpoint] = session;
|
||||
|
||||
// introduce
|
||||
LogPrint (eLogInfo, "SSU: Introduce new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()),
|
||||
"] through introducer ", introducer->iHost, ":", introducer->iPort);
|
||||
session->WaitForIntroduction ();
|
||||
session->WaitForIntroduction ();
|
||||
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
|
||||
{
|
||||
uint8_t buf[1];
|
||||
Send (buf, 0, remoteEndpoint); // send HolePunch
|
||||
}
|
||||
}
|
||||
}
|
||||
introducerSession->Introduce (*introducer, router);
|
||||
}
|
||||
else
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Can't connect to unreachable router and no introducers present");
|
||||
}
|
||||
else
|
||||
@ -518,8 +518,8 @@ namespace transport
|
||||
m_SessionsV6.erase (ep);
|
||||
else
|
||||
m_Sessions.erase (ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::DeleteAllSessions ()
|
||||
{
|
||||
@ -543,15 +543,15 @@ namespace transport
|
||||
auto ind = rand () % filteredSessions.size ();
|
||||
return filteredSessions[ind];
|
||||
}
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV4Session (std::shared_ptr<const SSUSession> excluded) // v4 only
|
||||
{
|
||||
return GetRandomV4Session (
|
||||
[excluded](std::shared_ptr<SSUSession> session)->bool
|
||||
{
|
||||
return session->GetState () == eSessionStateEstablished && session != excluded;
|
||||
[excluded](std::shared_ptr<SSUSession> session)->bool
|
||||
{
|
||||
return session->GetState () == eSessionStateEstablished && session != excluded;
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -567,15 +567,15 @@ namespace transport
|
||||
auto ind = rand () % filteredSessions.size ();
|
||||
return filteredSessions[ind];
|
||||
}
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<SSUSession> SSUServer::GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded) // v6 only
|
||||
{
|
||||
return GetRandomV6Session (
|
||||
[excluded](std::shared_ptr<SSUSession> session)->bool
|
||||
{
|
||||
return session->GetState () == eSessionStateEstablished && session != excluded;
|
||||
[excluded](std::shared_ptr<SSUSession> session)->bool
|
||||
{
|
||||
return session->GetState () == eSessionStateEstablished && session != excluded;
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -587,18 +587,18 @@ namespace transport
|
||||
for (int i = 0; i < maxNumIntroducers; i++)
|
||||
{
|
||||
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 ()) &&
|
||||
session->GetState () == eSessionStateEstablished &&
|
||||
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
|
||||
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
|
||||
}
|
||||
);
|
||||
);
|
||||
if (session)
|
||||
{
|
||||
ret.insert (session.get ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -607,7 +607,7 @@ namespace transport
|
||||
{
|
||||
m_IntroducersUpdateTimer.expires_from_now (boost::posix_time::seconds(SSU_KEEP_ALIVE_INTERVAL));
|
||||
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)
|
||||
@ -620,7 +620,7 @@ namespace transport
|
||||
// we still don't know if we need introducers
|
||||
ScheduleIntroducersUpdateTimer ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (i2p::context.GetStatus () == eRouterStatusOK) return; // we don't need introducers anymore
|
||||
// we are firewalled
|
||||
if (!i2p::context.IsUnreachable ()) i2p::context.SetUnreachable ();
|
||||
@ -628,7 +628,7 @@ namespace transport
|
||||
size_t numIntroducers = 0;
|
||||
uint32_t ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (const auto& it : m_Introducers)
|
||||
{
|
||||
{
|
||||
auto session = FindSession (it);
|
||||
if (session && ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION)
|
||||
{
|
||||
@ -636,7 +636,7 @@ namespace transport
|
||||
newList.push_back (it);
|
||||
numIntroducers++;
|
||||
}
|
||||
else
|
||||
else
|
||||
i2p::context.RemoveIntroducer (it);
|
||||
}
|
||||
|
||||
@ -658,16 +658,16 @@ namespace transport
|
||||
if (newList.size () >= SSU_MAX_NUM_INTRODUCERS) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Introducers = newList;
|
||||
if (m_Introducers.size () < SSU_MAX_NUM_INTRODUCERS)
|
||||
{
|
||||
auto introducer = i2p::data::netdb.GetRandomIntroducer ();
|
||||
if (introducer)
|
||||
CreateSession (introducer);
|
||||
}
|
||||
}
|
||||
ScheduleIntroducersUpdateTimer ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::NewPeerTest (uint32_t nonce, PeerTestParticipant role, std::shared_ptr<SSUSession> session)
|
||||
@ -682,7 +682,7 @@ namespace transport
|
||||
return it->second.role;
|
||||
else
|
||||
return ePeerTestParticipantUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<SSUSession> SSUServer::GetPeerTestSession (uint32_t nonce)
|
||||
{
|
||||
@ -698,26 +698,26 @@ namespace transport
|
||||
auto it = m_PeerTests.find (nonce);
|
||||
if (it != m_PeerTests.end ())
|
||||
it->second.role = role;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSUServer::RemovePeerTest (uint32_t nonce)
|
||||
{
|
||||
m_PeerTests.erase (nonce);
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::SchedulePeerTestsCleanupTimer ()
|
||||
{
|
||||
m_PeerTestsCleanupTimer.expires_from_now (boost::posix_time::seconds(SSU_PEER_TEST_TIMEOUT));
|
||||
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)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
int numDeleted = 0;
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
int numDeleted = 0;
|
||||
uint64_t ts = i2p::util::GetMillisecondsSinceEpoch ();
|
||||
for (auto it = m_PeerTests.begin (); it != m_PeerTests.end ();)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto& it: m_Sessions)
|
||||
if (it.second->IsTerminationTimeoutExpired (ts))
|
||||
{
|
||||
auto session = it.second;
|
||||
m_Service.post ([session]
|
||||
{
|
||||
m_Service.post ([session]
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||
session->Failed ();
|
||||
});
|
||||
});
|
||||
}
|
||||
ScheduleTermination ();
|
||||
}
|
||||
}
|
||||
ScheduleTermination ();
|
||||
}
|
||||
}
|
||||
|
||||
void SSUServer::ScheduleTerminationV6 ()
|
||||
{
|
||||
@ -770,21 +770,21 @@ namespace transport
|
||||
void SSUServer::HandleTerminationTimerV6 (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
{
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
for (auto& it: m_SessionsV6)
|
||||
if (it.second->IsTerminationTimeoutExpired (ts))
|
||||
{
|
||||
auto session = it.second;
|
||||
m_ServiceV6.post ([session]
|
||||
{
|
||||
m_ServiceV6.post ([session]
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: no activity with ", session->GetRemoteEndpoint (), " for ", session->GetTerminationTimeout (), " seconds");
|
||||
session->Failed ();
|
||||
});
|
||||
});
|
||||
}
|
||||
ScheduleTerminationV6 ();
|
||||
}
|
||||
}
|
||||
ScheduleTerminationV6 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,8 +20,8 @@ namespace i2p
|
||||
{
|
||||
namespace transport
|
||||
{
|
||||
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
|
||||
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
|
||||
const int SSU_KEEP_ALIVE_INTERVAL = 30; // 30 seconds
|
||||
const int SSU_PEER_TEST_TIMEOUT = 60; // 60 seconds
|
||||
const int SSU_TO_INTRODUCER_SESSION_DURATION = 3600; // 1 hour
|
||||
const int SSU_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
|
||||
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
|
||||
boost::asio::ip::udp::endpoint from;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class SSUServer
|
||||
{
|
||||
public:
|
||||
@ -45,7 +45,7 @@ namespace transport
|
||||
void Start ();
|
||||
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,
|
||||
void CreateSession (std::shared_ptr<const i2p::data::RouterInfo> router,
|
||||
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);
|
||||
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> GetRandomEstablishedV6Session (std::shared_ptr<const SSUSession> excluded);
|
||||
void DeleteSession (std::shared_ptr<SSUSession> session);
|
||||
void DeleteAllSessions ();
|
||||
void DeleteAllSessions ();
|
||||
|
||||
boost::asio::io_service& GetService () { return m_Service; };
|
||||
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 AddRelay (uint32_t tag, std::shared_ptr<SSUSession> relay);
|
||||
void RemoveRelay (uint32_t tag);
|
||||
@ -68,7 +68,7 @@ namespace transport
|
||||
std::shared_ptr<SSUSession> GetPeerTestSession (uint32_t nonce);
|
||||
void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role);
|
||||
void RemovePeerTest (uint32_t nonce);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void OpenSocket ();
|
||||
@ -84,13 +84,13 @@ namespace transport
|
||||
void HandleReceivedPackets (std::vector<SSUPacket *> packets,
|
||||
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>
|
||||
std::shared_ptr<SSUSession> GetRandomV4Session (Filter 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 HandleIntroducersUpdateTimer (const boost::system::error_code& ecode);
|
||||
|
||||
@ -111,10 +111,10 @@ namespace transport
|
||||
PeerTestParticipant role;
|
||||
std::shared_ptr<SSUSession> session; // for Bob to Alice
|
||||
};
|
||||
|
||||
bool m_OnlyV6;
|
||||
|
||||
bool m_OnlyV6;
|
||||
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::work m_Work, m_WorkV6, m_ReceiversWork, m_ReceiversWorkV6;
|
||||
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<uint32_t, std::shared_ptr<SSUSession> > m_Relays; // we are introducer
|
||||
std::map<uint32_t, PeerTest> m_PeerTests; // nonce -> creation time in milliseconds
|
||||
|
||||
|
||||
public:
|
||||
// for HTTP only
|
||||
const decltype(m_Sessions)& GetSessions () const { return m_Sessions; };
|
||||
|
@ -28,9 +28,9 @@ namespace transport
|
||||
}
|
||||
|
||||
SSUData::SSUData (SSUSession& session):
|
||||
m_Session (session), m_ResendTimer (session.GetService ()),
|
||||
m_IncompleteMessagesCleanupTimer (session.GetService ()),
|
||||
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
|
||||
m_Session (session), m_ResendTimer (session.GetService ()),
|
||||
m_IncompleteMessagesCleanupTimer (session.GetService ()),
|
||||
m_MaxPacketSize (session.IsV6 () ? SSU_V6_MAX_PACKET_SIZE : SSU_V4_MAX_PACKET_SIZE),
|
||||
m_PacketSize (m_MaxPacketSize), m_LastMessageReceivedTime (0)
|
||||
{
|
||||
}
|
||||
@ -42,8 +42,8 @@ namespace transport
|
||||
void SSUData::Start ()
|
||||
{
|
||||
ScheduleIncompleteMessagesCleanup ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSUData::Stop ()
|
||||
{
|
||||
m_ResendTimer.cancel ();
|
||||
@ -51,8 +51,8 @@ namespace transport
|
||||
m_IncompleteMessages.clear ();
|
||||
m_SentMessages.clear ();
|
||||
m_ReceivedMessages.clear ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSUData::AdjustPacketSize (std::shared_ptr<const i2p::data::RouterInfo> remoteRouter)
|
||||
{
|
||||
if (!remoteRouter) return;
|
||||
@ -72,11 +72,11 @@ namespace transport
|
||||
LogPrint (eLogDebug, "SSU: MTU=", ssuAddress->ssu->mtu, " packet size=", m_PacketSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Unexpected MTU ", ssuAddress->ssu->mtu);
|
||||
m_PacketSize = m_MaxPacketSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::UpdatePacketSize (const i2p::data::IdentHash& remoteIdent)
|
||||
@ -91,11 +91,11 @@ namespace transport
|
||||
auto it = m_SentMessages.find (msgID);
|
||||
if (it != m_SentMessages.end ())
|
||||
{
|
||||
m_SentMessages.erase (it);
|
||||
m_SentMessages.erase (it);
|
||||
if (m_SentMessages.empty ())
|
||||
m_ResendTimer.cancel ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::ProcessAcks (uint8_t *& buf, uint8_t flag)
|
||||
{
|
||||
@ -117,7 +117,7 @@ namespace transport
|
||||
{
|
||||
uint32_t msgID = bufbe32toh (buf);
|
||||
buf += 4; // msgID
|
||||
auto it = m_SentMessages.find (msgID);
|
||||
auto it = m_SentMessages.find (msgID);
|
||||
// process individual Ack bitfields
|
||||
bool isNonLast = false;
|
||||
int fragment = 0;
|
||||
@ -127,26 +127,26 @@ namespace transport
|
||||
isNonLast = bitfield & 0x80;
|
||||
bitfield &= 0x7F; // clear MSB
|
||||
if (bitfield && it != m_SentMessages.end ())
|
||||
{
|
||||
int numSentFragments = it->second->fragments.size ();
|
||||
{
|
||||
int numSentFragments = it->second->fragments.size ();
|
||||
// process bits
|
||||
uint8_t mask = 0x01;
|
||||
for (int j = 0; j < 7; j++)
|
||||
{
|
||||
{
|
||||
if (bitfield & mask)
|
||||
{
|
||||
if (fragment < numSentFragments)
|
||||
it->second->fragments[fragment].reset (nullptr);
|
||||
}
|
||||
}
|
||||
fragment++;
|
||||
mask <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
while (isNonLast);
|
||||
}
|
||||
}
|
||||
while (isNonLast);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::ProcessFragments (uint8_t * buf)
|
||||
@ -154,7 +154,7 @@ namespace transport
|
||||
uint8_t numFragments = *buf; // number of fragments
|
||||
buf++;
|
||||
for (int i = 0; i < numFragments; i++)
|
||||
{
|
||||
{
|
||||
uint32_t msgID = bufbe32toh (buf); // message ID
|
||||
buf += 4;
|
||||
uint8_t frag[4] = {0};
|
||||
@ -162,8 +162,8 @@ namespace transport
|
||||
buf += 3;
|
||||
uint32_t fragmentInfo = bufbe32toh (frag); // fragment info
|
||||
uint16_t fragmentSize = fragmentInfo & 0x3FFF; // bits 0 - 13
|
||||
bool isLast = fragmentInfo & 0x010000; // bit 16
|
||||
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
||||
bool isLast = fragmentInfo & 0x010000; // bit 16
|
||||
uint8_t fragmentNum = fragmentInfo >> 17; // bits 23 - 17
|
||||
if (fragmentSize >= SSU_V4_MAX_PACKET_SIZE)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Fragment size ", fragmentSize, " exceeds max SSU packet size");
|
||||
@ -172,12 +172,12 @@ namespace transport
|
||||
|
||||
// find message with msgID
|
||||
auto it = m_IncompleteMessages.find (msgID);
|
||||
if (it == m_IncompleteMessages.end ())
|
||||
if (it == m_IncompleteMessages.end ())
|
||||
{
|
||||
// create new message
|
||||
auto msg = NewI2NPShortMessage ();
|
||||
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>& incompleteMessage = it->second;
|
||||
@ -204,10 +204,10 @@ namespace transport
|
||||
}
|
||||
if (isLast)
|
||||
LogPrint (eLogDebug, "SSU: Message ", msgID, " complete");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
if (fragmentNum < incompleteMessage->nextFragmentNum)
|
||||
// duplicate fragment
|
||||
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);
|
||||
if (incompleteMessage->savedFragments.insert (std::unique_ptr<Fragment>(savedFragment)).second)
|
||||
incompleteMessage->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
else
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Fragment ", (int)fragmentNum, " of message ", msgID, " already saved");
|
||||
}
|
||||
isLast = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLast)
|
||||
{
|
||||
// delete incomplete message
|
||||
auto msg = incompleteMessage->msg;
|
||||
incompleteMessage->msg = nullptr;
|
||||
m_IncompleteMessages.erase (msgID);
|
||||
m_IncompleteMessages.erase (msgID);
|
||||
// process message
|
||||
SendMsgAck (msgID);
|
||||
msg->FromSSU (msgID);
|
||||
if (m_Session.GetState () == eSessionStateEstablished)
|
||||
{
|
||||
if (!m_ReceivedMessages.count (msgID))
|
||||
{
|
||||
{
|
||||
m_ReceivedMessages.insert (msgID);
|
||||
m_LastMessageReceivedTime = i2p::util::GetSecondsSinceEpoch ();
|
||||
if (!msg->IsExpired ())
|
||||
if (!msg->IsExpired ())
|
||||
{
|
||||
#ifdef WITH_EVENTS
|
||||
QueueIntEvent("transport.recvmsg", m_Session.GetIdentHashBase64(), 1);
|
||||
@ -248,10 +248,10 @@ namespace transport
|
||||
}
|
||||
else
|
||||
LogPrint (eLogDebug, "SSU: message expired");
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogWarning, "SSU: Message ", msgID, " already received");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// we expect DeliveryStatus
|
||||
@ -259,22 +259,22 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: session established");
|
||||
m_Session.Established ();
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU: unexpected message ", (int)msg->GetTypeID ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
SendFragmentAck (msgID, fragmentNum);
|
||||
SendFragmentAck (msgID, fragmentNum);
|
||||
buf += fragmentSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::FlushReceivedMessage ()
|
||||
{
|
||||
m_Handler.Flush ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSUData::ProcessMessage (uint8_t * buf, size_t len)
|
||||
{
|
||||
//uint8_t * start = buf;
|
||||
@ -303,25 +303,25 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: message ", msgID, " already sent");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_SentMessages.empty ()) // schedule resend at first message only
|
||||
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;
|
||||
if (ret.second)
|
||||
if (ret.second)
|
||||
{
|
||||
sentMessage->nextResendTime = i2p::util::GetSecondsSinceEpoch () + RESEND_INTERVAL;
|
||||
sentMessage->numResends = 0;
|
||||
}
|
||||
}
|
||||
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 ();
|
||||
uint8_t * msgBuf = msg->GetSSUHeader ();
|
||||
|
||||
uint32_t fragmentNum = 0;
|
||||
while (len > 0)
|
||||
{
|
||||
{
|
||||
Fragment * fragment = new Fragment;
|
||||
fragment->fragmentNum = fragmentNum;
|
||||
uint8_t * buf = fragment->buf;
|
||||
@ -337,39 +337,39 @@ namespace transport
|
||||
uint32_t fragmentInfo = (fragmentNum << 17);
|
||||
if (isLast)
|
||||
fragmentInfo |= 0x010000;
|
||||
|
||||
|
||||
fragmentInfo |= size;
|
||||
fragmentInfo = htobe32 (fragmentInfo);
|
||||
memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3);
|
||||
payload += 3;
|
||||
memcpy (payload, msgBuf, size);
|
||||
|
||||
|
||||
size += payload - buf;
|
||||
if (size & 0x0F) // make sure 16 bytes boundary
|
||||
size = ((size >> 4) + 1) << 4; // (/16 + 1)*16
|
||||
fragment->len = size;
|
||||
fragment->len = size;
|
||||
fragments.push_back (std::unique_ptr<Fragment> (fragment));
|
||||
|
||||
|
||||
// encrypt message with session key
|
||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size);
|
||||
try
|
||||
{
|
||||
{
|
||||
m_Session.Send (buf, size);
|
||||
}
|
||||
catch (boost::system::system_error& ec)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Can't send data fragment ", ec.what ());
|
||||
}
|
||||
}
|
||||
if (!isLast)
|
||||
{
|
||||
{
|
||||
len -= payloadSize;
|
||||
msgBuf += payloadSize;
|
||||
}
|
||||
}
|
||||
else
|
||||
len = 0;
|
||||
fragmentNum++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::SendMsgAck (uint32_t msgID)
|
||||
{
|
||||
@ -398,27 +398,27 @@ namespace transport
|
||||
uint8_t buf[64 + 18] = {0};
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
*payload = DATA_FLAG_ACK_BITFIELDS_INCLUDED; // flag
|
||||
payload++;
|
||||
payload++;
|
||||
*payload = 1; // number of ACK bitfields
|
||||
payload++;
|
||||
// one ack
|
||||
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||
*(uint32_t *)(payload) = htobe32 (msgID); // msgID
|
||||
payload += 4;
|
||||
div_t d = div (fragmentNum, 7);
|
||||
memset (payload, 0x80, d.quot); // 0x80 means non-last
|
||||
payload += d.quot;
|
||||
payload += d.quot;
|
||||
*payload = 0x01 << d.rem; // set corresponding bit
|
||||
payload++;
|
||||
*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
|
||||
m_Session.FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, len);
|
||||
m_Session.Send (buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::ScheduleResend()
|
||||
{
|
||||
{
|
||||
m_ResendTimer.cancel ();
|
||||
m_ResendTimer.expires_from_now (boost::posix_time::seconds(RESEND_INTERVAL));
|
||||
auto s = m_Session.shared_from_this();
|
||||
@ -435,7 +435,7 @@ namespace transport
|
||||
for (auto it = m_SentMessages.begin (); it != m_SentMessages.end ();)
|
||||
{
|
||||
if (ts >= it->second->nextResendTime)
|
||||
{
|
||||
{
|
||||
if (it->second->numResends < MAX_NUM_RESENDS)
|
||||
{
|
||||
for (auto& f: it->second->fragments)
|
||||
@ -455,13 +455,13 @@ namespace transport
|
||||
it->second->numResends++;
|
||||
it->second->nextResendTime += it->second->numResends*RESEND_INTERVAL;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU: message has not been ACKed after ", MAX_NUM_RESENDS, " attempts, deleted");
|
||||
it = m_SentMessages.erase (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
@ -472,9 +472,9 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogError, "SSU: resend window exceeds max size. Session terminated");
|
||||
m_Session.Close ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUData::ScheduleIncompleteMessagesCleanup ()
|
||||
{
|
||||
@ -484,7 +484,7 @@ namespace transport
|
||||
m_IncompleteMessagesCleanupTimer.async_wait ([s](const boost::system::error_code& ecode)
|
||||
{ s->m_Data.HandleIncompleteMessagesCleanupTimer (ecode); });
|
||||
}
|
||||
|
||||
|
||||
void SSUData::HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
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");
|
||||
it = m_IncompleteMessages.erase (it);
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
// decay
|
||||
if (m_ReceivedMessages.size () > MAX_NUM_RECEIVED_MESSAGES ||
|
||||
i2p::util::GetSecondsSinceEpoch () > m_LastMessageReceivedTime + DECAY_INTERVAL)
|
||||
m_ReceivedMessages.clear ();
|
||||
|
||||
|
||||
ScheduleIncompleteMessagesCleanup ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace transport
|
||||
const size_t SSU_MTU_V6 = 1488;
|
||||
#endif
|
||||
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 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
|
||||
@ -40,7 +40,7 @@ namespace transport
|
||||
const uint8_t DATA_FLAG_REQUEST_PREVIOUS_ACKS = 0x08;
|
||||
const uint8_t DATA_FLAG_EXPLICIT_CONGESTION_NOTIFICATION = 0x10;
|
||||
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
|
||||
{
|
||||
@ -50,27 +50,27 @@ namespace transport
|
||||
uint8_t buf[SSU_V4_MAX_PACKET_SIZE + 18]; // use biggest
|
||||
|
||||
Fragment () = default;
|
||||
Fragment (int n, const uint8_t * b, int l, bool last):
|
||||
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
|
||||
};
|
||||
Fragment (int n, const uint8_t * b, int l, bool last):
|
||||
fragmentNum (n), len (l), isLast (last) { memcpy (buf, b, len); };
|
||||
};
|
||||
|
||||
struct FragmentCmp
|
||||
{
|
||||
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
|
||||
{
|
||||
std::shared_ptr<I2NPMessage> msg;
|
||||
int nextFragmentNum;
|
||||
int nextFragmentNum;
|
||||
uint32_t lastFragmentInsertTime; // in seconds
|
||||
std::set<std::unique_ptr<Fragment>, FragmentCmp> savedFragments;
|
||||
|
||||
|
||||
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
|
||||
@ -78,24 +78,24 @@ namespace transport
|
||||
std::vector<std::unique_ptr<Fragment> > fragments;
|
||||
uint32_t nextResendTime; // in seconds
|
||||
int numResends;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class SSUSession;
|
||||
class SSUData
|
||||
{
|
||||
public:
|
||||
|
||||
SSUData (SSUSession& session);
|
||||
SSUData (SSUSession& session);
|
||||
~SSUData ();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
void Stop ();
|
||||
|
||||
void ProcessMessage (uint8_t * buf, size_t len);
|
||||
void FlushReceivedMessage ();
|
||||
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);
|
||||
|
||||
private:
|
||||
@ -104,16 +104,16 @@ namespace transport
|
||||
void SendFragmentAck (uint32_t msgID, int fragmentNum);
|
||||
void ProcessAcks (uint8_t *& buf, uint8_t flag);
|
||||
void ProcessFragments (uint8_t * buf);
|
||||
void ProcessSentMessageAck (uint32_t msgID);
|
||||
void ProcessSentMessageAck (uint32_t msgID);
|
||||
|
||||
void ScheduleResend ();
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
void ScheduleIncompleteMessagesCleanup ();
|
||||
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
|
||||
|
||||
|
||||
private:
|
||||
void HandleIncompleteMessagesCleanupTimer (const boost::system::error_code& ecode);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
SSUSession& m_Session;
|
||||
std::map<uint32_t, std::unique_ptr<IncompleteMessage> > m_IncompleteMessages;
|
||||
@ -123,7 +123,7 @@ namespace transport
|
||||
int m_MaxPacketSize, m_PacketSize;
|
||||
i2p::I2NPMessagesHandler m_Handler;
|
||||
uint32_t m_LastMessageReceivedTime; // in second
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,12 @@ namespace i2p
|
||||
namespace transport
|
||||
{
|
||||
SSUSession::SSUSession (SSUServer& server, boost::asio::ip::udp::endpoint& remoteEndpoint,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ):
|
||||
TransportSession (router, SSU_TERMINATION_TIMEOUT),
|
||||
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_ConnectTimer (GetService ()),
|
||||
m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false),
|
||||
std::shared_ptr<const i2p::data::RouterInfo> router, bool peerTest ):
|
||||
TransportSession (router, SSU_TERMINATION_TIMEOUT),
|
||||
m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_ConnectTimer (GetService ()),
|
||||
m_IsPeerTest (peerTest),m_State (eSessionStateUnknown), m_IsSessionKey (false),
|
||||
m_RelayTag (0), m_SentRelayTag (0), m_Data (*this), m_IsDataReceived (false)
|
||||
{
|
||||
{
|
||||
if (router)
|
||||
{
|
||||
// we are client
|
||||
@ -36,14 +36,14 @@ namespace transport
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint8_t sharedKey[256];
|
||||
@ -55,14 +55,14 @@ namespace transport
|
||||
sessionKey[0] = 0;
|
||||
memcpy (sessionKey + 1, sharedKey, 31);
|
||||
memcpy (macKey, sharedKey + 31, 32);
|
||||
}
|
||||
}
|
||||
else if (sharedKey[0])
|
||||
{
|
||||
memcpy (sessionKey, sharedKey, 32);
|
||||
memcpy (macKey, sharedKey + 32, 32);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
// find first non-zero byte
|
||||
uint8_t * nonZero = sharedKey + 1;
|
||||
while (!*nonZero)
|
||||
@ -72,16 +72,16 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: first 32 bytes of shared key is all zeros. Ignored");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
memcpy (sessionKey, nonZero, 32);
|
||||
SHA256(nonZero, 64 - (nonZero - sharedKey), macKey);
|
||||
}
|
||||
m_IsSessionKey = true;
|
||||
m_SessionKeyEncryption.SetKey (m_SessionKey);
|
||||
m_SessionKeyDecryption.SetKey (m_SessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||
{
|
||||
@ -96,40 +96,40 @@ namespace transport
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!len) return; // ignore zero-length packets
|
||||
if (!len) return; // ignore zero-length packets
|
||||
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
|
||||
DecryptSessionKey (buf, len);
|
||||
else
|
||||
DecryptSessionKey (buf, len);
|
||||
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
|
||||
if (Validate (buf, len, m_IntroKey))
|
||||
Decrypt (buf, len, m_IntroKey);
|
||||
else
|
||||
{
|
||||
{
|
||||
// try own intro key
|
||||
auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false);
|
||||
if (!address)
|
||||
{
|
||||
LogPrint (eLogInfo, "SSU is not supported");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Validate (buf, len, address->ssu->key))
|
||||
Decrypt (buf, len, address->ssu->key);
|
||||
else
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: MAC verification failed ", len, " bytes from ", senderEndpoint);
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// successfully decrypted
|
||||
ProcessMessage (buf, len, senderEndpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t SSUSession::GetSSUHeaderSize (const uint8_t * buf) const
|
||||
@ -158,14 +158,14 @@ namespace transport
|
||||
ProcessData (buf + headerSize, len - headerSize);
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_REQUEST:
|
||||
ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
|
||||
ProcessSessionRequest (buf, len, senderEndpoint); // buf with header
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_CREATED:
|
||||
ProcessSessionCreated (buf, len); // buf with header
|
||||
break;
|
||||
case PAYLOAD_TYPE_SESSION_CONFIRMED:
|
||||
ProcessSessionConfirmed (buf, len); // buf with header
|
||||
break;
|
||||
break;
|
||||
case PAYLOAD_TYPE_PEER_TEST:
|
||||
LogPrint (eLogDebug, "SSU: peer test received");
|
||||
ProcessPeerTest (buf + headerSize, len - headerSize, senderEndpoint);
|
||||
@ -173,9 +173,9 @@ namespace transport
|
||||
case PAYLOAD_TYPE_SESSION_DESTROYED:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: session destroy received");
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
m_Server.DeleteSession (shared_from_this ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
case PAYLOAD_TYPE_RELAY_RESPONSE:
|
||||
ProcessRelayResponse (buf + headerSize, len - headerSize);
|
||||
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)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU message: session request");
|
||||
bool sendRelayTag = true;
|
||||
bool sendRelayTag = true;
|
||||
auto headerSize = sizeof (SSUHeader);
|
||||
if (((SSUHeader *)buf)->IsExtendedOptions ())
|
||||
{
|
||||
@ -206,14 +206,14 @@ namespace transport
|
||||
if (extendedOptionsLen >= 3) // options are presented
|
||||
{
|
||||
uint16_t flags = bufbe16toh (buf + headerSize);
|
||||
sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
|
||||
sendRelayTag = flags & EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG;
|
||||
}
|
||||
headerSize += extendedOptionsLen;
|
||||
}
|
||||
}
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "Session reaquest header size ", headerSize, " exceeds packet length ", len);
|
||||
return;
|
||||
return;
|
||||
}
|
||||
m_RemoteEndpoint = senderEndpoint;
|
||||
if (!m_DHKeysPair)
|
||||
@ -232,14 +232,14 @@ namespace transport
|
||||
|
||||
LogPrint (eLogDebug, "SSU message: session created");
|
||||
m_ConnectTimer.cancel (); // connect timer
|
||||
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, signed on time
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "Session created header size ", headerSize, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
uint8_t * payload = buf + headerSize;
|
||||
return;
|
||||
}
|
||||
uint8_t * payload = buf + headerSize;
|
||||
uint8_t * y = payload;
|
||||
CreateAESandMacKey (y);
|
||||
s.Insert (m_DHKeysPair->GetPublicKey (), 256); // x
|
||||
@ -250,18 +250,18 @@ namespace transport
|
||||
uint8_t * ourAddress = payload;
|
||||
boost::asio::ip::address ourIP;
|
||||
if (addressSize == 4) // v4
|
||||
{
|
||||
{
|
||||
boost::asio::ip::address_v4::bytes_type bytes;
|
||||
memcpy (bytes.data (), ourAddress, 4);
|
||||
ourIP = boost::asio::ip::address_v4 (bytes);
|
||||
}
|
||||
}
|
||||
else // v6
|
||||
{
|
||||
boost::asio::ip::address_v6::bytes_type bytes;
|
||||
memcpy (bytes.data (), ourAddress, 16);
|
||||
ourIP = boost::asio::ip::address_v6 (bytes);
|
||||
}
|
||||
s.Insert (ourAddress, addressSize); // our IP
|
||||
}
|
||||
s.Insert (ourAddress, addressSize); // our IP
|
||||
payload += addressSize; // address
|
||||
uint16_t ourPort = bufbe16toh (payload);
|
||||
s.Insert (payload, 2); // our port
|
||||
@ -271,19 +271,19 @@ namespace transport
|
||||
else
|
||||
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 (payload, 8); // relayTag and signed on time
|
||||
s.Insert (payload, 8); // relayTag and signed on time
|
||||
m_RelayTag = bufbe32toh (payload);
|
||||
payload += 4; // relayTag
|
||||
if (i2p::context.GetStatus () == eRouterStatusTesting)
|
||||
{
|
||||
{
|
||||
auto ts = i2p::util::GetSecondsSinceEpoch ();
|
||||
uint32_t signedOnTime = bufbe32toh(payload);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
payload += 4; // signed on time
|
||||
// decrypt signature
|
||||
size_t signatureLen = m_RemoteIdentity->GetSignatureLen ();
|
||||
@ -304,34 +304,34 @@ namespace transport
|
||||
LogPrint (eLogError, "SSU: message 'created' signature verification failed");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::ProcessSessionConfirmed (const uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: Session confirmed received");
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
LogPrint (eLogDebug, "SSU: Session confirmed received");
|
||||
auto headerSize = GetSSUHeaderSize (buf);
|
||||
if (headerSize >= len)
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Session confirmed header size ", len, " exceeds packet length ", len);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
const uint8_t * payload = buf + headerSize;
|
||||
payload++; // identity fragment info
|
||||
uint16_t identitySize = bufbe16toh (payload);
|
||||
uint16_t identitySize = bufbe16toh (payload);
|
||||
payload += 2; // size of identity fragment
|
||||
auto identity = std::make_shared<i2p::data::IdentityEx> (payload, identitySize);
|
||||
auto existing = i2p::data::netdb.FindRouter (identity->GetIdentHash ()); // check if exists already
|
||||
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : identity);
|
||||
m_Data.UpdatePacketSize (m_RemoteIdentity->GetIdentHash ());
|
||||
payload += identitySize; // identity
|
||||
payload += identitySize; // identity
|
||||
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)
|
||||
{
|
||||
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 ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_SignedData)
|
||||
m_SignedData->Insert (payload, 4); // insert Alice's signed on time
|
||||
payload += 4; // signed-on time
|
||||
@ -345,7 +345,7 @@ namespace transport
|
||||
m_Data.Send (CreateDeliveryStatusMsg (0));
|
||||
Established ();
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "SSU message 'confirmed' signature verification failed");
|
||||
Failed ();
|
||||
@ -353,33 +353,33 @@ namespace transport
|
||||
}
|
||||
|
||||
void SSUSession::SendSessionRequest ()
|
||||
{
|
||||
{
|
||||
uint8_t buf[320 + 18] = {0}; // 304 bytes for ipv4, 320 for ipv6
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
uint8_t flag = 0;
|
||||
// fill extended options, 3 bytes extended options don't change message size
|
||||
if (i2p::context.GetStatus () == eRouterStatusOK) // we don't need relays
|
||||
{
|
||||
{
|
||||
// tell out peer to now assign relay tag
|
||||
flag = SSU_HEADER_EXTENDED_OPTIONS_INCLUDED;
|
||||
*payload = 2; payload++; // 1 byte length
|
||||
uint16_t flags = 0; // clear EXTENDED_OPTIONS_FLAG_REQUEST_RELAY_TAG
|
||||
htobe16buf (payload, flags);
|
||||
htobe16buf (payload, flags);
|
||||
payload += 2;
|
||||
}
|
||||
}
|
||||
// fill payload
|
||||
memcpy (payload, m_DHKeysPair->GetPublicKey (), 256); // x
|
||||
bool isV4 = m_RemoteEndpoint.address ().is_v4 ();
|
||||
if (isV4)
|
||||
{
|
||||
payload[256] = 4;
|
||||
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
|
||||
payload[256] = 4;
|
||||
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data(), 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload[256] = 16;
|
||||
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
|
||||
}
|
||||
payload[256] = 16;
|
||||
memcpy (payload + 257, m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data(), 16);
|
||||
}
|
||||
// encrypt and send
|
||||
uint8_t iv[16];
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
@ -395,7 +395,7 @@ namespace transport
|
||||
LogPrint (eLogInfo, "SSU is not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint8_t buf[96 + 18] = {0};
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
htobe32buf (payload, introducer.iTag);
|
||||
@ -405,17 +405,17 @@ namespace transport
|
||||
htobuf16(payload, 0); // port = 0
|
||||
payload += 2;
|
||||
*payload = 0; // challenge
|
||||
payload++;
|
||||
payload++;
|
||||
memcpy (payload, (const uint8_t *)address->ssu->key, 32);
|
||||
payload += 32;
|
||||
htobe32buf (payload, nonce); // nonce
|
||||
htobe32buf (payload, nonce); // nonce
|
||||
|
||||
uint8_t iv[16];
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
if (m_State == eSessionStateEstablished)
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, m_SessionKey, iv, m_MacKey);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -428,7 +428,7 @@ namespace transport
|
||||
LogPrint (eLogInfo, "SSU is not supported");
|
||||
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
|
||||
|
||||
uint8_t buf[384 + 18] = {0};
|
||||
@ -441,7 +441,7 @@ namespace transport
|
||||
// ipv4
|
||||
*payload = 4;
|
||||
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
|
||||
payload += 4;
|
||||
}
|
||||
@ -450,7 +450,7 @@ namespace transport
|
||||
// ipv6
|
||||
*payload = 16;
|
||||
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
|
||||
payload += 16;
|
||||
}
|
||||
@ -467,20 +467,20 @@ namespace transport
|
||||
RAND_bytes((uint8_t *)&m_SentRelayTag, 4);
|
||||
if (!m_SentRelayTag) m_SentRelayTag = 1;
|
||||
}
|
||||
htobe32buf (payload, m_SentRelayTag);
|
||||
payload += 4; // relay tag
|
||||
htobe32buf (payload, m_SentRelayTag);
|
||||
payload += 4; // relay tag
|
||||
htobe32buf (payload, i2p::util::GetSecondsSinceEpoch ()); // signed on time
|
||||
payload += 4;
|
||||
s.Insert (payload - 8, 4); // relayTag
|
||||
s.Insert (payload - 8, 4); // relayTag
|
||||
// we have to store this signed data for session confirmed
|
||||
// same data but signed on time, it will Alice's there
|
||||
m_SignedData = std::unique_ptr<SignedData>(new SignedData (s));
|
||||
s.Insert (payload - 4, 4); // BOB's signed on time
|
||||
// same data but signed on time, it will Alice's there
|
||||
m_SignedData = std::unique_ptr<SignedData>(new SignedData (s));
|
||||
s.Insert (payload - 4, 4); // BOB's signed on time
|
||||
s.Sign (i2p::context.GetPrivateKeys (), payload); // DSA signature
|
||||
|
||||
uint8_t iv[16];
|
||||
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 paddingSize = signatureLen & 0x0F; // %16
|
||||
if (paddingSize > 0)
|
||||
@ -493,9 +493,9 @@ namespace transport
|
||||
m_SessionKeyEncryption.Encrypt (payload, signatureLen, payload);
|
||||
payload += signatureLen;
|
||||
size_t msgLen = payload - buf;
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@ -518,21 +518,21 @@ namespace transport
|
||||
if (paddingSize > 0) paddingSize = 16 - paddingSize;
|
||||
RAND_bytes(payload, paddingSize); // fill padding with random
|
||||
payload += paddingSize; // padding size
|
||||
// signature
|
||||
SignedData s; // x,y, our IP, our port, remote IP, remote port, relayTag, our signed on time
|
||||
// signature
|
||||
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 (y, 256); // y
|
||||
s.Insert (ourAddress, ourAddressLen); // our address/port as seem by party
|
||||
if (m_RemoteEndpoint.address ().is_v4 ())
|
||||
s.Insert (m_RemoteEndpoint.address ().to_v4 ().to_bytes ().data (), 4); // remote IP V4
|
||||
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 (htobe32 (m_RelayTag)); // relay tag
|
||||
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;
|
||||
|
||||
|
||||
size_t msgLen = payload - buf;
|
||||
uint8_t iv[16];
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
@ -547,7 +547,7 @@ namespace transport
|
||||
auto session = m_Server.FindRelaySession (relayTag);
|
||||
if (session)
|
||||
{
|
||||
buf += 4; // relay tag
|
||||
buf += 4; // relay tag
|
||||
uint8_t size = *buf;
|
||||
buf++; // size
|
||||
buf += size; // address
|
||||
@ -560,7 +560,7 @@ namespace transport
|
||||
uint32_t nonce = bufbe32toh (buf);
|
||||
SendRelayResponse (nonce, from, introKey, session->m_RemoteEndpoint);
|
||||
SendRelayIntro (session, from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::SendRelayResponse (uint32_t nonce, const boost::asio::ip::udp::endpoint& from,
|
||||
@ -577,7 +577,7 @@ namespace transport
|
||||
*payload = 4;
|
||||
payload++; // size
|
||||
htobe32buf (payload, to.address ().to_v4 ().to_ulong ()); // Charlie's IP
|
||||
payload += 4; // address
|
||||
payload += 4; // address
|
||||
htobe16buf (payload, to.port ()); // Charlie's port
|
||||
payload += 2; // port
|
||||
// Alice
|
||||
@ -587,25 +587,25 @@ namespace transport
|
||||
*payload = 4;
|
||||
payload++; // size
|
||||
memcpy (payload, from.address ().to_v4 ().to_bytes ().data (), 4); // Alice's IP V4
|
||||
payload += 4; // address
|
||||
payload += 4; // address
|
||||
}
|
||||
else
|
||||
{
|
||||
*payload = 16;
|
||||
payload++; // size
|
||||
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
|
||||
payload += 2; // port
|
||||
htobe32buf (payload, nonce);
|
||||
htobe32buf (payload, nonce);
|
||||
|
||||
if (m_State == eSessionStateEstablished)
|
||||
{
|
||||
{
|
||||
// encrypt with session key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80);
|
||||
Send (buf, isV4 ? 64 : 80);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ecrypt with Alice's intro key
|
||||
@ -613,45 +613,45 @@ namespace transport
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_RESPONSE, buf, isV4 ? 64 : 80, introKey, iv, introKey);
|
||||
m_Server.Send (buf, isV4 ? 64 : 80, from);
|
||||
}
|
||||
}
|
||||
LogPrint (eLogDebug, "SSU: relay response sent");
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if (!from.address ().is_v4 ())
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: Alice's IP must be v4");
|
||||
return;
|
||||
}
|
||||
}
|
||||
uint8_t buf[48 + 18] = {0};
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
*payload = 4;
|
||||
payload++; // size
|
||||
htobe32buf (payload, from.address ().to_v4 ().to_ulong ()); // Alice's IP
|
||||
payload += 4; // address
|
||||
payload += 4; // address
|
||||
htobe16buf (payload, from.port ()); // Alice's port
|
||||
payload += 2; // port
|
||||
*payload = 0; // challenge size
|
||||
*payload = 0; // challenge size
|
||||
uint8_t iv[16];
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_INTRO, buf, 48, session->m_SessionKey, iv, session->m_MacKey);
|
||||
m_Server.Send (buf, 48, session->m_RemoteEndpoint);
|
||||
LogPrint (eLogDebug, "SSU: relay intro sent");
|
||||
}
|
||||
|
||||
|
||||
void SSUSession::ProcessRelayResponse (const uint8_t * buf, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU message: Relay response received");
|
||||
uint8_t remoteSize = *buf;
|
||||
LogPrint (eLogDebug, "SSU message: Relay response received");
|
||||
uint8_t remoteSize = *buf;
|
||||
buf++; // remote size
|
||||
boost::asio::ip::address_v4 remoteIP (bufbe32toh (buf));
|
||||
buf += remoteSize; // remote address
|
||||
uint16_t remotePort = bufbe16toh (buf);
|
||||
buf += 2; // remote port
|
||||
uint8_t ourSize = *buf;
|
||||
uint8_t ourSize = *buf;
|
||||
buf++; // our size
|
||||
boost::asio::ip::address ourIP;
|
||||
if (ourSize == 4)
|
||||
@ -675,7 +675,7 @@ namespace transport
|
||||
buf += 4; // nonce
|
||||
auto it = m_RelayRequests.find (nonce);
|
||||
if (it != m_RelayRequests.end ())
|
||||
{
|
||||
{
|
||||
// check if we are waiting for introduction
|
||||
boost::asio::ip::udp::endpoint remoteEndpoint (remoteIP, remotePort);
|
||||
if (!m_Server.FindSession (remoteEndpoint))
|
||||
@ -686,10 +686,10 @@ namespace transport
|
||||
if (i2p::context.GetRouterInfo ().UsesIntroducer ()) // if we are unreachable
|
||||
m_Server.Send (buf, 0, remoteEndpoint); // send HolePunch
|
||||
m_Server.CreateDirectSession (it->second, remoteEndpoint, false);
|
||||
}
|
||||
}
|
||||
// delete request
|
||||
m_RelayRequests.erase (it);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "SSU: Unsolicited RelayResponse, nonce=", nonce);
|
||||
}
|
||||
@ -708,11 +708,11 @@ namespace transport
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
@ -753,18 +753,18 @@ namespace transport
|
||||
memcpy (buf + len, header->iv, 16);
|
||||
htobe16buf (buf + len + 16, encryptedLen);
|
||||
i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, m_MacKey, header->mac);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SSUSession::Decrypt (uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey)
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
i2p::crypto::CBCDecryption decryption;
|
||||
decryption.SetKey (aesKey);
|
||||
decryption.SetIV (header->iv);
|
||||
@ -777,24 +777,24 @@ namespace transport
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
if (encryptedLen > 0)
|
||||
{
|
||||
{
|
||||
m_SessionKeyDecryption.SetIV (header->iv);
|
||||
m_SessionKeyDecryption.Decrypt (encrypted, encryptedLen, encrypted);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool SSUSession::Validate (uint8_t * buf, size_t len, const i2p::crypto::MACKey& macKey)
|
||||
{
|
||||
if (len < sizeof (SSUHeader))
|
||||
{
|
||||
LogPrint (eLogError, "SSU: Unexpected packet length ", len);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SSUHeader * header = (SSUHeader *)buf;
|
||||
uint8_t * encrypted = &header->flag;
|
||||
uint16_t encryptedLen = len - (encrypted - buf);
|
||||
@ -809,12 +809,12 @@ namespace transport
|
||||
void SSUSession::Connect ()
|
||||
{
|
||||
if (m_State == eSessionStateUnknown)
|
||||
{
|
||||
{
|
||||
// set connect timer
|
||||
ScheduleConnectTimer ();
|
||||
m_DHKeysPair = transports.GetNextDHKeysPair ();
|
||||
SendSessionRequest ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::WaitForConnect ()
|
||||
@ -830,7 +830,7 @@ namespace transport
|
||||
m_ConnectTimer.cancel ();
|
||||
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
|
||||
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)
|
||||
@ -840,14 +840,14 @@ namespace transport
|
||||
// timeout expired
|
||||
LogPrint (eLogWarning, "SSU: session with ", m_RemoteEndpoint, " was not established after ", SSU_CONNECT_TIMEOUT, " seconds");
|
||||
Failed ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::Introduce (const i2p::data::RouterInfo::Introducer& introducer,
|
||||
std::shared_ptr<const i2p::data::RouterInfo> to)
|
||||
{
|
||||
if (m_State == eSessionStateUnknown)
|
||||
{
|
||||
{
|
||||
// set connect timer
|
||||
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
|
||||
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
|
||||
@ -865,7 +865,7 @@ namespace transport
|
||||
// set connect timer
|
||||
m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU_CONNECT_TIMEOUT));
|
||||
m_ConnectTimer.async_wait (std::bind (&SSUSession::HandleConnectTimer,
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
shared_from_this (), std::placeholders::_1));
|
||||
}
|
||||
|
||||
void SSUSession::Close ()
|
||||
@ -873,7 +873,7 @@ namespace transport
|
||||
SendSessionDestroyed ();
|
||||
Reset ();
|
||||
m_State = eSessionStateClosed;
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::Reset ()
|
||||
{
|
||||
@ -882,10 +882,10 @@ namespace transport
|
||||
m_Data.Stop ();
|
||||
m_ConnectTimer.cancel ();
|
||||
if (m_SentRelayTag)
|
||||
{
|
||||
{
|
||||
m_Server.RemoveRelay (m_SentRelayTag); // relay tag is not valid anymore
|
||||
m_SentRelayTag = 0;
|
||||
}
|
||||
}
|
||||
m_DHKeysPair = nullptr;
|
||||
m_SignedData = nullptr;
|
||||
m_IsSessionKey = false;
|
||||
@ -908,20 +908,20 @@ namespace transport
|
||||
if (m_SentRelayTag)
|
||||
m_Server.AddRelay (m_SentRelayTag, shared_from_this ());
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::Failed ()
|
||||
{
|
||||
if (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)
|
||||
{
|
||||
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)
|
||||
@ -931,7 +931,7 @@ namespace transport
|
||||
for (const auto& it: msgs)
|
||||
if (it) m_Data.Send (it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::ProcessData (uint8_t * buf, size_t len)
|
||||
{
|
||||
@ -942,29 +942,29 @@ namespace transport
|
||||
void SSUSession::FlushData ()
|
||||
{
|
||||
if (m_IsDataReceived)
|
||||
{
|
||||
{
|
||||
m_Data.FlushReceivedMessage ();
|
||||
m_IsDataReceived = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::ProcessPeerTest (const uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint)
|
||||
{
|
||||
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
|
||||
uint16_t port = buf16toh(buf + size + 5); // big endian, 2 bytes
|
||||
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");
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (m_Server.GetPeerTestParticipant (nonce))
|
||||
{
|
||||
// existing test
|
||||
{
|
||||
// existing test
|
||||
case ePeerTestParticipantAlice1:
|
||||
{
|
||||
{
|
||||
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
|
||||
{
|
||||
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
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
case ePeerTestParticipantAlice2:
|
||||
{
|
||||
if (m_Server.GetPeerTestSession (nonce) == shared_from_this ()) // Alice-Bob
|
||||
@ -994,8 +994,8 @@ namespace transport
|
||||
m_Server.RemovePeerTest (nonce);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ePeerTestParticipantBob:
|
||||
}
|
||||
case ePeerTestParticipantBob:
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: peer test from Charlie. We are Bob");
|
||||
auto session = m_Server.GetPeerTestSession (nonce); // session with Alice from PeerTest
|
||||
@ -1005,13 +1005,13 @@ namespace transport
|
||||
break;
|
||||
}
|
||||
case ePeerTestParticipantCharlie:
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "SSU: peer test from Alice. We are Charlie");
|
||||
SendPeerTest (nonce, senderEndpoint.address (), senderEndpoint.port (), introKey); // to Alice with her actual address
|
||||
m_Server.RemovePeerTest (nonce); // nonce has been used
|
||||
break;
|
||||
}
|
||||
// test not found
|
||||
// test not found
|
||||
case ePeerTestParticipantUnknown:
|
||||
{
|
||||
if (m_State == eSessionStateEstablished)
|
||||
@ -1034,7 +1034,7 @@ namespace transport
|
||||
boost::asio::ip::address_v6::bytes_type bytes;
|
||||
memcpy (bytes.data (), address, 16);
|
||||
addr = boost::asio::ip::address_v6 (bytes);
|
||||
}
|
||||
}
|
||||
SendPeerTest (nonce, addr, be16toh (port), introKey); // to Alice with her address received from Bob
|
||||
}
|
||||
else
|
||||
@ -1044,26 +1044,26 @@ namespace transport
|
||||
if (session)
|
||||
{
|
||||
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
|
||||
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)
|
||||
// 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 iv[16];
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
htobe32buf (payload, nonce);
|
||||
payload += 4; // nonce
|
||||
payload += 4; // nonce
|
||||
// address and port
|
||||
if (sendAddress)
|
||||
{
|
||||
@ -1075,11 +1075,11 @@ namespace transport
|
||||
else if (address.is_v6 ())
|
||||
{
|
||||
*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
|
||||
*payload = 0;
|
||||
payload += (payload[0] + 1);
|
||||
payload += (payload[0] + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1096,27 +1096,27 @@ namespace transport
|
||||
if (addr)
|
||||
memcpy (payload, addr->ssu->key, 32); // intro key
|
||||
else
|
||||
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
||||
}
|
||||
else
|
||||
LogPrint (eLogInfo, "SSU is not supported. Can't send peer test");
|
||||
}
|
||||
else
|
||||
memcpy (payload, introKey, 32); // intro key
|
||||
|
||||
// send
|
||||
// send
|
||||
RAND_bytes (iv, 16); // random iv
|
||||
if (toAddress)
|
||||
{
|
||||
{
|
||||
// encrypt message with specified intro key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80, introKey, iv, introKey);
|
||||
boost::asio::ip::udp::endpoint e (address, port);
|
||||
m_Server.Send (buf, 80, e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// encrypt message with session key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_PEER_TEST, buf, 80);
|
||||
Send (buf, 80);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::SendPeerTest ()
|
||||
{
|
||||
@ -1134,23 +1134,23 @@ namespace transport
|
||||
m_IsPeerTest = false;
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::SendKeepAlive ()
|
||||
{
|
||||
if (m_State == eSessionStateEstablished)
|
||||
{
|
||||
{
|
||||
uint8_t buf[48 + 18] = {0};
|
||||
uint8_t * payload = buf + sizeof (SSUHeader);
|
||||
*payload = 0; // flags
|
||||
payload++;
|
||||
*payload = 0; // num fragments
|
||||
*payload = 0; // num fragments
|
||||
// encrypt message with session key
|
||||
FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, 48);
|
||||
Send (buf, 48);
|
||||
LogPrint (eLogDebug, "SSU: keep-alive sent");
|
||||
m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::SendSessionDestroyed ()
|
||||
@ -1170,31 +1170,31 @@ namespace transport
|
||||
}
|
||||
LogPrint (eLogDebug, "SSU: session destroyed sent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::Send (uint8_t type, const uint8_t * payload, size_t len)
|
||||
{
|
||||
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
|
||||
if (paddingSize > 0) msgSize += (16 - paddingSize);
|
||||
if (msgSize > SSU_MTU_V4)
|
||||
{
|
||||
LogPrint (eLogWarning, "SSU: payload size ", msgSize, " exceeds MTU");
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy (buf + sizeof (SSUHeader), payload, len);
|
||||
// encrypt message with session key
|
||||
FillHeaderAndEncrypt (type, buf, msgSize);
|
||||
Send (buf, msgSize);
|
||||
}
|
||||
}
|
||||
|
||||
void SSUSession::Send (const uint8_t * buf, size_t size)
|
||||
{
|
||||
m_NumSentBytes += size;
|
||||
i2p::transport::transports.UpdateSentBytes (size);
|
||||
m_Server.Send (buf, size, m_RemoteEndpoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,15 +19,15 @@ namespace transport
|
||||
uint8_t mac[16];
|
||||
uint8_t iv[16];
|
||||
uint8_t flag;
|
||||
uint8_t time[4];
|
||||
uint8_t time[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_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)
|
||||
const uint8_t PAYLOAD_TYPE_SESSION_REQUEST = 0;
|
||||
@ -45,12 +45,12 @@ namespace transport
|
||||
|
||||
enum SessionState
|
||||
{
|
||||
eSessionStateUnknown,
|
||||
eSessionStateUnknown,
|
||||
eSessionStateIntroduced,
|
||||
eSessionStateEstablished,
|
||||
eSessionStateClosed,
|
||||
eSessionStateFailed
|
||||
};
|
||||
};
|
||||
|
||||
enum PeerTestParticipant
|
||||
{
|
||||
@ -60,7 +60,7 @@ namespace transport
|
||||
ePeerTestParticipantBob,
|
||||
ePeerTestParticipantCharlie
|
||||
};
|
||||
|
||||
|
||||
class SSUServer;
|
||||
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,
|
||||
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 ();
|
||||
|
||||
|
||||
void Connect ();
|
||||
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
|
||||
void WaitForIntroduction ();
|
||||
void Close ();
|
||||
@ -82,23 +82,23 @@ namespace transport
|
||||
boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; };
|
||||
bool IsV6 () const { return m_RemoteEndpoint.address ().is_v6 (); };
|
||||
void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs);
|
||||
void SendPeerTest (); // Alice
|
||||
void SendPeerTest (); // Alice
|
||||
|
||||
SessionState GetState () const { return m_State; };
|
||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
|
||||
void SendKeepAlive ();
|
||||
uint32_t GetRelayTag () const { return m_RelayTag; };
|
||||
|
||||
void SendKeepAlive ();
|
||||
uint32_t GetRelayTag () const { return m_RelayTag; };
|
||||
const i2p::data::RouterInfo::IntroKey& GetIntroKey () const { return m_IntroKey; };
|
||||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||
|
||||
void FlushData ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
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;
|
||||
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
|
||||
@ -119,23 +119,23 @@ namespace transport
|
||||
void ScheduleConnectTimer ();
|
||||
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 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 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 SendSessionDestroyed ();
|
||||
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 FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const i2p::crypto::AESKey& aesKey,
|
||||
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,
|
||||
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 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 ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
friend class SSUData; // TODO: change in later
|
||||
SSUServer& m_Server;
|
||||
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
|
||||
|
@ -16,24 +16,24 @@ namespace crypto
|
||||
BIGNUM * tmp = BN_new ();
|
||||
|
||||
q = BN_new ();
|
||||
// 2^255-19
|
||||
BN_set_bit (q, 255); // 2^255
|
||||
// 2^255-19
|
||||
BN_set_bit (q, 255); // 2^255
|
||||
BN_sub_word (q, 19);
|
||||
|
||||
|
||||
l = BN_new ();
|
||||
// 2^252 + 27742317777372353535851937790883648493
|
||||
BN_set_bit (l, 252);
|
||||
two_252_2 = BN_dup (l);
|
||||
BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
|
||||
BN_add (l, l, tmp);
|
||||
BN_sub_word (two_252_2, 2); // 2^252 - 2
|
||||
BN_add (l, l, tmp);
|
||||
BN_sub_word (two_252_2, 2); // 2^252 - 2
|
||||
|
||||
// -121665*inv(121666)
|
||||
d = BN_new ();
|
||||
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_negative (d, 1);
|
||||
BN_set_negative (d, 1);
|
||||
BN_mul (d, d, tmp, ctx);
|
||||
|
||||
// 2^((q-1)/4)
|
||||
@ -41,20 +41,20 @@ namespace crypto
|
||||
BN_free (tmp);
|
||||
tmp = BN_dup (q);
|
||||
BN_sub_word (tmp, 1);
|
||||
BN_div_word (tmp, 4);
|
||||
BN_div_word (tmp, 4);
|
||||
BN_set_word (I, 2);
|
||||
BN_mod_exp (I, I, tmp, q, ctx);
|
||||
BN_free (tmp);
|
||||
|
||||
// 4*inv(5)
|
||||
BIGNUM * By = BN_new ();
|
||||
BN_free (tmp);
|
||||
|
||||
// 4*inv(5)
|
||||
BIGNUM * By = BN_new ();
|
||||
BN_set_word (By, 5);
|
||||
BN_mod_inverse (By, By, q, ctx);
|
||||
BN_mod_inverse (By, By, q, ctx);
|
||||
BN_mul_word (By, 4);
|
||||
BIGNUM * Bx = RecoverX (By, ctx);
|
||||
BIGNUM * Bx = RecoverX (By, ctx);
|
||||
BN_mod (Bx, Bx, q, ctx); // % q
|
||||
BN_mod (By, By, q, ctx); // % q
|
||||
|
||||
BN_mod (By, By, q, ctx); // % q
|
||||
|
||||
// precalculate Bi256 table
|
||||
Bi256Carry = { Bx, By }; // B
|
||||
for (int i = 0; i < 32; i++)
|
||||
@ -70,7 +70,7 @@ namespace crypto
|
||||
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)),
|
||||
Bi256Carry (other.Bi256Carry)
|
||||
{
|
||||
@ -106,9 +106,9 @@ namespace crypto
|
||||
|
||||
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);
|
||||
// signature 0..31 - R, 32..63 - S
|
||||
// signature 0..31 - R, 32..63 - S
|
||||
// B*S = R + PK*h => R = 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;
|
||||
@ -117,14 +117,14 @@ namespace crypto
|
||||
uint8_t diff[32];
|
||||
EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
|
||||
bool passed = !memcmp (signature, diff, 32); // R
|
||||
BN_free (h);
|
||||
BN_free (h);
|
||||
BN_CTX_free (ctx);
|
||||
if (!passed)
|
||||
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
|
||||
{
|
||||
BN_CTX * bnCtx = BN_CTX_new ();
|
||||
@ -138,14 +138,14 @@ namespace crypto
|
||||
BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors
|
||||
// calculate R
|
||||
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
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
|
||||
SHA512_Update (&ctx, buf, len); // data
|
||||
SHA512_Final (digest, &ctx);
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
BIGNUM * h = DecodeBN<64> (digest);
|
||||
// S = (r + h*a) % l
|
||||
BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
|
||||
BN_mod_mul (h, h, a, l, bnCtx); // %l
|
||||
@ -156,7 +156,7 @@ namespace crypto
|
||||
BN_CTX_free (bnCtx);
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
|
||||
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)
|
||||
// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
|
||||
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 (y3, p1.y, p2.y, ctx); // B = y1*y2
|
||||
|
||||
BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
|
||||
BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
|
||||
|
||||
BN_CTX_start (ctx);
|
||||
BIGNUM * t1 = p1.t, * t2 = p2.t;
|
||||
@ -189,10 +189,10 @@ namespace crypto
|
||||
BN_copy (z3, p2.z); // D = z2
|
||||
else
|
||||
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);
|
||||
BN_add (E, p1.x, p1.y);
|
||||
BN_add (E, p1.x, p1.y);
|
||||
BN_add (F, p2.x, p2.y);
|
||||
BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
|
||||
BN_sub (E, E, x3);
|
||||
@ -202,9 +202,9 @@ namespace crypto
|
||||
BN_add (H, y3, x3); // H = B + A
|
||||
|
||||
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 (z3, F, G, q, ctx); // z3 = F*G
|
||||
BN_mod_mul (t3, E, H, q, ctx); // t3 = E*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 (t3, E, H, q, ctx); // t3 = E*H
|
||||
|
||||
BN_CTX_end (ctx);
|
||||
|
||||
@ -215,40 +215,40 @@ namespace crypto
|
||||
{
|
||||
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);
|
||||
|
||||
BN_sqr (x2, p.x, ctx); // x2 = A = x^2
|
||||
BN_sqr (y2, p.y, ctx); // y2 = B = y^2
|
||||
|
||||
BN_sqr (x2, p.x, ctx); // x2 = A = x^2
|
||||
BN_sqr (y2, p.y, ctx); // y2 = B = y^2
|
||||
if (p.t)
|
||||
BN_sqr (t2, p.t, ctx); // t2 = t^2
|
||||
else
|
||||
{
|
||||
BN_mul (t2, p.x, p.y, ctx); // t = x*y
|
||||
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)
|
||||
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
|
||||
BN_sqr (z2, p.z, ctx); // z2 = D = z^2
|
||||
else
|
||||
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);
|
||||
// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
|
||||
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_add (G, z2, t2); // G = D + C
|
||||
BN_add (G, z2, t2); // G = D + C
|
||||
BN_add (H, y2, x2); // H = B + A
|
||||
|
||||
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 ();
|
||||
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 ();
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
EDDSAPoint Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const
|
||||
{
|
||||
BIGNUM * zero = BN_new (), * one = BN_new ();
|
||||
@ -262,10 +262,10 @@ namespace crypto
|
||||
Double (res, ctx);
|
||||
if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 ();
|
||||
@ -275,15 +275,15 @@ namespace crypto
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
uint8_t x = e[i];
|
||||
if (carry)
|
||||
{
|
||||
if (x < 255)
|
||||
{
|
||||
x++;
|
||||
if (carry)
|
||||
{
|
||||
if (x < 255)
|
||||
{
|
||||
x++;
|
||||
carry = false;
|
||||
}
|
||||
else
|
||||
x = 0;
|
||||
}
|
||||
else
|
||||
x = 0;
|
||||
}
|
||||
if (x > 0)
|
||||
{
|
||||
@ -293,7 +293,7 @@ namespace crypto
|
||||
{
|
||||
res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
|
||||
carry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
BN_sqr (x2, p.x, ctx); // x^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, tmp, y2, ctx);
|
||||
BN_mul (tmp, tmp, y2, ctx);
|
||||
BN_sub (tmp, y2, tmp);
|
||||
BN_sub (tmp, tmp, x2);
|
||||
BN_sub_word (tmp, 1);
|
||||
@ -330,25 +330,25 @@ namespace crypto
|
||||
bool ret = BN_is_zero (tmp);
|
||||
BN_CTX_end (ctx);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
BIGNUM * RecoverX (const BIGNUM * y, BN_CTX * ctx) const
|
||||
{
|
||||
BN_CTX_start (ctx);
|
||||
BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx);
|
||||
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_add_word (xx, 1);
|
||||
BN_mod_inverse (xx, xx, q, ctx);
|
||||
BN_sub_word (y2, 1);
|
||||
BN_mul (xx, y2, xx, ctx);
|
||||
// x = srqt(xx) = xx^(2^252-2)
|
||||
// x = srqt(xx) = xx^(2^252-2)
|
||||
BIGNUM * x = BN_new ();
|
||||
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_mod_sub (y2, y2, xx, q, ctx);
|
||||
BN_mod_sub (y2, y2, xx, q, ctx);
|
||||
if (!BN_is_zero (y2))
|
||||
BN_mod_mul (x, x, I, q, ctx);
|
||||
if (BN_is_odd (x))
|
||||
@ -373,18 +373,18 @@ namespace crypto
|
||||
BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
|
||||
BIGNUM * x = RecoverX (y, ctx);
|
||||
if (BN_is_bit_set (x, 0) != isHighestBitSet)
|
||||
BN_sub (x, q, x); // x = q - x
|
||||
BIGNUM * z = BN_new (), * t = BN_new ();
|
||||
BN_sub (x, q, x); // x = q - x
|
||||
BIGNUM * z = BN_new (), * t = BN_new ();
|
||||
BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
|
||||
EDDSAPoint p {x, y, z, t};
|
||||
if (!IsOnCurve (p, ctx))
|
||||
if (!IsOnCurve (p, ctx))
|
||||
LogPrint (eLogError, "Decoded point is not on 25519");
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit
|
||||
}
|
||||
@ -413,12 +413,12 @@ namespace crypto
|
||||
uint8_t tmp = buf[i];
|
||||
buf[i] = buf[len -1 - i];
|
||||
buf[len -1 - i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
BIGNUM * q, * l, * d, * I;
|
||||
|
||||
BIGNUM * q, * l, * d, * I;
|
||||
// transient values
|
||||
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
|
||||
@ -437,14 +437,14 @@ namespace crypto
|
||||
g_Ed25519.reset (c);
|
||||
else
|
||||
delete c;
|
||||
}
|
||||
return g_Ed25519;
|
||||
}
|
||||
|
||||
}
|
||||
return g_Ed25519;
|
||||
}
|
||||
|
||||
|
||||
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 ();
|
||||
m_PublicKey = GetEd25519 ()->DecodePublicKey (m_PublicKeyEncoded, ctx);
|
||||
BN_CTX_free (ctx);
|
||||
@ -457,40 +457,40 @@ namespace crypto
|
||||
SHA512_Init (&ctx);
|
||||
SHA512_Update (&ctx, signature, EDDSA25519_SIGNATURE_LENGTH/2); // R
|
||||
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);
|
||||
|
||||
|
||||
return GetEd25519 ()->Verify (m_PublicKey, digest, signature);
|
||||
}
|
||||
|
||||
EDDSA25519Signer::EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey)
|
||||
{
|
||||
{
|
||||
// expand key
|
||||
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] |= 0x40; // set second bit
|
||||
|
||||
|
||||
// generate and encode public key
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
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))
|
||||
{
|
||||
// keys don't match, it means older key with 0x1F
|
||||
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);
|
||||
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
|
||||
GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx);
|
||||
}
|
||||
BN_CTX_free (ctx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EDDSA25519Signer::Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
GetEd25519 ()->Sign (m_ExpandedPrivateKey, m_PublicKeyEncoded, buf, len, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace crypto
|
||||
class Verifier
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
virtual ~Verifier () {};
|
||||
virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0;
|
||||
virtual size_t GetPublicKeyLen () const = 0;
|
||||
@ -30,12 +30,12 @@ namespace crypto
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Signer () {};
|
||||
virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0;
|
||||
virtual ~Signer () {};
|
||||
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_SIGNATURE_LENGTH = 40;
|
||||
const size_t DSA_SIGNATURE_LENGTH = 40;
|
||||
const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2;
|
||||
class DSAVerifier: public Verifier
|
||||
{
|
||||
@ -51,7 +51,7 @@ namespace crypto
|
||||
{
|
||||
DSA_free (m_PublicKey);
|
||||
}
|
||||
|
||||
|
||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
// calculate SHA1 digest
|
||||
@ -64,11 +64,11 @@ namespace crypto
|
||||
int ret = DSA_do_verify (digest, 20, sig, m_PublicKey);
|
||||
DSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; };
|
||||
size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
DSA * m_PublicKey;
|
||||
@ -89,7 +89,7 @@ namespace crypto
|
||||
{
|
||||
DSA_free (m_PrivateKey);
|
||||
}
|
||||
|
||||
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[20];
|
||||
@ -115,21 +115,21 @@ namespace crypto
|
||||
DSA_get0_key(dsa, &pub_key, &priv_key);
|
||||
bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH);
|
||||
bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH);
|
||||
DSA_free (dsa);
|
||||
}
|
||||
DSA_free (dsa);
|
||||
}
|
||||
|
||||
struct SHA256Hash
|
||||
{
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
SHA256 (buf, len, digest);
|
||||
}
|
||||
|
||||
enum { hashLen = 32 };
|
||||
};
|
||||
};
|
||||
|
||||
struct SHA384Hash
|
||||
{
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
SHA384 (buf, len, digest);
|
||||
@ -139,7 +139,7 @@ namespace crypto
|
||||
};
|
||||
|
||||
struct SHA512Hash
|
||||
{
|
||||
{
|
||||
static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest)
|
||||
{
|
||||
SHA512 (buf, len, digest);
|
||||
@ -147,10 +147,10 @@ namespace crypto
|
||||
|
||||
enum { hashLen = 64 };
|
||||
};
|
||||
|
||||
|
||||
template<typename Hash, int curve, size_t keyLen>
|
||||
class ECDSAVerifier: public Verifier
|
||||
{
|
||||
{
|
||||
public:
|
||||
|
||||
ECDSAVerifier (const uint8_t * signingKey)
|
||||
@ -166,7 +166,7 @@ namespace crypto
|
||||
{
|
||||
EC_KEY_free (m_PublicKey);
|
||||
}
|
||||
|
||||
|
||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[Hash::hashLen];
|
||||
@ -179,12 +179,12 @@ namespace crypto
|
||||
int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey);
|
||||
ECDSA_SIG_free(sig);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
size_t GetPublicKeyLen () const { return keyLen; };
|
||||
size_t GetSignatureLen () const { return keyLen; }; // signature length = key length
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
EC_KEY * m_PublicKey;
|
||||
@ -198,14 +198,14 @@ namespace crypto
|
||||
ECDSASigner (const uint8_t * signingPrivateKey)
|
||||
{
|
||||
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 ()
|
||||
{
|
||||
EC_KEY_free (m_PrivateKey);
|
||||
}
|
||||
|
||||
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[Hash::hashLen];
|
||||
@ -235,18 +235,18 @@ namespace crypto
|
||||
bn2buf (x, signingPublicKey, keyLen/2);
|
||||
bn2buf (y, signingPublicKey + keyLen/2, keyLen/2);
|
||||
BN_free (x); BN_free (y);
|
||||
EC_KEY_free (signingKey);
|
||||
EC_KEY_free (signingKey);
|
||||
}
|
||||
|
||||
// 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 ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer;
|
||||
|
||||
inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||
}
|
||||
}
|
||||
|
||||
// ECDSA_SHA384_P384
|
||||
const size_t ECDSAP384_KEY_LENGTH = 96;
|
||||
@ -256,7 +256,7 @@ namespace crypto
|
||||
inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey);
|
||||
}
|
||||
}
|
||||
|
||||
// ECDSA_SHA512_P521
|
||||
const size_t ECDSAP521_KEY_LENGTH = 132;
|
||||
@ -269,7 +269,7 @@ namespace crypto
|
||||
}
|
||||
|
||||
// RSA
|
||||
template<typename Hash, int type, size_t keyLen>
|
||||
template<typename Hash, int type, size_t keyLen>
|
||||
class RSAVerifier: public Verifier
|
||||
{
|
||||
public:
|
||||
@ -284,23 +284,23 @@ namespace crypto
|
||||
{
|
||||
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];
|
||||
Hash::CalculateHash (buf, len, digest);
|
||||
return RSA_verify (type, digest, Hash::hashLen, signature, GetSignatureLen (), m_PublicKey);
|
||||
}
|
||||
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; };
|
||||
|
||||
private:
|
||||
|
||||
RSA * m_PublicKey;
|
||||
};
|
||||
|
||||
|
||||
RSA * m_PublicKey;
|
||||
};
|
||||
|
||||
|
||||
template<typename Hash, int type, size_t keyLen>
|
||||
class RSASigner: public Signer
|
||||
{
|
||||
@ -317,7 +317,7 @@ namespace crypto
|
||||
{
|
||||
RSA_free (m_PrivateKey);
|
||||
}
|
||||
|
||||
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[Hash::hashLen];
|
||||
@ -325,11 +325,11 @@ namespace crypto
|
||||
unsigned int signatureLen = keyLen;
|
||||
RSA_sign (type, digest, Hash::hashLen, signature, &signatureLen, m_PrivateKey);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
RSA * m_PrivateKey;
|
||||
};
|
||||
};
|
||||
|
||||
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
|
||||
RSA_generate_key_ex (rsa, publicKeyLen*8, e, NULL);
|
||||
const BIGNUM * n, * d, * e1;
|
||||
RSA_get0_key (rsa, &n, &e1, &d);
|
||||
RSA_get0_key (rsa, &n, &e1, &d);
|
||||
bn2buf (n, signingPrivateKey, publicKeyLen);
|
||||
bn2buf (d, signingPrivateKey + publicKeyLen, publicKeyLen);
|
||||
bn2buf (n, signingPublicKey, publicKeyLen);
|
||||
BN_free (e); // this e is not assigned to rsa->e
|
||||
RSA_free (rsa);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// RSA_SHA256_2048
|
||||
const size_t RSASHA2562048_KEY_LENGTH = 256;
|
||||
typedef RSAVerifier<SHA256Hash, NID_sha256, RSASHA2562048_KEY_LENGTH> RSASHA2562048Verifier;
|
||||
@ -353,7 +353,7 @@ namespace crypto
|
||||
// RSA_SHA384_3072
|
||||
const size_t RSASHA3843072_KEY_LENGTH = 384;
|
||||
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
|
||||
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& operator=(EDDSAPoint&& other)
|
||||
EDDSAPoint& operator=(EDDSAPoint&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
@ -389,9 +389,9 @@ namespace crypto
|
||||
BN_free (t); t = other.t; other.t = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
EDDSAPoint& operator=(const EDDSAPoint& other)
|
||||
EDDSAPoint& operator=(const EDDSAPoint& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
@ -412,11 +412,11 @@ namespace crypto
|
||||
if (t) { t1 = BN_dup (t); BN_set_negative (t1, !BN_is_negative (t)); };
|
||||
return EDDSAPoint {x1, y1, z1, t1};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const size_t EDDSA25519_PUBLIC_KEY_LENGTH = 32;
|
||||
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
|
||||
{
|
||||
public:
|
||||
@ -429,7 +429,7 @@ namespace crypto
|
||||
|
||||
private:
|
||||
|
||||
EDDSAPoint m_PublicKey;
|
||||
EDDSAPoint m_PublicKey;
|
||||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
};
|
||||
|
||||
@ -437,14 +437,14 @@ namespace crypto
|
||||
{
|
||||
public:
|
||||
|
||||
EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
|
||||
// we pass signingPublicKey to check if it matches private key
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||
EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr);
|
||||
// we pass signingPublicKey to check if it matches private key
|
||||
void Sign (const uint8_t * buf, int len, uint8_t * signature) const;
|
||||
const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
uint8_t m_ExpandedPrivateKey[64];
|
||||
uint8_t m_ExpandedPrivateKey[64];
|
||||
uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH];
|
||||
};
|
||||
|
||||
@ -456,22 +456,22 @@ namespace crypto
|
||||
}
|
||||
|
||||
|
||||
// ГОСТ Р 34.11
|
||||
// ГОСТ Р 34.11
|
||||
struct GOSTR3411_256_Hash
|
||||
{
|
||||
{
|
||||
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 };
|
||||
};
|
||||
|
||||
struct GOSTR3411_512_Hash
|
||||
{
|
||||
{
|
||||
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 };
|
||||
@ -487,7 +487,7 @@ namespace crypto
|
||||
public:
|
||||
|
||||
enum { keyLen = Hash::hashLen };
|
||||
|
||||
|
||||
GOSTR3410Verifier (GOSTR3410ParamSet paramSet, const uint8_t * signingKey):
|
||||
m_ParamSet (paramSet)
|
||||
{
|
||||
@ -497,7 +497,7 @@ namespace crypto
|
||||
BN_free (x); BN_free (y);
|
||||
}
|
||||
~GOSTR3410Verifier () { EC_POINT_free (m_PublicKey); }
|
||||
|
||||
|
||||
bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const
|
||||
{
|
||||
uint8_t digest[Hash::hashLen];
|
||||
@ -506,7 +506,7 @@ namespace crypto
|
||||
BIGNUM * r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL);
|
||||
BIGNUM * s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -517,7 +517,7 @@ namespace crypto
|
||||
|
||||
GOSTR3410ParamSet m_ParamSet;
|
||||
EC_POINT * m_PublicKey;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename Hash>
|
||||
class GOSTR3410Signer: public Signer
|
||||
@ -525,11 +525,11 @@ namespace crypto
|
||||
public:
|
||||
|
||||
enum { keyLen = Hash::hashLen };
|
||||
|
||||
|
||||
GOSTR3410Signer (GOSTR3410ParamSet paramSet, const uint8_t * signingPrivateKey):
|
||||
m_ParamSet (paramSet)
|
||||
{
|
||||
m_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
|
||||
{
|
||||
m_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
|
||||
}
|
||||
~GOSTR3410Signer () { BN_free (m_PrivateKey); }
|
||||
|
||||
@ -537,19 +537,19 @@ namespace crypto
|
||||
{
|
||||
uint8_t digest[Hash::hashLen];
|
||||
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 ();
|
||||
GetGOSTR3410Curve (m_ParamSet)->Sign (m_PrivateKey, d, r, s);
|
||||
bn2buf (r, signature, keyLen);
|
||||
bn2buf (s, signature + keyLen, keyLen);
|
||||
BN_free (d); BN_free (r); BN_free (s);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
GOSTR3410ParamSet m_ParamSet;
|
||||
BIGNUM * m_PrivateKey;
|
||||
};
|
||||
};
|
||||
|
||||
inline void CreateGOSTR3410RandomKeys (GOSTR3410ParamSet paramSet, uint8_t * signingPrivateKey, uint8_t * signingPublicKey)
|
||||
{
|
||||
@ -557,7 +557,7 @@ namespace crypto
|
||||
auto keyLen = curve->GetKeyLen ();
|
||||
RAND_bytes (signingPrivateKey, keyLen);
|
||||
BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen, nullptr);
|
||||
|
||||
|
||||
auto pub = curve->MulP (priv);
|
||||
BN_free (priv);
|
||||
BIGNUM * x = BN_new (), * y = BN_new ();
|
||||
@ -565,7 +565,7 @@ namespace crypto
|
||||
EC_POINT_free (pub);
|
||||
bn2buf (x, signingPublicKey, 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;
|
||||
|
@ -12,11 +12,11 @@ namespace i2p
|
||||
namespace stream
|
||||
{
|
||||
void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler)
|
||||
{
|
||||
{
|
||||
m_Buffers.push_back (std::make_shared<SendBuffer>(buf, len, handler));
|
||||
m_Size += len;
|
||||
}
|
||||
|
||||
|
||||
size_t SendBufferQueue::Get (uint8_t * buf, size_t len)
|
||||
{
|
||||
size_t offset = 0;
|
||||
@ -30,7 +30,7 @@ namespace stream
|
||||
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), rem);
|
||||
offset += rem;
|
||||
m_Buffers.pop_front (); // delete it
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// partially
|
||||
@ -38,23 +38,23 @@ namespace stream
|
||||
memcpy (buf + offset, nextBuffer->GetRemaningBuffer (), len - offset);
|
||||
nextBuffer->offset += (len - offset);
|
||||
offset = len; // break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Size -= offset;
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
void SendBufferQueue::CleanUp ()
|
||||
{
|
||||
void SendBufferQueue::CleanUp ()
|
||||
{
|
||||
if (!m_Buffers.empty ())
|
||||
{
|
||||
{
|
||||
for (auto it: m_Buffers)
|
||||
it->Cancel ();
|
||||
m_Buffers.clear ();
|
||||
m_Buffers.clear ();
|
||||
m_Size = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Stream::Stream (boost::asio::io_service& service, StreamingDestination& local,
|
||||
std::shared_ptr<const i2p::data::LeaseSet> remote, int port): m_Service (service),
|
||||
m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (-1),
|
||||
@ -100,7 +100,7 @@ namespace stream
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SendBufferMutex);
|
||||
m_SendBuffer.CleanUp ();
|
||||
}
|
||||
}
|
||||
while (!m_ReceiveQueue.empty ())
|
||||
{
|
||||
auto packet = m_ReceiveQueue.front ();
|
||||
@ -1108,7 +1108,7 @@ namespace stream
|
||||
}
|
||||
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);
|
||||
}
|
||||
});
|
||||
@ -1118,8 +1118,8 @@ namespace stream
|
||||
{
|
||||
m_Acceptor = prev;
|
||||
acceptor (stream);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StreamingDestination::HandlePendingIncomingTimer (const boost::system::error_code& ecode)
|
||||
{
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
|
@ -41,40 +41,40 @@ namespace stream
|
||||
|
||||
const size_t STREAMING_MTU = 1730;
|
||||
const size_t MAX_PACKET_SIZE = 4096;
|
||||
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
|
||||
const int MAX_NUM_RESEND_ATTEMPTS = 6;
|
||||
const size_t COMPRESSION_THRESHOLD_SIZE = 66;
|
||||
const int MAX_NUM_RESEND_ATTEMPTS = 6;
|
||||
const int WINDOW_SIZE = 6; // in messages
|
||||
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_RTO = 9000; // 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 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 */
|
||||
const char I2CP_PARAM_STREAMING_MAX_CONNS_PER_MIN[] = "maxconns";
|
||||
/** default maximum connections attempts per minute per destination */
|
||||
const uint32_t DEFAULT_MAX_CONNS_PER_MIN = 600;
|
||||
|
||||
/**
|
||||
/**
|
||||
* max banned destinations per local destination
|
||||
* TODO: make configurable
|
||||
*/
|
||||
const uint16_t MAX_BANNED_CONNS = 9999;
|
||||
/**
|
||||
/**
|
||||
* length of a ban in ms
|
||||
* TODO: make configurable
|
||||
* TODO: make configurable
|
||||
*/
|
||||
const uint64_t DEFAULT_BAN_INTERVAL = 60 * 60 * 1000;
|
||||
|
||||
|
||||
struct Packet
|
||||
{
|
||||
size_t len, offset;
|
||||
uint8_t buf[MAX_PACKET_SIZE];
|
||||
uint8_t buf[MAX_PACKET_SIZE];
|
||||
uint64_t sendTime;
|
||||
|
||||
|
||||
Packet (): len (0), offset (0), sendTime (0) {};
|
||||
uint8_t * GetBuffer () { return buf + offset; };
|
||||
size_t GetLength () const { return len - offset; };
|
||||
@ -93,15 +93,15 @@ namespace stream
|
||||
|
||||
bool IsSYN () const { return GetFlags () & PACKET_FLAG_SYNCHRONIZE; };
|
||||
bool IsNoAck () const { return GetFlags () & PACKET_FLAG_NO_ACK; };
|
||||
};
|
||||
};
|
||||
|
||||
struct PacketCmp
|
||||
{
|
||||
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;
|
||||
struct SendBuffer
|
||||
@ -115,16 +115,16 @@ namespace stream
|
||||
{
|
||||
buf = new uint8_t[len];
|
||||
memcpy (buf, b, len);
|
||||
}
|
||||
}
|
||||
~SendBuffer ()
|
||||
{
|
||||
delete[] buf;
|
||||
if (handler) handler(boost::system::error_code ());
|
||||
}
|
||||
}
|
||||
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; };
|
||||
};
|
||||
};
|
||||
|
||||
class SendBufferQueue
|
||||
{
|
||||
@ -133,18 +133,18 @@ namespace stream
|
||||
SendBufferQueue (): m_Size (0) {};
|
||||
~SendBufferQueue () { CleanUp (); };
|
||||
|
||||
void Add (const uint8_t * buf, size_t len, SendHandler handler);
|
||||
size_t Get (uint8_t * buf, size_t len);
|
||||
void Add (const uint8_t * buf, size_t len, SendHandler handler);
|
||||
size_t Get (uint8_t * buf, size_t len);
|
||||
size_t GetSize () const { return m_Size; };
|
||||
bool IsEmpty () const { return m_Buffers.empty (); };
|
||||
void CleanUp ();
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
|
||||
std::list<std::shared_ptr<SendBuffer> > m_Buffers;
|
||||
size_t m_Size;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
enum StreamStatus
|
||||
{
|
||||
eStreamStatusNew = 0,
|
||||
@ -152,16 +152,16 @@ namespace stream
|
||||
eStreamStatusReset,
|
||||
eStreamStatusClosing,
|
||||
eStreamStatusClosed
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class StreamingDestination;
|
||||
class Stream: public std::enable_shared_from_this<Stream>
|
||||
{
|
||||
{
|
||||
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
|
||||
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
|
||||
Stream (boost::asio::io_service& service, StreamingDestination& local); // incoming
|
||||
|
||||
~Stream ();
|
||||
uint32_t GetSendStreamID () const { return m_SendStreamID; };
|
||||
@ -172,15 +172,15 @@ namespace stream
|
||||
bool IsEstablished () const { return m_SendStreamID; };
|
||||
StreamStatus GetStatus () const { return m_Status; };
|
||||
StreamingDestination& GetLocalDestination () { return m_LocalDestination; };
|
||||
|
||||
|
||||
void HandleNextPacket (Packet * packet);
|
||||
size_t Send (const uint8_t * buf, size_t len);
|
||||
void AsyncSend (const uint8_t * buf, size_t len, SendHandler handler);
|
||||
|
||||
|
||||
template<typename Buffer, typename ReceiveHandler>
|
||||
void AsyncReceive (const Buffer& buffer, ReceiveHandler handler, int timeout = 0);
|
||||
size_t ReadSome (uint8_t * buf, size_t len) { return ConcatenatePackets (buf, len); };
|
||||
|
||||
|
||||
void Close ();
|
||||
void Cancel () { m_ReceiveTimer.cancel (); };
|
||||
|
||||
@ -194,11 +194,11 @@ namespace stream
|
||||
|
||||
/** don't call me */
|
||||
void Terminate ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void CleanUp ();
|
||||
|
||||
|
||||
void SendBuffer ();
|
||||
void SendQuickAck ();
|
||||
void SendClose ();
|
||||
@ -212,14 +212,14 @@ namespace stream
|
||||
size_t ConcatenatePackets (uint8_t * buf, size_t len);
|
||||
|
||||
void UpdateCurrentRemoteLease (bool expired = false);
|
||||
|
||||
|
||||
template<typename Buffer, typename ReceiveHandler>
|
||||
void HandleReceiveTimer (const boost::system::error_code& ecode, const Buffer& buffer, ReceiveHandler handler, int remainingTimeout);
|
||||
|
||||
|
||||
void ScheduleResend ();
|
||||
void HandleResendTimer (const boost::system::error_code& ecode);
|
||||
void HandleAckSendTimer (const boost::system::error_code& ecode);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::io_service& m_Service;
|
||||
@ -254,16 +254,16 @@ namespace stream
|
||||
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 ();
|
||||
~StreamingDestination ();
|
||||
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
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 ResetAcceptor ();
|
||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||
bool IsAcceptorSet () const { return m_Acceptor != nullptr; };
|
||||
void AcceptOnce (const Acceptor& acceptor);
|
||||
|
||||
std::shared_ptr<i2p::client::ClientDestination> GetOwner () const { return m_Owner; };
|
||||
@ -278,11 +278,11 @@ namespace stream
|
||||
|
||||
Packet * NewPacket () { return m_PacketsPool.Acquire (); }
|
||||
void DeletePacket (Packet * p) { m_PacketsPool.Release (p); }
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
|
||||
void AcceptOnceAcceptor (std::shared_ptr<Stream> stream, Acceptor acceptor, Acceptor prev);
|
||||
|
||||
|
||||
void HandleNextPacket (Packet * packet);
|
||||
std::shared_ptr<Stream> CreateNewIncomingStream ();
|
||||
void HandlePendingIncomingTimer (const boost::system::error_code& ecode);
|
||||
@ -293,7 +293,7 @@ namespace stream
|
||||
bool DropNewStream(const i2p::data::IdentHash & ident);
|
||||
|
||||
void ScheduleConnTrack();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<i2p::client::ClientDestination> m_Owner;
|
||||
@ -306,7 +306,7 @@ namespace stream
|
||||
std::list<std::shared_ptr<Stream> > m_PendingIncomingStreams;
|
||||
boost::asio::deadline_timer m_PendingIncomingTimer;
|
||||
std::map<uint32_t, std::list<Packet *> > m_SavedPackets; // receiveStreamID->packets, arrived before SYN
|
||||
|
||||
|
||||
std::mutex m_ConnsMutex;
|
||||
/** how many connections per minute did each identity have */
|
||||
std::map<i2p::data::IdentHash, uint32_t> m_Conns;
|
||||
@ -318,15 +318,15 @@ namespace stream
|
||||
|
||||
i2p::util::MemoryPool<Packet> m_PacketsPool;
|
||||
bool m_EnableDrop;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
i2p::data::GzipInflator m_Inflator;
|
||||
i2p::data::GzipDeflator m_Deflator;
|
||||
|
||||
|
||||
// for HTTP only
|
||||
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->HandleReceiveTimer (ecode, buffer, handler, timeout - t); });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Buffer, typename ReceiveHandler>
|
||||
@ -355,27 +355,27 @@ namespace stream
|
||||
if (received > 0)
|
||||
handler (boost::system::error_code (), received);
|
||||
else if (ecode == boost::asio::error::operation_aborted)
|
||||
{
|
||||
// timeout not expired
|
||||
{
|
||||
// timeout not expired
|
||||
if (m_Status == eStreamStatusReset)
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::connection_reset), 0);
|
||||
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
|
||||
{
|
||||
{
|
||||
// timeout expired
|
||||
if (remainingTimeout <= 0)
|
||||
handler (boost::asio::error::make_error_code (boost::asio::error::timed_out), received);
|
||||
else
|
||||
{
|
||||
{
|
||||
// itermediate iterrupt
|
||||
SendUpdatedLeaseSet (); // send our leaseset if applicable
|
||||
AsyncReceive (buffer, handler, remainingTimeout);
|
||||
}
|
||||
}
|
||||
AsyncReceive (buffer, handler, remainingTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
{
|
||||
RAND_bytes(m_Buf, sz);
|
||||
}
|
||||
|
||||
|
||||
std::string ToBase64 () const
|
||||
{
|
||||
char str[sz*2];
|
||||
|
@ -40,7 +40,7 @@ namespace util
|
||||
int i = 0;
|
||||
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++;
|
||||
}
|
||||
if (socket.available ())
|
||||
|
@ -10,58 +10,58 @@
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||
{
|
||||
TransitTunnel::TransitTunnel (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey):
|
||||
TunnelBase (receiveTunnelID, nextTunnelID, nextIdent)
|
||||
{
|
||||
{
|
||||
m_Encryption.SetKeys (layerKey, ivKey);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
TransitTunnelParticipant::~TransitTunnelParticipant ()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TransitTunnelParticipant::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
||||
{
|
||||
auto newMsg = CreateEmptyTunnelDataMsg ();
|
||||
EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||
|
||||
|
||||
m_NumTransmittedBytes += tunnelMsg->GetLength ();
|
||||
htobe32buf (newMsg->GetPayload (), GetNextTunnelID ());
|
||||
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
m_TunnelDataMsgs.push_back (newMsg);
|
||||
}
|
||||
|
||||
void TransitTunnelParticipant::FlushTunnelDataMsgs ()
|
||||
{
|
||||
if (!m_TunnelDataMsgs.empty ())
|
||||
{
|
||||
{
|
||||
auto num = m_TunnelDataMsgs.size ();
|
||||
if (num > 1)
|
||||
LogPrint (eLogDebug, "TransitTunnel: ", GetTunnelID (), "->", GetNextTunnelID (), " ", num);
|
||||
i2p::transport::transports.SendMessages (GetNextIdentHash (), m_TunnelDataMsgs);
|
||||
m_TunnelDataMsgs.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void TransitTunnel::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogError, "TransitTunnel: We are not a gateway for ", GetTunnelID ());
|
||||
}
|
||||
}
|
||||
|
||||
void TransitTunnel::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
||||
{
|
||||
LogPrint (eLogError, "TransitTunnel: Incoming tunnel message is not supported ", GetTunnelID ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TransitTunnelGateway::SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg)
|
||||
{
|
||||
TunnelMessageBlock block;
|
||||
@ -69,43 +69,43 @@ namespace tunnel
|
||||
block.data = msg;
|
||||
std::unique_lock<std::mutex> l(m_SendMutex);
|
||||
m_Gateway.PutTunnelDataMsg (block);
|
||||
}
|
||||
}
|
||||
|
||||
void TransitTunnelGateway::FlushTunnelDataMsgs ()
|
||||
{
|
||||
std::unique_lock<std::mutex> l(m_SendMutex);
|
||||
m_Gateway.SendBuffer ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TransitTunnelEndpoint::HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg)
|
||||
{
|
||||
auto newMsg = CreateEmptyTunnelDataMsg ();
|
||||
EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||
|
||||
|
||||
LogPrint (eLogDebug, "TransitTunnel: handle msg for endpoint ", GetTunnelID ());
|
||||
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
|
||||
m_Endpoint.HandleDecryptedTunnelDataMsg (newMsg);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey,
|
||||
bool isGateway, bool isEndpoint)
|
||||
{
|
||||
if (isEndpoint)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "TransitTunnel: endpoint ", receiveTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelEndpoint> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
}
|
||||
else if (isGateway)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogInfo, "TransitTunnel: gateway ", receiveTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelGateway> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
LogPrint (eLogDebug, "TransitTunnel: ", receiveTunnelID, "->", nextTunnelID, " created");
|
||||
return std::make_shared<TransitTunnelParticipant> (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,34 +14,34 @@
|
||||
namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
class TransitTunnel: public TunnelBase
|
||||
{
|
||||
class TransitTunnel: public TunnelBase
|
||||
{
|
||||
public:
|
||||
|
||||
TransitTunnel (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey);
|
||||
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey);
|
||||
|
||||
virtual size_t GetNumTransmittedBytes () const { return 0; };
|
||||
|
||||
// implements TunnelBase
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
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:
|
||||
|
||||
|
||||
i2p::crypto::TunnelEncryption m_Encryption;
|
||||
};
|
||||
};
|
||||
|
||||
class TransitTunnelParticipant: public TransitTunnel
|
||||
{
|
||||
public:
|
||||
|
||||
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):
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||
layerKey, ivKey), m_NumTransmittedBytes (0) {};
|
||||
~TransitTunnelParticipant ();
|
||||
|
||||
@ -53,51 +53,51 @@ namespace tunnel
|
||||
|
||||
size_t m_NumTransmittedBytes;
|
||||
std::vector<std::shared_ptr<i2p::I2NPMessage> > m_TunnelDataMsgs;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class TransitTunnelGateway: public TransitTunnel
|
||||
{
|
||||
public:
|
||||
|
||||
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):
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID,
|
||||
layerKey, ivKey), m_Gateway(this) {};
|
||||
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void FlushTunnelDataMsgs ();
|
||||
size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_SendMutex;
|
||||
TunnelGateway m_Gateway;
|
||||
};
|
||||
};
|
||||
|
||||
class TransitTunnelEndpoint: public TransitTunnel
|
||||
{
|
||||
public:
|
||||
|
||||
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):
|
||||
TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey),
|
||||
m_Endpoint (false) {}; // transit endpoint is always outbound
|
||||
|
||||
void Cleanup () { m_Endpoint.Cleanup (); }
|
||||
|
||||
|
||||
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
||||
size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
TunnelEndpoint m_Endpoint;
|
||||
};
|
||||
|
||||
|
||||
std::shared_ptr<TransitTunnel> CreateTransitTunnel (uint32_t receiveTunnelID,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey,
|
||||
const uint8_t * nextIdent, uint32_t nextTunnelID,
|
||||
const uint8_t * layerKey,const uint8_t * ivKey,
|
||||
bool isGateway, bool isEndpoint);
|
||||
}
|
||||
}
|
||||
|
@ -20,42 +20,42 @@ namespace transport
|
||||
public:
|
||||
|
||||
SignedData () {}
|
||||
SignedData (const SignedData& other)
|
||||
SignedData (const SignedData& other)
|
||||
{
|
||||
m_Stream << other.m_Stream.rdbuf ();
|
||||
}
|
||||
void Insert (const uint8_t * buf, size_t len)
|
||||
{
|
||||
m_Stream.write ((char *)buf, len);
|
||||
}
|
||||
}
|
||||
void Insert (const uint8_t * buf, size_t len)
|
||||
{
|
||||
m_Stream.write ((char *)buf, len);
|
||||
}
|
||||
|
||||
template<typename 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
|
||||
{
|
||||
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
|
||||
{
|
||||
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:
|
||||
|
||||
|
||||
std::stringstream m_Stream;
|
||||
};
|
||||
};
|
||||
|
||||
class TransportSession
|
||||
{
|
||||
public:
|
||||
|
||||
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),
|
||||
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_LastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ())
|
||||
{
|
||||
if (router)
|
||||
@ -66,30 +66,30 @@ namespace transport
|
||||
virtual void Done () = 0;
|
||||
|
||||
std::string GetIdentHashBase64() const { return m_RemoteIdentity ? m_RemoteIdentity->GetIdentHash().ToBase64() : ""; }
|
||||
|
||||
|
||||
std::shared_ptr<const i2p::data::IdentityEx> GetRemoteIdentity () { return m_RemoteIdentity; };
|
||||
void SetRemoteIdentity (std::shared_ptr<const i2p::data::IdentityEx> ident) { m_RemoteIdentity = ident; };
|
||||
|
||||
|
||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
bool IsOutgoing () const { return m_IsOutgoing; };
|
||||
|
||||
|
||||
int GetTerminationTimeout () const { return m_TerminationTimeout; };
|
||||
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
|
||||
bool IsTerminationTimeoutExpired (uint64_t ts) const
|
||||
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
|
||||
void SetTerminationTimeout (int terminationTimeout) { m_TerminationTimeout = terminationTimeout; };
|
||||
bool IsTerminationTimeoutExpired (uint64_t ts) const
|
||||
{ return ts >= m_LastActivityTimestamp + GetTerminationTimeout (); };
|
||||
|
||||
virtual void SendI2NPMessages (const std::vector<std::shared_ptr<I2NPMessage> >& msgs) = 0;
|
||||
|
||||
|
||||
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
|
||||
size_t m_NumSentBytes, m_NumReceivedBytes;
|
||||
bool m_IsOutgoing;
|
||||
int m_TerminationTimeout;
|
||||
uint64_t m_LastActivityTimestamp;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "I2PEndian.h"
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <vector>
|
||||
#include "Crypto.h"
|
||||
#include "RouterContext.h"
|
||||
#include "Log.h"
|
||||
@ -20,8 +20,8 @@
|
||||
namespace i2p
|
||||
{
|
||||
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 ()),
|
||||
m_Config (config), m_Pool (nullptr), m_State (eTunnelStatePending), m_IsRecreated (false),
|
||||
m_Latency (0)
|
||||
@ -38,7 +38,7 @@ namespace tunnel
|
||||
std::string peers = i2p::context.GetIdentity()->GetIdentHash().ToBase64();
|
||||
#endif
|
||||
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 ();
|
||||
*msg->GetPayload () = numRecords;
|
||||
msg->len += numRecords*TUNNEL_BUILD_RECORD_SIZE + 1;
|
||||
@ -48,20 +48,20 @@ namespace tunnel
|
||||
std::random_shuffle (recordIndicies.begin(), recordIndicies.end());
|
||||
|
||||
// create real records
|
||||
uint8_t * records = msg->GetPayload () + 1;
|
||||
uint8_t * records = msg->GetPayload () + 1;
|
||||
TunnelHopConfig * hop = m_Config->GetFirstHop ();
|
||||
int i = 0;
|
||||
BN_CTX * ctx = BN_CTX_new ();
|
||||
while (hop)
|
||||
{
|
||||
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);
|
||||
else
|
||||
msgID = replyMsgID;
|
||||
int idx = recordIndicies[i];
|
||||
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID, ctx);
|
||||
hop->recordIndex = idx;
|
||||
hop->CreateBuildRequestRecord (records + idx*TUNNEL_BUILD_RECORD_SIZE, msgID, ctx);
|
||||
hop->recordIndex = idx;
|
||||
i++;
|
||||
#ifdef WITH_EVENTS
|
||||
peers += ":" + hop->ident->GetIdentHash().ToBase64();
|
||||
@ -76,7 +76,7 @@ namespace tunnel
|
||||
for (int i = numHops; i < numRecords; 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
|
||||
@ -110,7 +110,7 @@ namespace tunnel
|
||||
LogPrint (eLogDebug, "Tunnel: TunnelBuildResponse ", (int)msg[0], " records.");
|
||||
|
||||
i2p::crypto::CBCDecryption decryption;
|
||||
TunnelHopConfig * hop = m_Config->GetLastHop ();
|
||||
TunnelHopConfig * hop = m_Config->GetLastHop ();
|
||||
while (hop)
|
||||
{
|
||||
decryption.SetKey (hop->replyKey);
|
||||
@ -142,12 +142,12 @@ namespace tunnel
|
||||
auto profile = i2p::data::netdb.FindRouterProfile (hop->ident->GetIdentHash ());
|
||||
if (profile)
|
||||
profile->TunnelBuildResponse (ret);
|
||||
if (ret)
|
||||
if (ret)
|
||||
// if any of participants declined the tunnel is not established
|
||||
established = false;
|
||||
established = false;
|
||||
hop = hop->next;
|
||||
}
|
||||
if (established)
|
||||
if (established)
|
||||
{
|
||||
// create tunnel decryptions from layer and iv keys in reverse order
|
||||
hop = m_Config->GetLastHop ();
|
||||
@ -170,7 +170,7 @@ namespace tunnel
|
||||
auto latency = GetMeanLatency();
|
||||
return latency >= lower && latency <= upper;
|
||||
}
|
||||
|
||||
|
||||
void Tunnel::EncryptTunnelMsg (std::shared_ptr<const I2NPMessage> in, std::shared_ptr<I2NPMessage> out)
|
||||
{
|
||||
const uint8_t * inPayload = in->GetPayload () + 4;
|
||||
@ -178,7 +178,7 @@ namespace tunnel
|
||||
for (auto& it: m_Hops)
|
||||
{
|
||||
it->decryption.Decrypt (inPayload, outPayload);
|
||||
inPayload = outPayload;
|
||||
inPayload = outPayload;
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,11 +210,11 @@ namespace tunnel
|
||||
EmitTunnelEvent("tunnel.state", this, state);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
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++)
|
||||
{
|
||||
s << " ⇒ ";
|
||||
@ -354,7 +354,7 @@ namespace tunnel
|
||||
{
|
||||
return GetPendingTunnel (replyMsgID, m_PendingInboundTunnels);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<OutboundTunnel> Tunnels::GetPendingOutboundTunnel (uint32_t replyMsgID)
|
||||
{
|
||||
return GetPendingTunnel (replyMsgID, m_PendingOutboundTunnels);
|
||||
@ -374,7 +374,7 @@ namespace tunnel
|
||||
|
||||
std::shared_ptr<InboundTunnel> Tunnels::GetNextInboundTunnel ()
|
||||
{
|
||||
std::shared_ptr<InboundTunnel> tunnel;
|
||||
std::shared_ptr<InboundTunnel> tunnel;
|
||||
size_t minReceived = 0;
|
||||
for (const auto& it : m_InboundTunnels)
|
||||
{
|
||||
@ -405,7 +405,7 @@ namespace 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)
|
||||
{
|
||||
auto pool = std::make_shared<TunnelPool> (numInboundHops, numOutboundHops, numInboundTunnels, numOutboundTunnels);
|
||||
@ -434,7 +434,7 @@ namespace tunnel
|
||||
pool->DetachTunnels ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Tunnels::AddTransitTunnel (std::shared_ptr<TransitTunnel> tunnel)
|
||||
{
|
||||
if (m_Tunnels.emplace (tunnel->GetTunnelID (), tunnel).second)
|
||||
@ -455,7 +455,7 @@ namespace tunnel
|
||||
m_Queue.WakeUp ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = 0;
|
||||
}
|
||||
@ -484,11 +484,11 @@ namespace tunnel
|
||||
case eI2NPTunnelData:
|
||||
case eI2NPTunnelGateway:
|
||||
{
|
||||
tunnelID = bufbe32toh (msg->GetPayload ());
|
||||
tunnelID = bufbe32toh (msg->GetPayload ());
|
||||
if (tunnelID == prevTunnelID)
|
||||
tunnel = prevTunnel;
|
||||
else if (prevTunnel)
|
||||
prevTunnel->FlushTunnelDataMsgs ();
|
||||
prevTunnel->FlushTunnelDataMsgs ();
|
||||
|
||||
if (!tunnel)
|
||||
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);
|
||||
|
||||
if (IsRouterInfoMsg (msg) || typeID == eI2NPDatabaseSearchReply)
|
||||
// transit DatabaseStore my contain new/updated RI
|
||||
// transit DatabaseStore my contain new/updated RI
|
||||
// or DatabaseSearchReply with new routers
|
||||
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg));
|
||||
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg));
|
||||
tunnel->SendTunnelDataMsg (msg);
|
||||
}
|
||||
|
||||
@ -593,7 +593,7 @@ namespace tunnel
|
||||
auto pool = tunnel->GetTunnelPool();
|
||||
switch (tunnel->GetState ())
|
||||
{
|
||||
case eTunnelStatePending:
|
||||
case eTunnelStatePending:
|
||||
if (ts > tunnel->GetCreationTime () + TUNNEL_CREATION_TIMEOUT)
|
||||
{
|
||||
LogPrint (eLogDebug, "Tunnel: pending build request ", it->first, " timeout, deleted");
|
||||
@ -632,7 +632,7 @@ namespace tunnel
|
||||
#endif
|
||||
// for i2lua
|
||||
if(pool) pool->OnTunnelBuildResult(tunnel, eBuildResultRejected);
|
||||
|
||||
|
||||
it = pendingTunnels.erase (it);
|
||||
m_NumFailedTunnelCreations++;
|
||||
break;
|
||||
@ -664,7 +664,7 @@ namespace tunnel
|
||||
// we don't have outbound tunnels in m_Tunnels
|
||||
it = m_OutboundTunnels.erase (it);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
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
|
||||
auto inboundTunnel = GetNextInboundTunnel ();
|
||||
@ -715,7 +715,7 @@ namespace tunnel
|
||||
m_Tunnels.erase (tunnel->GetTunnelID ());
|
||||
it = m_InboundTunnels.erase (it);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (tunnel->IsEstablished ())
|
||||
{
|
||||
@ -748,13 +748,13 @@ namespace tunnel
|
||||
int obLen; i2p::config::GetOption("exploratory.outbound.length", obLen);
|
||||
int ibNum; i2p::config::GetOption("exploratory.inbound.quantity", ibNum);
|
||||
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 ());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3)
|
||||
if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3)
|
||||
{
|
||||
// trying to create one more inbound tunnel
|
||||
auto router = i2p::transport::transports.RoutesRestricted() ?
|
||||
@ -783,7 +783,7 @@ namespace tunnel
|
||||
m_Tunnels.erase (tunnel->GetTunnelID ());
|
||||
it = m_TransitTunnels.erase (it);
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
tunnel->Cleanup ();
|
||||
it++;
|
||||
@ -820,14 +820,14 @@ namespace tunnel
|
||||
auto newTunnel = std::make_shared<TTunnel> (config);
|
||||
uint32_t replyMsgID;
|
||||
RAND_bytes ((uint8_t *)&replyMsgID, 4);
|
||||
AddPendingTunnel (replyMsgID, newTunnel);
|
||||
AddPendingTunnel (replyMsgID, newTunnel);
|
||||
newTunnel->Build (replyMsgID, outboundTunnel);
|
||||
return newTunnel;
|
||||
}
|
||||
|
||||
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);
|
||||
else
|
||||
return CreateZeroHopsInboundTunnel ();
|
||||
@ -843,12 +843,12 @@ namespace 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)
|
||||
{
|
||||
m_PendingOutboundTunnels[replyMsgID] = tunnel;
|
||||
m_PendingOutboundTunnels[replyMsgID] = tunnel;
|
||||
}
|
||||
|
||||
void Tunnels::AddOutboundTunnel (std::shared_ptr<OutboundTunnel> newTunnel)
|
||||
@ -872,7 +872,7 @@ namespace tunnel
|
||||
{
|
||||
// build symmetric outbound tunnel
|
||||
CreateTunnel<OutboundTunnel> (std::make_shared<TunnelConfig>(newTunnel->GetInvertedPeers (),
|
||||
newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()),
|
||||
newTunnel->GetNextTunnelID (), newTunnel->GetNextIdentHash ()),
|
||||
GetNextOutboundTunnel ());
|
||||
}
|
||||
else
|
||||
|
112
libi2pd/Tunnel.h
112
libi2pd/Tunnel.h
@ -36,7 +36,7 @@ namespace tunnel
|
||||
(void) t;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template<typename TunnelT, typename T>
|
||||
static void EmitTunnelEvent(const std::string & ev, TunnelT * t, const T & val)
|
||||
{
|
||||
@ -46,7 +46,7 @@ namespace tunnel
|
||||
(void) ev;
|
||||
(void) t;
|
||||
(void) val;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TunnelT>
|
||||
@ -58,13 +58,13 @@ namespace tunnel
|
||||
(void) ev;
|
||||
(void) t;
|
||||
(void) val;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
||||
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
|
||||
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
|
||||
|
||||
const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes
|
||||
const int TUNNEL_EXPIRATION_THRESHOLD = 60; // 1 minute
|
||||
const int TUNNEL_RECREATION_THRESHOLD = 90; // 1.5 minutes
|
||||
const int TUNNEL_CREATION_TIMEOUT = 30; // 30 seconds
|
||||
const int STANDARD_NUM_RECORDS = 5; // in VariableTunnelBuild message
|
||||
|
||||
@ -77,8 +77,8 @@ namespace tunnel
|
||||
eTunnelStateTestFailed,
|
||||
eTunnelStateFailed,
|
||||
eTunnelStateExpiring
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class OutboundTunnel;
|
||||
class InboundTunnel;
|
||||
class Tunnel: public TunnelBase
|
||||
@ -87,18 +87,18 @@ namespace tunnel
|
||||
{
|
||||
std::shared_ptr<const i2p::data::IdentityEx> ident;
|
||||
i2p::crypto::TunnelDecryption decryption;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Tunnel (std::shared_ptr<const TunnelConfig> config);
|
||||
~Tunnel ();
|
||||
|
||||
void Build (uint32_t replyMsgID, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
|
||||
|
||||
|
||||
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> > GetInvertedPeers () const;
|
||||
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetPeers () const;
|
||||
std::vector<std::shared_ptr<const i2p::data::IdentityEx> > GetInvertedPeers () const;
|
||||
TunnelState GetState () const { return m_State; };
|
||||
void SetState (TunnelState state);
|
||||
bool IsEstablished () const { return m_State == eTunnelStateEstablished; };
|
||||
@ -106,17 +106,17 @@ namespace tunnel
|
||||
bool IsRecreated () const { return m_IsRecreated; };
|
||||
void SetIsRecreated () { m_IsRecreated = true; };
|
||||
virtual bool IsInbound() const = 0;
|
||||
|
||||
|
||||
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);
|
||||
|
||||
virtual void Print (std::stringstream&) const {};
|
||||
|
||||
|
||||
// implements TunnelBase
|
||||
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 */
|
||||
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; }
|
||||
/** @brief return true if this tunnel's latency fits in range [lowerbound, upperbound] */
|
||||
bool LatencyFitsRange(uint64_t lowerbound, uint64_t upperbound) const;
|
||||
|
||||
|
||||
bool LatencyIsKnown() const { return m_Latency > 0; }
|
||||
protected:
|
||||
|
||||
void PrintHops (std::stringstream& s) const;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::shared_ptr<const TunnelConfig> m_Config;
|
||||
@ -138,30 +138,30 @@ namespace tunnel
|
||||
TunnelState m_State;
|
||||
bool m_IsRecreated;
|
||||
uint64_t m_Latency; // in milliseconds
|
||||
};
|
||||
};
|
||||
|
||||
class OutboundTunnel: public Tunnel
|
||||
class OutboundTunnel: public Tunnel
|
||||
{
|
||||
public:
|
||||
|
||||
OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
|
||||
OutboundTunnel (std::shared_ptr<const TunnelConfig> config):
|
||||
Tunnel (config), m_Gateway (this), m_EndpointIdentHash (config->GetLastIdentHash ()) {};
|
||||
|
||||
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
|
||||
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 (); };
|
||||
void Print (std::stringstream& s) const;
|
||||
|
||||
|
||||
// implements TunnelBase
|
||||
void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg);
|
||||
|
||||
bool IsInbound() const { return false; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::mutex m_SendMutex;
|
||||
TunnelGateway m_Gateway;
|
||||
TunnelGateway m_Gateway;
|
||||
i2p::data::IdentHash m_EndpointIdentHash;
|
||||
};
|
||||
|
||||
@ -176,27 +176,27 @@ namespace tunnel
|
||||
bool IsInbound() const { return true; }
|
||||
|
||||
// override TunnelBase
|
||||
void Cleanup () { m_Endpoint.Cleanup (); };
|
||||
void Cleanup () { m_Endpoint.Cleanup (); };
|
||||
|
||||
private:
|
||||
|
||||
TunnelEndpoint m_Endpoint;
|
||||
};
|
||||
|
||||
TunnelEndpoint m_Endpoint;
|
||||
};
|
||||
|
||||
class ZeroHopsInboundTunnel: public InboundTunnel
|
||||
{
|
||||
public:
|
||||
|
||||
ZeroHopsInboundTunnel ();
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg);
|
||||
void Print (std::stringstream& s) const;
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
size_t m_NumReceivedBytes;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
class ZeroHopsOutboundTunnel: public OutboundTunnel
|
||||
{
|
||||
public:
|
||||
@ -205,23 +205,23 @@ namespace tunnel
|
||||
void SendTunnelDataMsg (const std::vector<TunnelMessageBlock>& msgs);
|
||||
void Print (std::stringstream& s) const;
|
||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
size_t m_NumSentBytes;
|
||||
};
|
||||
};
|
||||
|
||||
class Tunnels
|
||||
{
|
||||
{
|
||||
public:
|
||||
|
||||
Tunnels ();
|
||||
~Tunnels ();
|
||||
void Start ();
|
||||
void Stop ();
|
||||
|
||||
std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID);
|
||||
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
|
||||
void Stop ();
|
||||
|
||||
std::shared_ptr<InboundTunnel> GetPendingInboundTunnel (uint32_t replyMsgID);
|
||||
std::shared_ptr<OutboundTunnel> GetPendingOutboundTunnel (uint32_t replyMsgID);
|
||||
std::shared_ptr<InboundTunnel> GetNextInboundTunnel ();
|
||||
std::shared_ptr<OutboundTunnel> GetNextOutboundTunnel ();
|
||||
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 AddPendingTunnel (uint32_t replyMsgID, std::shared_ptr<InboundTunnel> 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);
|
||||
void DeleteTunnelPool (std::shared_ptr<TunnelPool> pool);
|
||||
void StopTunnelPool (std::shared_ptr<TunnelPool> pool);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
template<class TTunnel>
|
||||
std::shared_ptr<TTunnel> CreateTunnel (std::shared_ptr<TunnelConfig> config, std::shared_ptr<OutboundTunnel> outboundTunnel = nullptr);
|
||||
|
||||
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 Run ();
|
||||
void Run ();
|
||||
void ManageTunnels ();
|
||||
void ManageOutboundTunnels ();
|
||||
void ManageInboundTunnels ();
|
||||
@ -260,14 +260,14 @@ namespace tunnel
|
||||
template<class PendingTunnels>
|
||||
void ManagePendingTunnels (PendingTunnels& pendingTunnels);
|
||||
void ManageTunnelPools ();
|
||||
|
||||
|
||||
std::shared_ptr<ZeroHopsInboundTunnel> CreateZeroHopsInboundTunnel ();
|
||||
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel ();
|
||||
std::shared_ptr<ZeroHopsOutboundTunnel> CreateZeroHopsOutboundTunnel ();
|
||||
|
||||
private:
|
||||
|
||||
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<OutboundTunnel> > m_PendingOutboundTunnels; // by replyMsgID
|
||||
std::list<std::shared_ptr<InboundTunnel> > m_InboundTunnels;
|
||||
@ -292,17 +292,17 @@ namespace tunnel
|
||||
size_t CountTransitTunnels() const;
|
||||
size_t CountInboundTunnels() const;
|
||||
size_t CountOutboundTunnels() const;
|
||||
|
||||
|
||||
int GetQueueSize () { return m_Queue.GetSize (); };
|
||||
int GetTunnelCreationSuccessRate () const // in percents
|
||||
{
|
||||
{
|
||||
int totalNum = m_NumSuccesiveTunnelCreations + m_NumFailedTunnelCreations;
|
||||
return totalNum ? m_NumSuccesiveTunnelCreations*100/totalNum : 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
extern Tunnels tunnels;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -14,17 +14,17 @@ namespace tunnel
|
||||
const size_t TUNNEL_DATA_MSG_SIZE = 1028;
|
||||
const size_t TUNNEL_DATA_ENCRYPTED_SIZE = 1008;
|
||||
const size_t TUNNEL_DATA_MAX_PAYLOAD_SIZE = 1003;
|
||||
|
||||
enum TunnelDeliveryType
|
||||
{
|
||||
eDeliveryTypeLocal = 0,
|
||||
|
||||
enum TunnelDeliveryType
|
||||
{
|
||||
eDeliveryTypeLocal = 0,
|
||||
eDeliveryTypeTunnel = 1,
|
||||
eDeliveryTypeRouter = 2
|
||||
};
|
||||
};
|
||||
struct TunnelMessageBlock
|
||||
{
|
||||
TunnelDeliveryType deliveryType;
|
||||
i2p::data::IdentHash hash;
|
||||
i2p::data::IdentHash hash;
|
||||
uint32_t tunnelID;
|
||||
std::shared_ptr<I2NPMessage> data;
|
||||
};
|
||||
@ -33,12 +33,12 @@ namespace tunnel
|
||||
{
|
||||
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_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {};
|
||||
virtual ~TunnelBase () {};
|
||||
virtual void Cleanup () {};
|
||||
|
||||
|
||||
virtual void HandleTunnelDataMsg (std::shared_ptr<const i2p::I2NPMessage> tunnelMsg) = 0;
|
||||
virtual void SendTunnelDataMsg (std::shared_ptr<i2p::I2NPMessage> msg) = 0;
|
||||
virtual void FlushTunnelDataMsgs () {};
|
||||
@ -49,24 +49,24 @@ namespace tunnel
|
||||
|
||||
uint32_t GetCreationTime () const { return m_CreationTime; };
|
||||
void SetCreationTime (uint32_t t) { m_CreationTime = t; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_TunnelID, m_NextTunnelID;
|
||||
i2p::data::IdentHash m_NextIdent;
|
||||
uint32_t m_CreationTime; // seconds since epoch
|
||||
};
|
||||
};
|
||||
|
||||
struct TunnelCreationTimeCmp
|
||||
{
|
||||
bool operator() (std::shared_ptr<const TunnelBase> t1, std::shared_ptr<const TunnelBase> t2) const
|
||||
{
|
||||
{
|
||||
if (t1->GetCreationTime () != t2->GetCreationTime ())
|
||||
return t1->GetCreationTime () > t2->GetCreationTime ();
|
||||
return t1->GetCreationTime () > t2->GetCreationTime ();
|
||||
else
|
||||
return t1 < t2;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,11 @@ namespace tunnel
|
||||
uint8_t ivKey[32];
|
||||
uint8_t replyKey[32];
|
||||
uint8_t replyIV[16];
|
||||
bool isGateway, isEndpoint;
|
||||
|
||||
bool isGateway, isEndpoint;
|
||||
|
||||
TunnelHopConfig * next, * prev;
|
||||
int recordIndex; // record # in tunnel build message
|
||||
|
||||
|
||||
TunnelHopConfig (std::shared_ptr<const i2p::data::IdentityEx> r)
|
||||
{
|
||||
RAND_bytes (layerKey, 32);
|
||||
@ -37,20 +37,20 @@ namespace tunnel
|
||||
RAND_bytes ((uint8_t *)&tunnelID, 4);
|
||||
isGateway = true;
|
||||
isEndpoint = true;
|
||||
ident = r;
|
||||
//nextRouter = nullptr;
|
||||
ident = r;
|
||||
//nextRouter = nullptr;
|
||||
nextTunnelID = 0;
|
||||
|
||||
next = nullptr;
|
||||
prev = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SetNextIdent (const i2p::data::IdentHash& ident)
|
||||
{
|
||||
nextIdent = ident;
|
||||
isEndpoint = false;
|
||||
RAND_bytes ((uint8_t *)&nextTunnelID, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void SetReplyHop (uint32_t replyTunnelID, const i2p::data::IdentHash& replyIdent)
|
||||
{
|
||||
@ -58,35 +58,35 @@ namespace tunnel
|
||||
nextTunnelID = replyTunnelID;
|
||||
isEndpoint = true;
|
||||
}
|
||||
|
||||
|
||||
void SetNext (TunnelHopConfig * n)
|
||||
{
|
||||
next = n;
|
||||
if (next)
|
||||
{
|
||||
{
|
||||
next->prev = this;
|
||||
next->isGateway = false;
|
||||
isEndpoint = false;
|
||||
nextIdent = next->ident->GetIdentHash ();
|
||||
nextTunnelID = next->tunnelID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetPrev (TunnelHopConfig * p)
|
||||
{
|
||||
prev = p;
|
||||
if (prev)
|
||||
{
|
||||
if (prev)
|
||||
{
|
||||
prev->next = this;
|
||||
prev->isEndpoint = false;
|
||||
isGateway = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx) const
|
||||
{
|
||||
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);
|
||||
htobe32buf (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET, nextTunnelID);
|
||||
memcpy (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, nextIdent, 32);
|
||||
@ -98,44 +98,44 @@ namespace tunnel
|
||||
if (isGateway) flag |= 0x80;
|
||||
if (isEndpoint) flag |= 0x40;
|
||||
clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] = flag;
|
||||
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_REQUEST_TIME_OFFSET, i2p::util::GetHoursSinceEpoch ());
|
||||
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);
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class TunnelConfig
|
||||
{
|
||||
public:
|
||||
|
||||
public:
|
||||
|
||||
TunnelConfig (std::vector<std::shared_ptr<const i2p::data::IdentityEx> > peers) // inbound
|
||||
{
|
||||
CreatePeers (peers);
|
||||
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
|
||||
{
|
||||
CreatePeers (peers);
|
||||
m_FirstHop->isGateway = false;
|
||||
m_LastHop->SetReplyHop (replyTunnelID, replyIdent);
|
||||
}
|
||||
|
||||
|
||||
~TunnelConfig ()
|
||||
{
|
||||
TunnelHopConfig * hop = m_FirstHop;
|
||||
|
||||
|
||||
while (hop)
|
||||
{
|
||||
auto tmp = hop;
|
||||
hop = hop->next;
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TunnelHopConfig * GetFirstHop () const
|
||||
{
|
||||
return m_FirstHop;
|
||||
@ -149,63 +149,63 @@ namespace tunnel
|
||||
int GetNumHops () const
|
||||
{
|
||||
int num = 0;
|
||||
TunnelHopConfig * hop = m_FirstHop;
|
||||
TunnelHopConfig * hop = m_FirstHop;
|
||||
while (hop)
|
||||
{
|
||||
num++;
|
||||
hop = hop->next;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
bool IsEmpty () const
|
||||
{
|
||||
return !m_FirstHop;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool IsInbound () const { return m_FirstHop->isGateway; }
|
||||
|
||||
virtual uint32_t GetTunnelID () const
|
||||
{
|
||||
virtual uint32_t GetTunnelID () const
|
||||
{
|
||||
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;
|
||||
return m_FirstHop->tunnelID;
|
||||
return m_FirstHop->tunnelID;
|
||||
}
|
||||
|
||||
virtual const i2p::data::IdentHash& GetNextIdentHash () const
|
||||
{
|
||||
return m_FirstHop->ident->GetIdentHash ();
|
||||
}
|
||||
virtual const i2p::data::IdentHash& GetNextIdentHash () const
|
||||
{
|
||||
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> > peers;
|
||||
TunnelHopConfig * hop = m_FirstHop;
|
||||
TunnelHopConfig * hop = m_FirstHop;
|
||||
while (hop)
|
||||
{
|
||||
peers.push_back (hop->ident);
|
||||
hop = hop->next;
|
||||
}
|
||||
}
|
||||
return peers;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// this constructor can't be called from outside
|
||||
TunnelConfig (): m_FirstHop (nullptr), m_LastHop (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
template<class Peers>
|
||||
@ -217,13 +217,13 @@ namespace tunnel
|
||||
auto hop = new TunnelHopConfig (it);
|
||||
if (prev)
|
||||
prev->SetNext (hop);
|
||||
else
|
||||
else
|
||||
m_FirstHop = hop;
|
||||
prev = hop;
|
||||
}
|
||||
}
|
||||
m_LastHop = prev;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
TunnelHopConfig * m_FirstHop, * m_LastHop;
|
||||
@ -235,7 +235,7 @@ namespace tunnel
|
||||
|
||||
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 GetNextTunnelID () const { return m_TunnelID; };
|
||||
const i2p::data::IdentHash& GetNextIdentHash () const { return i2p::context.GetIdentHash (); };
|
||||
@ -243,10 +243,10 @@ namespace tunnel
|
||||
|
||||
|
||||
private:
|
||||
|
||||
uint32_t m_TunnelID;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t m_TunnelID;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -15,16 +15,16 @@ namespace tunnel
|
||||
{
|
||||
TunnelEndpoint::~TunnelEndpoint ()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelEndpoint::HandleDecryptedTunnelDataMsg (std::shared_ptr<I2NPMessage> msg)
|
||||
{
|
||||
m_NumReceivedBytes += TUNNEL_DATA_MSG_SIZE;
|
||||
|
||||
|
||||
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
|
||||
if (zero)
|
||||
{
|
||||
{
|
||||
uint8_t * fragment = zero + 1;
|
||||
// verify checksum
|
||||
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");
|
||||
return;
|
||||
}
|
||||
}
|
||||
// process fragments
|
||||
while (fragment < decrypted + TUNNEL_DATA_ENCRYPTED_SIZE)
|
||||
{
|
||||
uint8_t flag = fragment[0];
|
||||
fragment++;
|
||||
|
||||
bool isFollowOnFragment = flag & 0x80, isLastFragment = true;
|
||||
|
||||
bool isFollowOnFragment = flag & 0x80, isLastFragment = true;
|
||||
uint32_t msgID = 0;
|
||||
int fragmentNum = 0;
|
||||
TunnelMessageBlockEx m;
|
||||
if (!isFollowOnFragment)
|
||||
{
|
||||
{
|
||||
// first fragment
|
||||
|
||||
|
||||
m.deliveryType = (TunnelDeliveryType)((flag >> 5) & 0x03);
|
||||
switch (m.deliveryType)
|
||||
{
|
||||
@ -61,31 +61,31 @@ namespace tunnel
|
||||
fragment += 32; // hash
|
||||
break;
|
||||
case eDeliveryTypeRouter: // 2
|
||||
m.hash = i2p::data::IdentHash (fragment);
|
||||
m.hash = i2p::data::IdentHash (fragment);
|
||||
fragment += 32; // to hash
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
bool isFragmented = flag & 0x08;
|
||||
if (isFragmented)
|
||||
{
|
||||
// Message ID
|
||||
msgID = bufbe32toh (fragment);
|
||||
msgID = bufbe32toh (fragment);
|
||||
fragment += 4;
|
||||
isLastFragment = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// follow on
|
||||
msgID = bufbe32toh (fragment); // MessageID
|
||||
fragment += 4;
|
||||
msgID = bufbe32toh (fragment); // MessageID
|
||||
fragment += 4;
|
||||
fragmentNum = (flag >> 1) & 0x3F; // 6 bits
|
||||
isLastFragment = flag & 0x01;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
uint16_t size = bufbe16toh (fragment);
|
||||
fragment += 2;
|
||||
|
||||
@ -106,7 +106,7 @@ namespace tunnel
|
||||
}
|
||||
else
|
||||
m.data = msg;
|
||||
|
||||
|
||||
if (!isFollowOnFragment && isLastFragment)
|
||||
HandleNextMessage (m);
|
||||
else
|
||||
@ -127,18 +127,18 @@ namespace tunnel
|
||||
{
|
||||
m.nextFragmentNum = fragmentNum;
|
||||
HandleFollowOnFragment (msgID, isLastFragment, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else
|
||||
LogPrint (eLogError, "TunnelMessage: Message is fragmented, but msgID is not presented");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fragment += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "TunnelMessage: zero not found");
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelEndpoint::HandleFollowOnFragment (uint32_t msgID, bool isLastFragment, const TunnelMessageBlockEx& m)
|
||||
{
|
||||
@ -151,7 +151,7 @@ namespace tunnel
|
||||
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 > msg.data->maxLen)
|
||||
{
|
||||
// LogPrint (eLogWarning, "TunnelMessage: I2NP message size ", msg.data->maxLen, " is not enough");
|
||||
@ -164,14 +164,14 @@ namespace tunnel
|
||||
if (isLastFragment)
|
||||
{
|
||||
// message complete
|
||||
HandleNextMessage (msg);
|
||||
m_IncompleteMessages.erase (it);
|
||||
}
|
||||
HandleNextMessage (msg);
|
||||
m_IncompleteMessages.erase (it);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
msg.nextFragmentNum++;
|
||||
HandleOutOfSequenceFragments (msgID, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -180,31 +180,31 @@ namespace tunnel
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
LogPrint (eLogWarning, "TunnelMessage: Unexpected fragment ", (int)m.nextFragmentNum, " instead ", (int)msg.nextFragmentNum, " of message ", msgID, ", saved");
|
||||
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
LogPrint (eLogWarning, "TunnelMessage: First fragment of message ", msgID, " not found, saved");
|
||||
AddOutOfSequenceFragment (msgID, m.nextFragmentNum, isLastFragment, m.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)
|
||||
LogPrint (eLogInfo, "TunnelMessage: duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID);
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelEndpoint::HandleOutOfSequenceFragments (uint32_t msgID, TunnelMessageBlockEx& msg)
|
||||
{
|
||||
while (ConcatNextOutOfSequenceFragment (msgID, msg))
|
||||
while (ConcatNextOutOfSequenceFragment (msgID, msg))
|
||||
{
|
||||
if (!msg.nextFragmentNum) // message complete
|
||||
{
|
||||
HandleNextMessage (msg);
|
||||
HandleNextMessage (msg);
|
||||
m_IncompleteMessages.erase (msgID);
|
||||
break;
|
||||
}
|
||||
@ -215,7 +215,7 @@ namespace tunnel
|
||||
{
|
||||
auto it = m_OutOfSequenceFragments.find ({msgID, msg.nextFragmentNum});
|
||||
if (it != m_OutOfSequenceFragments.end ())
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found");
|
||||
size_t size = it->second.data->GetLength ();
|
||||
if (msg.data->len + size > msg.data->maxLen)
|
||||
@ -233,21 +233,21 @@ namespace tunnel
|
||||
else
|
||||
msg.nextFragmentNum++;
|
||||
m_OutOfSequenceFragments.erase (it);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelEndpoint::HandleNextMessage (const TunnelMessageBlock& msg)
|
||||
{
|
||||
if (!m_IsInbound && msg.data->IsExpired ())
|
||||
{
|
||||
LogPrint (eLogInfo, "TunnelMessage: message expired");
|
||||
return;
|
||||
}
|
||||
}
|
||||
uint8_t typeID = msg.data->GetTypeID ();
|
||||
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) &&
|
||||
!m_IsInbound && msg.deliveryType != eDeliveryTypeLocal)
|
||||
i2p::data::netdb.PostI2NPMsg (CopyI2NPMessage (msg.data));
|
||||
@ -263,15 +263,15 @@ namespace tunnel
|
||||
else
|
||||
LogPrint (eLogError, "TunnelMessage: Delivery type 'tunnel' arrived from an inbound tunnel, dropped");
|
||||
break;
|
||||
case eDeliveryTypeRouter:
|
||||
case eDeliveryTypeRouter:
|
||||
if (!m_IsInbound) // outbound transit tunnel
|
||||
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");
|
||||
break;
|
||||
default:
|
||||
LogPrint (eLogError, "TunnelMessage: Unknown delivery type ", (int)msg.deliveryType);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
void TunnelEndpoint::Cleanup ()
|
||||
@ -293,6 +293,6 @@ namespace tunnel
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,26 +12,26 @@ namespace i2p
|
||||
namespace tunnel
|
||||
{
|
||||
class TunnelEndpoint
|
||||
{
|
||||
{
|
||||
struct TunnelMessageBlockEx: public TunnelMessageBlock
|
||||
{
|
||||
uint64_t receiveTime; // milliseconds since epoch
|
||||
uint8_t nextFragmentNum;
|
||||
};
|
||||
};
|
||||
|
||||
struct Fragment
|
||||
{
|
||||
bool isLastFragment;
|
||||
std::shared_ptr<I2NPMessage> data;
|
||||
uint64_t receiveTime; // milliseconds since epoch
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
TunnelEndpoint (bool isInbound): m_IsInbound (isInbound), m_NumReceivedBytes (0) {};
|
||||
~TunnelEndpoint ();
|
||||
size_t GetNumReceivedBytes () const { return m_NumReceivedBytes; };
|
||||
void Cleanup ();
|
||||
void Cleanup ();
|
||||
|
||||
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);
|
||||
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<std::pair<uint32_t, uint8_t>, Fragment> m_OutOfSequenceFragments; // (msgID, fragment#)->fragment
|
||||
bool m_IsInbound;
|
||||
size_t m_NumReceivedBytes;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -10,8 +10,8 @@ namespace i2p
|
||||
{
|
||||
namespace tunnel
|
||||
{
|
||||
TunnelGatewayBuffer::TunnelGatewayBuffer ():
|
||||
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0)
|
||||
TunnelGatewayBuffer::TunnelGatewayBuffer ():
|
||||
m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0)
|
||||
{
|
||||
RAND_bytes (m_NonZeroRandomBuffer, TUNNEL_DATA_MAX_PAYLOAD_SIZE);
|
||||
for (size_t i = 0; i < TUNNEL_DATA_MAX_PAYLOAD_SIZE; i++)
|
||||
@ -21,31 +21,31 @@ namespace tunnel
|
||||
TunnelGatewayBuffer::~TunnelGatewayBuffer ()
|
||||
{
|
||||
ClearTunnelDataMsgs ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block)
|
||||
{
|
||||
bool messageCreated = false;
|
||||
if (!m_CurrentTunnelDataMsg)
|
||||
{
|
||||
{
|
||||
CreateCurrentTunnelDataMessage ();
|
||||
messageCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
// create delivery instructions
|
||||
uint8_t di[43]; // max delivery instruction length is 43 for tunnel
|
||||
size_t diLen = 1;// flag
|
||||
if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router
|
||||
{
|
||||
{
|
||||
if (block.deliveryType == eDeliveryTypeTunnel)
|
||||
{
|
||||
htobe32buf (di + diLen, block.tunnelID);
|
||||
diLen += 4; // tunnelID
|
||||
}
|
||||
|
||||
|
||||
memcpy (di + diLen, block.hash, 32);
|
||||
diLen += 32; //len
|
||||
}
|
||||
}
|
||||
di[0] = block.deliveryType << 5; // set delivery type
|
||||
|
||||
// create fragments
|
||||
@ -62,21 +62,21 @@ namespace tunnel
|
||||
m_RemainingSize -= diLen + msg->GetLength ();
|
||||
if (!m_RemainingSize)
|
||||
CompleteCurrentTunnelDataMessage ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!messageCreated) // check if we should complete previous message
|
||||
{
|
||||
{
|
||||
size_t numFollowOnFragments = fullMsgLen / TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||
// length of bytes don't fit full tunnel message
|
||||
// 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)
|
||||
{
|
||||
CompleteCurrentTunnelDataMessage ();
|
||||
CreateCurrentTunnelDataMessage ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (diLen + 6 <= m_RemainingSize)
|
||||
{
|
||||
// delivery instructions fit
|
||||
@ -97,16 +97,16 @@ namespace tunnel
|
||||
// follow on fragments
|
||||
int fragmentNumber = 1;
|
||||
while (size < msg->GetLength ())
|
||||
{
|
||||
{
|
||||
CreateCurrentTunnelDataMessage ();
|
||||
uint8_t * buf = m_CurrentTunnelDataMsg->GetBuffer ();
|
||||
buf[0] = 0x80 | (fragmentNumber << 1); // frag
|
||||
bool isLastFragment = false;
|
||||
size_t s = msg->GetLength () - size;
|
||||
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
|
||||
{
|
||||
{
|
||||
buf[0] |= 0x01;
|
||||
isLastFragment = true;
|
||||
}
|
||||
@ -119,7 +119,7 @@ namespace tunnel
|
||||
if(m_RemainingSize < (s+7)) {
|
||||
LogPrint (eLogError, "TunnelGateway: remaining size overflow: ", m_RemainingSize, " < ", s+7);
|
||||
} else {
|
||||
m_RemainingSize -= s+7;
|
||||
m_RemainingSize -= s+7;
|
||||
if (m_RemainingSize == 0)
|
||||
CompleteCurrentTunnelDataMessage ();
|
||||
}
|
||||
@ -129,17 +129,17 @@ namespace tunnel
|
||||
size += s;
|
||||
fragmentNumber++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// delivery instructions don't fit. Create new message
|
||||
CompleteCurrentTunnelDataMessage ();
|
||||
PutI2NPMsg (block);
|
||||
// don't delete msg because it's taken care inside
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TunnelGatewayBuffer::ClearTunnelDataMsgs ()
|
||||
{
|
||||
m_TunnelDataMsgs.clear ();
|
||||
@ -155,49 +155,49 @@ namespace tunnel
|
||||
m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + I2NP_HEADER_SIZE;
|
||||
m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset;
|
||||
m_RemainingSize = TUNNEL_DATA_MAX_PAYLOAD_SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TunnelGatewayBuffer::CompleteCurrentTunnelDataMessage ()
|
||||
{
|
||||
if (!m_CurrentTunnelDataMsg) return;
|
||||
uint8_t * payload = m_CurrentTunnelDataMsg->GetBuffer ();
|
||||
size_t size = m_CurrentTunnelDataMsg->len - m_CurrentTunnelDataMsg->offset;
|
||||
|
||||
|
||||
m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - I2NP_HEADER_SIZE;
|
||||
uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload ();
|
||||
RAND_bytes (buf + 4, 16); // original IV
|
||||
memcpy (payload + size, buf + 4, 16); // copy IV for checksum
|
||||
RAND_bytes (buf + 4, 16); // original IV
|
||||
memcpy (payload + size, buf + 4, 16); // copy IV for checksum
|
||||
uint8_t hash[32];
|
||||
SHA256(payload, size+16, hash);
|
||||
memcpy (buf+20, hash, 4); // checksum
|
||||
payload[-1] = 0; // zero
|
||||
ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1
|
||||
memcpy (buf+20, hash, 4); // checksum
|
||||
payload[-1] = 0; // zero
|
||||
ptrdiff_t paddingSize = payload - buf - 25; // 25 = 24 + 1
|
||||
if (paddingSize > 0)
|
||||
{
|
||||
// non-zero padding
|
||||
// non-zero padding
|
||||
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
|
||||
m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg);
|
||||
m_CurrentTunnelDataMsg = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block)
|
||||
{
|
||||
if (block.data)
|
||||
{
|
||||
{
|
||||
PutTunnelDataMsg (block);
|
||||
SendBuffer ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block)
|
||||
{
|
||||
if (block.data)
|
||||
m_Buffer.PutI2NPMsg (block);
|
||||
}
|
||||
}
|
||||
|
||||
void TunnelGateway::SendBuffer ()
|
||||
{
|
||||
@ -205,17 +205,17 @@ namespace tunnel
|
||||
std::vector<std::shared_ptr<I2NPMessage> > newTunnelMsgs;
|
||||
const auto& tunnelDataMsgs = m_Buffer.GetTunnelDataMsgs ();
|
||||
for (auto& tunnelMsg : tunnelDataMsgs)
|
||||
{
|
||||
{
|
||||
auto newMsg = CreateEmptyTunnelDataMsg ();
|
||||
m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||
m_Tunnel->EncryptTunnelMsg (tunnelMsg, newMsg);
|
||||
htobe32buf (newMsg->GetPayload (), m_Tunnel->GetNextTunnelID ());
|
||||
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
newMsg->FillI2NPMessageHeader (eI2NPTunnelData);
|
||||
newTunnelMsgs.push_back (newMsg);
|
||||
m_NumSentBytes += TUNNEL_DATA_MSG_SIZE;
|
||||
}
|
||||
}
|
||||
m_Buffer.ClearTunnelDataMsgs ();
|
||||
i2p::transport::transports.SendMessages (m_Tunnel->GetNextIdentHash (), newTunnelMsgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace tunnel
|
||||
public:
|
||||
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; };
|
||||
void ClearTunnelDataMsgs ();
|
||||
void CompleteCurrentTunnelDataMessage ();
|
||||
@ -24,14 +24,14 @@ namespace tunnel
|
||||
private:
|
||||
|
||||
void CreateCurrentTunnelDataMessage ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
std::vector<std::shared_ptr<const I2NPMessage> > m_TunnelDataMsgs;
|
||||
std::shared_ptr<I2NPMessage> m_CurrentTunnelDataMsg;
|
||||
size_t m_RemainingSize;
|
||||
uint8_t m_NonZeroRandomBuffer[TUNNEL_DATA_MAX_PAYLOAD_SIZE];
|
||||
};
|
||||
};
|
||||
|
||||
class TunnelGateway
|
||||
{
|
||||
@ -39,18 +39,18 @@ namespace tunnel
|
||||
|
||||
TunnelGateway (TunnelBase * tunnel):
|
||||
m_Tunnel (tunnel), m_NumSentBytes (0) {};
|
||||
void SendTunnelDataMsg (const TunnelMessageBlock& block);
|
||||
void SendTunnelDataMsg (const TunnelMessageBlock& block);
|
||||
void PutTunnelDataMsg (const TunnelMessageBlock& block);
|
||||
void SendBuffer ();
|
||||
void SendBuffer ();
|
||||
size_t GetNumSentBytes () const { return m_NumSentBytes; };
|
||||
|
||||
|
||||
private:
|
||||
|
||||
TunnelBase * m_Tunnel;
|
||||
TunnelGatewayBuffer m_Buffer;
|
||||
size_t m_NumSentBytes;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -28,23 +28,23 @@ namespace api
|
||||
i2p::fs::DetectDataDir(datadir, false);
|
||||
i2p::fs::Init();
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#if defined(__x86_64__)
|
||||
i2p::crypto::InitCrypto (false);
|
||||
#else
|
||||
i2p::crypto::InitCrypto (true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int netID; i2p::config::GetOption("netid", netID);
|
||||
i2p::context.SetNetID (netID);
|
||||
|
||||
i2p::context.Init ();
|
||||
i2p::context.Init ();
|
||||
}
|
||||
|
||||
void TerminateI2P ()
|
||||
{
|
||||
i2p::crypto::TerminateCrypto ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void StartI2P (std::shared_ptr<std::ostream> logStream)
|
||||
{
|
||||
if (logStream)
|
||||
@ -75,8 +75,8 @@ namespace api
|
||||
void RunPeerTest ()
|
||||
{
|
||||
i2p::transport::transports.PeerTest ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic,
|
||||
const std::map<std::string, std::string> * params)
|
||||
{
|
||||
@ -119,8 +119,8 @@ namespace api
|
||||
else
|
||||
{
|
||||
RequestLeaseSet (dest, remote);
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AcceptStream (std::shared_ptr<i2p::client::ClientDestination> dest, const i2p::stream::StreamingDestination::Acceptor& acceptor)
|
||||
|
@ -11,18 +11,18 @@ namespace i2p
|
||||
{
|
||||
namespace api
|
||||
{
|
||||
// initialization start and stop
|
||||
// initialization start and stop
|
||||
void InitI2P (int argc, char* argv[], const char * appName);
|
||||
void TerminateI2P ();
|
||||
void StartI2P (std::shared_ptr<std::ostream> logStream = nullptr);
|
||||
// write system log to logStream, if not specified to <appName>.log in application's folder
|
||||
void StopI2P ();
|
||||
void RunPeerTest (); // should be called after UPnP
|
||||
|
||||
|
||||
// destinations
|
||||
std::shared_ptr<i2p::client::ClientDestination> CreateLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic = true,
|
||||
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,
|
||||
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,
|
||||
const std::map<std::string, std::string> * params = nullptr); // transient destinations usually not published
|
||||
void DestroyLocalDestination (std::shared_ptr<i2p::client::ClientDestination> dest);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#ifdef WIN32
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <iphlpapi.h>
|
||||
@ -167,7 +167,7 @@ namespace net
|
||||
}
|
||||
|
||||
int GetMTUWindows(const boost::asio::ip::address& localAddress, int fallback)
|
||||
{
|
||||
{
|
||||
#ifdef UNICODE
|
||||
string localAddress_temporary = localAddress.to_string();
|
||||
wstring localAddressUniversal(localAddress_temporary.begin(), localAddress_temporary.end());
|
||||
@ -181,7 +181,7 @@ namespace net
|
||||
return GetMTUWindowsIpv4(inputAddress, fallback);
|
||||
} else if(localAddress.is_v6()) {
|
||||
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);
|
||||
} else {
|
||||
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)
|
||||
{
|
||||
ifaddrs* ifaddr, *ifa = nullptr;
|
||||
if(getifaddrs(&ifaddr) == -1)
|
||||
if(getifaddrs(&ifaddr) == -1)
|
||||
{
|
||||
LogPrint(eLogError, "NetIface: Can't call getifaddrs(): ", strerror(errno));
|
||||
return fallback;
|
||||
}
|
||||
|
||||
int family = 0;
|
||||
// look for interface matching local address
|
||||
for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
|
||||
// look for interface matching local address
|
||||
for(ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next)
|
||||
{
|
||||
if(!ifa->ifa_addr)
|
||||
continue;
|
||||
|
||||
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;
|
||||
if(!memcmp(&sa->sin_addr, localAddress.to_v4().to_bytes().data(), 4))
|
||||
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;
|
||||
if(!memcmp(&sa->sin6_addr, localAddress.to_v6().to_bytes().data(), 16))
|
||||
@ -221,28 +221,28 @@ namespace net
|
||||
}
|
||||
}
|
||||
int mtu = fallback;
|
||||
if(ifa && family)
|
||||
if(ifa && family)
|
||||
{ // interface found?
|
||||
int fd = socket(family, SOCK_DGRAM, 0);
|
||||
if(fd > 0)
|
||||
if(fd > 0)
|
||||
{
|
||||
ifreq ifr;
|
||||
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
|
||||
else
|
||||
LogPrint (eLogError, "NetIface: Failed to run ioctl: ", strerror(errno));
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
else
|
||||
LogPrint(eLogError, "NetIface: Failed to create datagram socket");
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
LogPrint(eLogWarning, "NetIface: interface for local address", localAddress.to_string(), " not found");
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
return mtu;
|
||||
}
|
||||
}
|
||||
#endif // WIN32
|
||||
|
||||
int GetMTU(const boost::asio::ip::address& localAddress)
|
||||
@ -256,7 +256,7 @@ namespace net
|
||||
#endif
|
||||
return fallback;
|
||||
}
|
||||
|
||||
|
||||
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6)
|
||||
{
|
||||
#ifdef WIN32
|
||||
@ -299,9 +299,9 @@ namespace net
|
||||
LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname);
|
||||
}
|
||||
return boost::asio::ip::address::from_string(fallback);
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
} // util
|
||||
} // i2p
|
||||
|
@ -38,15 +38,15 @@ namespace util
|
||||
public:
|
||||
|
||||
MemoryPool (): m_Head (nullptr) {}
|
||||
~MemoryPool ()
|
||||
{
|
||||
while (m_Head)
|
||||
~MemoryPool ()
|
||||
{
|
||||
while (m_Head)
|
||||
{
|
||||
auto tmp = m_Head;
|
||||
m_Head = static_cast<T*>(*(void * *)m_Head); // next
|
||||
delete tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... TArgs>
|
||||
T * Acquire (TArgs&&... args)
|
||||
@ -65,7 +65,7 @@ namespace util
|
||||
if (!t) return;
|
||||
t->~T ();
|
||||
*(void * *)t = m_Head; // next
|
||||
m_Head = t;
|
||||
m_Head = t;
|
||||
}
|
||||
|
||||
template<typename... TArgs>
|
||||
@ -74,7 +74,7 @@ namespace util
|
||||
return std::unique_ptr<T, std::function<void(T*)> >(Acquire (std::forward<TArgs>(args)...),
|
||||
std::bind (&MemoryPool<T>::Release, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
|
||||
template<typename... TArgs>
|
||||
std::shared_ptr<T> AcquireShared (TArgs&&... args)
|
||||
{
|
||||
@ -85,7 +85,7 @@ namespace util
|
||||
protected:
|
||||
|
||||
T * m_Head;
|
||||
};
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class MemoryPoolMt: public MemoryPool<T>
|
||||
@ -104,19 +104,19 @@ namespace util
|
||||
void ReleaseMt (T * t)
|
||||
{
|
||||
std::lock_guard<std::mutex> l(m_Mutex);
|
||||
this->Release (t);
|
||||
this->Release (t);
|
||||
}
|
||||
|
||||
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);
|
||||
for (auto& it: c)
|
||||
this->Release (it);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
||||
std::mutex m_Mutex;
|
||||
};
|
||||
|
||||
|
@ -383,9 +383,9 @@ namespace client
|
||||
{
|
||||
it->second = ident->GetIdentHash ();
|
||||
m_Storage->AddAddress (ident);
|
||||
LogPrint (eLogInfo, "Addressbook: updated host: ", name);
|
||||
LogPrint (eLogInfo, "Addressbook: updated host: ", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Addresses.insert (std::make_pair (name, ident->GetIdentHash ()));
|
||||
|
@ -18,15 +18,15 @@ namespace i2p
|
||||
{
|
||||
namespace client
|
||||
{
|
||||
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // 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_RETRY_TIMEOUT = 5; // in minutes
|
||||
const int INITIAL_SUBSCRIPTION_UPDATE_TIMEOUT = 3; // 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_RETRY_TIMEOUT = 5; // in minutes
|
||||
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;
|
||||
|
||||
|
||||
inline std::string GetB32Address(const i2p::data::IdentHash& ident) { return ident.ToBase32().append(".b32.i2p"); }
|
||||
|
||||
class AddressBookStorage // interface for storage
|
||||
@ -34,10 +34,10 @@ namespace client
|
||||
public:
|
||||
|
||||
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 RemoveAddress (const i2p::data::IdentHash& ident) = 0;
|
||||
|
||||
|
||||
virtual bool Init () = 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;
|
||||
@ -45,7 +45,7 @@ namespace client
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
|
||||
class AddressBookSubscription;
|
||||
class AddressResolver;
|
||||
@ -77,7 +77,7 @@ namespace client
|
||||
|
||||
void StartSubscriptions ();
|
||||
void StopSubscriptions ();
|
||||
|
||||
|
||||
void LoadHosts ();
|
||||
void LoadSubscriptions ();
|
||||
void LoadLocal ();
|
||||
@ -87,8 +87,8 @@ namespace client
|
||||
void StartLookups ();
|
||||
void StopLookups ();
|
||||
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::map<std::string, i2p::data::IdentHash> m_Addresses;
|
||||
@ -112,7 +112,7 @@ namespace client
|
||||
private:
|
||||
|
||||
bool MakeRequest ();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
AddressBook& m_Book;
|
||||
|
@ -8,7 +8,7 @@ namespace i2p
|
||||
{
|
||||
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)
|
||||
{
|
||||
}
|
||||
@ -36,13 +36,13 @@ namespace client
|
||||
receiver->socket = std::make_shared<boost::asio::ip::tcp::socket> (GetService ());
|
||||
m_Acceptor.async_accept (*receiver->socket, std::bind (&BOBI2PInboundTunnel::HandleAccept, this,
|
||||
std::placeholders::_1, receiver));
|
||||
}
|
||||
}
|
||||
|
||||
void BOBI2PInboundTunnel::HandleAccept (const boost::system::error_code& ecode, std::shared_ptr<AddressReceiver> receiver)
|
||||
{
|
||||
if (!ecode)
|
||||
{
|
||||
Accept ();
|
||||
Accept ();
|
||||
ReceiveAddress (receiver);
|
||||
}
|
||||
}
|
||||
@ -50,12 +50,12 @@ namespace client
|
||||
void BOBI2PInboundTunnel::ReceiveAddress (std::shared_ptr<AddressReceiver> receiver)
|
||||
{
|
||||
receiver->socket->async_read_some (boost::asio::buffer(
|
||||
receiver->buffer + receiver->bufferOffset,
|
||||
BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset),
|
||||
std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this,
|
||||
receiver->buffer + receiver->bufferOffset,
|
||||
BOB_COMMAND_BUFFER_SIZE - receiver->bufferOffset),
|
||||
std::bind(&BOBI2PInboundTunnel::HandleReceivedAddress, this,
|
||||
std::placeholders::_1, std::placeholders::_2, receiver));
|
||||
}
|
||||
|
||||
|
||||
void BOBI2PInboundTunnel::HandleReceivedAddress (const boost::system::error_code& ecode, std::size_t bytes_transferred,
|
||||
std::shared_ptr<AddressReceiver> receiver)
|
||||
{
|
||||
@ -69,11 +69,11 @@ namespace client
|
||||
if (eol)
|
||||
{
|
||||
*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->dataLen = receiver->bufferOffset - (eol - receiver->buffer + 1);
|
||||
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");
|
||||
return;
|
||||
@ -82,7 +82,7 @@ namespace client
|
||||
if (leaseSet)
|
||||
CreateConnection (receiver, leaseSet);
|
||||
else
|
||||
GetLocalDestination ()->RequestDestination (ident,
|
||||
GetLocalDestination ()->RequestDestination (ident,
|
||||
std::bind (&BOBI2PInboundTunnel::HandleDestinationRequestComplete,
|
||||
this, std::placeholders::_1, receiver));
|
||||
}
|
||||
@ -92,7 +92,7 @@ namespace client
|
||||
ReceiveAddress (receiver);
|
||||
else
|
||||
LogPrint (eLogError, "BOB: missing inbound address");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ namespace client
|
||||
CreateConnection (receiver, leaseSet);
|
||||
else
|
||||
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)
|
||||
{
|
||||
@ -112,12 +112,12 @@ namespace client
|
||||
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),
|
||||
m_Endpoint (boost::asio::ip::address::from_string (address), port), m_IsQuiet (quiet)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void BOBI2POutboundTunnel::Start ()
|
||||
{
|
||||
Accept ();
|
||||
@ -126,11 +126,11 @@ namespace client
|
||||
void BOBI2POutboundTunnel::Stop ()
|
||||
{
|
||||
ClearHandlers ();
|
||||
}
|
||||
}
|
||||
|
||||
void BOBI2POutboundTunnel::Accept ()
|
||||
{
|
||||
auto localDestination = GetLocalDestination ();
|
||||
auto localDestination = GetLocalDestination ();
|
||||
if (localDestination)
|
||||
localDestination->AcceptStreams (std::bind (&BOBI2POutboundTunnel::HandleAccept, this, std::placeholders::_1));
|
||||
else
|
||||
@ -140,54 +140,54 @@ namespace client
|
||||
void BOBI2POutboundTunnel::HandleAccept (std::shared_ptr<i2p::stream::Stream> stream)
|
||||
{
|
||||
if (stream)
|
||||
{
|
||||
{
|
||||
auto conn = std::make_shared<I2PTunnelConnection> (this, stream, std::make_shared<boost::asio::ip::tcp::socket> (GetService ()), m_Endpoint, m_IsQuiet);
|
||||
AddHandler (conn);
|
||||
conn->Connect ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOBDestination::BOBDestination (std::shared_ptr<ClientDestination> localDestination):
|
||||
m_LocalDestination (localDestination),
|
||||
m_LocalDestination (localDestination),
|
||||
m_OutboundTunnel (nullptr), m_InboundTunnel (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BOBDestination::~BOBDestination ()
|
||||
{
|
||||
delete m_OutboundTunnel;
|
||||
delete m_InboundTunnel;
|
||||
i2p::client::context.DeleteLocalDestination (m_LocalDestination);
|
||||
}
|
||||
}
|
||||
|
||||
void BOBDestination::Start ()
|
||||
{
|
||||
if (m_OutboundTunnel) m_OutboundTunnel->Start ();
|
||||
if (m_InboundTunnel) m_InboundTunnel->Start ();
|
||||
}
|
||||
|
||||
|
||||
void BOBDestination::Stop ()
|
||||
{
|
||||
{
|
||||
StopTunnels ();
|
||||
m_LocalDestination->Stop ();
|
||||
}
|
||||
}
|
||||
|
||||
void BOBDestination::StopTunnels ()
|
||||
{
|
||||
if (m_OutboundTunnel)
|
||||
{
|
||||
{
|
||||
m_OutboundTunnel->Stop ();
|
||||
delete m_OutboundTunnel;
|
||||
m_OutboundTunnel = nullptr;
|
||||
}
|
||||
}
|
||||
if (m_InboundTunnel)
|
||||
{
|
||||
{
|
||||
m_InboundTunnel->Stop ();
|
||||
delete m_InboundTunnel;
|
||||
m_InboundTunnel = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void BOBDestination::CreateInboundTunnel (int port, const std::string& address)
|
||||
{
|
||||
if (!m_InboundTunnel)
|
||||
@ -200,21 +200,21 @@ namespace client
|
||||
if (!ec)
|
||||
ep.address (addr);
|
||||
else
|
||||
LogPrint (eLogError, "BOB: ", ec.message ());
|
||||
}
|
||||
LogPrint (eLogError, "BOB: ", ec.message ());
|
||||
}
|
||||
m_InboundTunnel = new BOBI2PInboundTunnel (ep, m_LocalDestination);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BOBDestination::CreateOutboundTunnel (const std::string& address, int port, bool quiet)
|
||||
{
|
||||
if (!m_OutboundTunnel)
|
||||
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_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)
|
||||
{
|
||||
}
|
||||
@ -226,13 +226,13 @@ namespace client
|
||||
void BOBCommandSession::Terminate ()
|
||||
{
|
||||
m_Socket.close ();
|
||||
m_IsOpen = false;
|
||||
m_IsOpen = false;
|
||||
}
|
||||
|
||||
void BOBCommandSession::Receive ()
|
||||
{
|
||||
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 (),
|
||||
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::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
@ -243,29 +243,29 @@ namespace client
|
||||
LogPrint (eLogError, "BOB: command channel read error: ", ecode.message ());
|
||||
if (ecode != boost::asio::error::operation_aborted)
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size = m_ReceiveBufferOffset + bytes_transferred;
|
||||
{
|
||||
size_t size = m_ReceiveBufferOffset + bytes_transferred;
|
||||
m_ReceiveBuffer[size] = 0;
|
||||
char * eol = strchr (m_ReceiveBuffer, '\n');
|
||||
if (eol)
|
||||
{
|
||||
*eol = 0;
|
||||
char * operand = strchr (m_ReceiveBuffer, ' ');
|
||||
if (operand)
|
||||
{
|
||||
if (operand)
|
||||
{
|
||||
*operand = 0;
|
||||
operand++;
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
operand = eol;
|
||||
// process command
|
||||
auto& handlers = m_Owner.GetCommandHandlers ();
|
||||
auto it = handlers.find (m_ReceiveBuffer);
|
||||
if (it != handlers.end ())
|
||||
(this->*(it->second))(operand, eol - operand);
|
||||
else
|
||||
else
|
||||
{
|
||||
LogPrint (eLogError, "BOB: unknown command ", m_ReceiveBuffer);
|
||||
SendReplyError ("unknown command");
|
||||
@ -283,15 +283,15 @@ namespace client
|
||||
LogPrint (eLogError, "BOB: Malformed input of the command channel");
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (),
|
||||
std::bind(&BOBCommandSession::HandleSent, shared_from_this (),
|
||||
std::bind(&BOBCommandSession::HandleSent, shared_from_this (),
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
}
|
||||
|
||||
@ -308,7 +308,7 @@ namespace client
|
||||
if (m_IsOpen)
|
||||
Receive ();
|
||||
else
|
||||
Terminate ();
|
||||
Terminate ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,7 +316,7 @@ namespace client
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
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);
|
||||
#endif
|
||||
Send (len);
|
||||
@ -326,12 +326,12 @@ namespace client
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
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);
|
||||
#endif
|
||||
Send (len);
|
||||
Send (len);
|
||||
}
|
||||
|
||||
|
||||
void BOBCommandSession::SendVersion ()
|
||||
{
|
||||
size_t len = strlen (BOB_VERSION);
|
||||
@ -343,12 +343,12 @@ namespace client
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
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);
|
||||
#endif
|
||||
Send (len);
|
||||
Send (len);
|
||||
}
|
||||
|
||||
|
||||
void BOBCommandSession::ZapCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: zap");
|
||||
@ -368,21 +368,21 @@ namespace client
|
||||
if (m_IsActive)
|
||||
{
|
||||
SendReplyError ("tunnel is active");
|
||||
return;
|
||||
return;
|
||||
}
|
||||
if (!m_CurrentDestination)
|
||||
{
|
||||
{
|
||||
m_CurrentDestination = new BOBDestination (i2p::client::context.CreateNewLocalDestination (m_Keys, true, &m_Options));
|
||||
m_Owner.AddDestination (m_Nickname, m_CurrentDestination);
|
||||
}
|
||||
}
|
||||
if (m_InPort)
|
||||
m_CurrentDestination->CreateInboundTunnel (m_InPort, m_Address);
|
||||
if (m_OutPort && !m_Address.empty ())
|
||||
m_CurrentDestination->CreateOutboundTunnel (m_Address, m_OutPort, m_IsQuiet);
|
||||
m_CurrentDestination->Start ();
|
||||
m_CurrentDestination->Start ();
|
||||
SendReplyOK ("Tunnel starting");
|
||||
m_IsActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::StopCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
@ -401,8 +401,8 @@ namespace client
|
||||
else
|
||||
SendReplyError ("tunnel not found");
|
||||
m_IsActive = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BOBCommandSession::SetNickCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: setnick ", operand);
|
||||
@ -410,30 +410,30 @@ namespace client
|
||||
std::string msg ("Nickname set to ");
|
||||
msg += m_Nickname;
|
||||
SendReplyOK (msg.c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::GetNickCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: getnick ", operand);
|
||||
m_CurrentDestination = m_Owner.FindDestination (operand);
|
||||
m_CurrentDestination = m_Owner.FindDestination (operand);
|
||||
if (m_CurrentDestination)
|
||||
{
|
||||
m_Keys = m_CurrentDestination->GetKeys ();
|
||||
m_Nickname = operand;
|
||||
}
|
||||
if (m_Nickname == operand)
|
||||
{
|
||||
{
|
||||
std::string msg ("Nickname set to ");
|
||||
msg += m_Nickname;
|
||||
SendReplyOK (msg.c_str ());
|
||||
}
|
||||
}
|
||||
else
|
||||
SendReplyError ("no nickname has been set");
|
||||
}
|
||||
SendReplyError ("no nickname has been set");
|
||||
}
|
||||
|
||||
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::CryptoKeyType cryptoType = i2p::data::CRYPTO_KEY_TYPE_ELGAMAL;
|
||||
if (*operand)
|
||||
@ -441,23 +441,23 @@ namespace client
|
||||
try
|
||||
{
|
||||
char * operand1 = (char *)strchr (operand, ' ');
|
||||
if (operand1)
|
||||
if (operand1)
|
||||
{
|
||||
*operand1 = 0; operand1++;
|
||||
cryptoType = std::stoi(operand1);
|
||||
}
|
||||
signatureType = std::stoi(operand);
|
||||
signatureType = std::stoi(operand);
|
||||
}
|
||||
catch (std::invalid_argument& ex)
|
||||
{
|
||||
LogPrint (eLogWarning, "BOB: newkeys ", ex.what ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (signatureType, cryptoType);
|
||||
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::SetkeysCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
@ -467,9 +467,9 @@ namespace client
|
||||
else
|
||||
SendReplyError ("invalid keys");
|
||||
}
|
||||
|
||||
|
||||
void BOBCommandSession::GetkeysCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: getkeys");
|
||||
if (m_Keys.GetPublic ()) // keys are set ?
|
||||
SendReplyOK (m_Keys.ToBase64 ().c_str ());
|
||||
@ -484,15 +484,15 @@ namespace client
|
||||
SendReplyOK (m_Keys.GetPublic ()->ToBase64 ().c_str ());
|
||||
else
|
||||
SendReplyError ("keys are not set");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BOBCommandSession::OuthostCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: outhost ", operand);
|
||||
m_Address = operand;
|
||||
SendReplyOK ("outhost set");
|
||||
}
|
||||
|
||||
|
||||
void BOBCommandSession::OutportCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: outport ", operand);
|
||||
@ -501,7 +501,7 @@ namespace client
|
||||
SendReplyOK ("outbound port set");
|
||||
else
|
||||
SendReplyError ("port out of range");
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::InhostCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
@ -509,7 +509,7 @@ namespace client
|
||||
m_Address = operand;
|
||||
SendReplyOK ("inhost set");
|
||||
}
|
||||
|
||||
|
||||
void BOBCommandSession::InportCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: inport ", operand);
|
||||
@ -518,7 +518,7 @@ namespace client
|
||||
SendReplyOK ("inbound port set");
|
||||
else
|
||||
SendReplyError ("port out of range");
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::QuietCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
@ -535,17 +535,17 @@ namespace client
|
||||
}
|
||||
else
|
||||
SendReplyError ("no nickname has been set");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BOBCommandSession::LookupCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: lookup ", operand);
|
||||
i2p::data::IdentHash ident;
|
||||
if (!context.GetAddressBook ().GetIdentHash (operand, ident))
|
||||
if (!context.GetAddressBook ().GetIdentHash (operand, ident))
|
||||
{
|
||||
SendReplyError ("Address Not found");
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto localDestination = m_CurrentDestination ? m_CurrentDestination->GetLocalDestination () : i2p::client::context.GetSharedLocalDestination ();
|
||||
auto leaseSet = localDestination->FindLeaseSet (ident);
|
||||
if (leaseSet)
|
||||
@ -553,14 +553,14 @@ namespace client
|
||||
else
|
||||
{
|
||||
auto s = shared_from_this ();
|
||||
localDestination->RequestDestination (ident,
|
||||
localDestination->RequestDestination (ident,
|
||||
[s](std::shared_ptr<i2p::data::LeaseSet> ls)
|
||||
{
|
||||
if (ls)
|
||||
s->SendReplyOK (ls->GetIdentity ()->ToBase64 ().c_str ());
|
||||
else
|
||||
else
|
||||
s->SendReplyError ("LeaseSet Not found");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -571,7 +571,7 @@ namespace client
|
||||
m_Owner.DeleteDestination (m_Nickname);
|
||||
m_Nickname = "";
|
||||
SendReplyOK ("cleared");
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::ListCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
@ -580,26 +580,26 @@ namespace client
|
||||
for (const auto& it: destinations)
|
||||
SendData (it.first.c_str ());
|
||||
SendReplyOK ("Listing done");
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::OptionCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
LogPrint (eLogDebug, "BOB: option ", operand);
|
||||
const char * value = strchr (operand, '=');
|
||||
if (value)
|
||||
{
|
||||
{
|
||||
std::string msg ("option ");
|
||||
*(const_cast<char *>(value)) = 0;
|
||||
m_Options[operand] = value + 1;
|
||||
m_Options[operand] = value + 1;
|
||||
msg += operand;
|
||||
*(const_cast<char *>(value)) = '=';
|
||||
msg += " set to ";
|
||||
msg += value;
|
||||
msg += value;
|
||||
SendReplyOK (msg.c_str ());
|
||||
}
|
||||
}
|
||||
else
|
||||
SendReplyError ("malformed");
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandSession::StatusCommandHandler (const char * operand, size_t len)
|
||||
{
|
||||
@ -609,37 +609,37 @@ namespace client
|
||||
std::stringstream s;
|
||||
s << "DATA"; s << " NICKNAME: "; s << m_Nickname;
|
||||
if (m_CurrentDestination)
|
||||
{
|
||||
{
|
||||
if (m_CurrentDestination->GetLocalDestination ()->IsReady ())
|
||||
s << " STARTING: false RUNNING: true STOPPING: false";
|
||||
else
|
||||
s << " STARTING: true RUNNING: false STOPPING: false";
|
||||
}
|
||||
}
|
||||
else
|
||||
s << " STARTING: false RUNNING: false STOPPING: false";
|
||||
s << " KEYS: true"; s << " QUIET: "; s << (m_IsQuiet ? "true":"false");
|
||||
if (m_InPort)
|
||||
{
|
||||
{
|
||||
s << " INPORT: " << m_InPort;
|
||||
s << " INHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1");
|
||||
}
|
||||
}
|
||||
if (m_OutPort)
|
||||
{
|
||||
{
|
||||
s << " OUTPORT: " << m_OutPort;
|
||||
s << " OUTHOST: " << (m_Address.length () > 0 ? m_Address : "127.0.0.1");
|
||||
}
|
||||
}
|
||||
SendReplyOK (s.str().c_str());
|
||||
}
|
||||
else
|
||||
SendReplyError ("no nickname has been set");
|
||||
}
|
||||
|
||||
SendReplyError ("no nickname has been set");
|
||||
}
|
||||
|
||||
BOBCommandChannel::BOBCommandChannel (const std::string& address, int port):
|
||||
m_IsRunning (false), m_Thread (nullptr),
|
||||
m_Acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(address), port))
|
||||
{
|
||||
// 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_START] = &BOBCommandSession::StartCommandHandler;
|
||||
m_CommandHandlers[BOB_COMMAND_STOP] = &BOBCommandSession::StopCommandHandler;
|
||||
@ -680,35 +680,35 @@ namespace client
|
||||
m_IsRunning = false;
|
||||
for (auto& it: m_Destinations)
|
||||
it.second->Stop ();
|
||||
m_Acceptor.cancel ();
|
||||
m_Acceptor.cancel ();
|
||||
m_Service.stop ();
|
||||
if (m_Thread)
|
||||
{
|
||||
m_Thread->join ();
|
||||
{
|
||||
m_Thread->join ();
|
||||
delete m_Thread;
|
||||
m_Thread = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandChannel::Run ()
|
||||
{
|
||||
|
||||
void BOBCommandChannel::Run ()
|
||||
{
|
||||
while (m_IsRunning)
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
m_Service.run ();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
LogPrint (eLogError, "BOB: runtime exception: ", ex.what ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandChannel::AddDestination (const std::string& name, BOBDestination * dest)
|
||||
{
|
||||
m_Destinations[name] = dest;
|
||||
}
|
||||
}
|
||||
|
||||
void BOBCommandChannel::DeleteDestination (const std::string& name)
|
||||
{
|
||||
@ -718,17 +718,17 @@ namespace client
|
||||
it->second->Stop ();
|
||||
delete it->second;
|
||||
m_Destinations.erase (it);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
BOBDestination * BOBCommandChannel::FindDestination (const std::string& name)
|
||||
{
|
||||
auto it = m_Destinations.find (name);
|
||||
if (it != m_Destinations.end ())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void BOBCommandChannel::Accept ()
|
||||
{
|
||||
auto newSession = std::make_shared<BOBCommandSession> (*this);
|
||||
@ -744,7 +744,7 @@ namespace client
|
||||
if (!ecode)
|
||||
{
|
||||
LogPrint (eLogInfo, "BOB: New command connection from ", session->GetSocket ().remote_endpoint ());
|
||||
session->SendVersion ();
|
||||
session->SendVersion ();
|
||||
}
|
||||
else
|
||||
LogPrint (eLogError, "BOB: accept error: ", ecode.message ());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user