Browse Source

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

pull/1272/head
Jeff Becker 6 years ago
parent
commit
16b3108719
No known key found for this signature in database
GPG Key ID: F357B3B42F6F9B05
  1. 15
      ChangeLog
  2. 3
      Win32/installer.iss
  3. 2
      android/AndroidManifest.xml
  4. 13
      android/assets/i2pd.conf
  5. 1
      android/assets/tunnels.d
  6. 2
      android/build.gradle
  7. 5
      android/jni/i2pd_android.cpp
  8. 3
      android/jni/org_purplei2p_i2pd_I2PD_JNI.h
  9. 1
      android/res/values/strings.xml
  10. 7
      android/src/org/purplei2p/i2pd/DaemonSingleton.java
  11. 70
      android/src/org/purplei2p/i2pd/I2PDActivity.java
  12. 2
      android/src/org/purplei2p/i2pd/I2PD_JNI.java
  13. 2
      appveyor.yml
  14. 10
      build/build_mingw.cmd
  15. 11
      contrib/i2pd.conf
  16. 6
      contrib/i2pd.service
  17. 36
      contrib/rpm/i2pd-git.spec
  18. 16
      contrib/rpm/i2pd.spec
  19. 7
      contrib/tunnels.d/IRC-Ilita.conf
  20. 7
      contrib/tunnels.d/IRC-Irc2P.conf
  21. 4
      contrib/tunnels.d/README
  22. 18
      daemon/Daemon.cpp
  23. 77
      daemon/HTTPServer.cpp
  24. 4
      debian/.gitignore
  25. 15
      debian/changelog
  26. 1
      debian/docs
  27. 3
      debian/i2pd.1
  28. 3
      debian/i2pd.init
  29. 1
      debian/i2pd.install
  30. 1
      debian/i2pd.links
  31. 3
      debian/i2pd.openrc
  32. 6
      debian/patches/02-fix-1210.patch
  33. 2
      debian/patches/series
  34. 4
      libi2pd/ChaCha20.cpp
  35. 3
      libi2pd/ChaCha20.h
  36. 38
      libi2pd/Config.cpp
  37. 10
      libi2pd/Crypto.cpp
  38. 24
      libi2pd/Crypto.h
  39. 2
      libi2pd/Ed25519.cpp
  40. 5
      libi2pd/Ed25519.h
  41. 1
      libi2pd/I2NPProtocol.h
  42. 122
      libi2pd/NTCP2.cpp
  43. 5
      libi2pd/NTCP2.h
  44. 92
      libi2pd/NetDb.cpp
  45. 6
      libi2pd/NetDb.hpp
  46. 4
      libi2pd/Poly1305.cpp
  47. 3
      libi2pd/Poly1305.h
  48. 8
      libi2pd/RouterContext.cpp
  49. 3
      libi2pd/Siphash.h
  50. 125
      libi2pd/Timestamp.cpp
  51. 44
      libi2pd/Timestamp.h
  52. 9
      libi2pd/Transports.cpp
  53. 6
      libi2pd/util.cpp
  54. 2
      libi2pd/version.h
  55. 2
      qt/i2pd_qt/android/AndroidManifest.xml
  56. BIN
      qt/i2pd_qt/data/icons/128x128/website.i2pd.i2pd.png
  57. BIN
      qt/i2pd_qt/data/icons/16x16/website.i2pd.i2pd.png
  58. BIN
      qt/i2pd_qt/data/icons/22x22/website.i2pd.i2pd.png
  59. BIN
      qt/i2pd_qt/data/icons/24x24/website.i2pd.i2pd.png
  60. BIN
      qt/i2pd_qt/data/icons/256x256/website.i2pd.i2pd.png
  61. BIN
      qt/i2pd_qt/data/icons/32x32/website.i2pd.i2pd.png
  62. BIN
      qt/i2pd_qt/data/icons/48x48/website.i2pd.i2pd.png
  63. BIN
      qt/i2pd_qt/data/icons/512x512/website.i2pd.i2pd.png
  64. BIN
      qt/i2pd_qt/data/icons/64x64/website.i2pd.i2pd.png
  65. 43
      qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml
  66. 11
      qt/i2pd_qt/data/website.i2pd.i2pd.desktop

15
ChangeLog

@ -1,6 +1,21 @@
# for this file format description, # for this file format description,
# see https://github.com/olivierlacan/keep-a-changelog # see https://github.com/olivierlacan/keep-a-changelog
## [2.22.0] - 2018-11-09
### Added
- Multiple tunnel config files from tunnels.d folder
### Changed
- Fetch own RouterInfo upon SessionRequest for NTCP2
- Faster XOR between AES blocks for non AVX capable CPUs
### Fixed
- Fixed NTCP2 termination send
## [2.21.1] - 2018-10-22
### Changed
- cost=13 for unpublished NTCP2 address
### Fixed
- Handle I2NP messages longer than 32K
## [2.21.0] - 2018-10-04 ## [2.21.0] - 2018-10-04
### Added ### Added
- EdDSA, x25519 and SipHash from openssl 1.1.1 - EdDSA, x25519 and SipHash from openssl 1.1.1

3
Win32/installer.iss

@ -1,5 +1,5 @@
#define I2Pd_AppName "i2pd" #define I2Pd_AppName "i2pd"
#define I2Pd_ver "2.21.0" #define I2Pd_ver "2.22.0"
#define I2Pd_Publisher "PurpleI2P" #define I2Pd_Publisher "PurpleI2P"
[Setup] [Setup]
@ -32,6 +32,7 @@ Source: ..\contrib\i2pd.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntex
Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
Source: ..\contrib\tunnels.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist Source: ..\contrib\tunnels.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist
Source: ..\contrib\certificates\*; DestDir: {userappdata}\i2pd\certificates; Flags: onlyifdoesntexist recursesubdirs createallsubdirs Source: ..\contrib\certificates\*; DestDir: {userappdata}\i2pd\certificates; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
Source: ..\contrib\tunnels.d\*; DestDir: {userappdata}\i2pd\tunnels.d; Flags: onlyifdoesntexist recursesubdirs createallsubdirs
[Icons] [Icons]
Name: {group}\I2Pd; Filename: {app}\i2pd.exe Name: {group}\I2Pd; Filename: {app}\i2pd.exe

2
android/AndroidManifest.xml

@ -3,7 +3,7 @@
package="org.purplei2p.i2pd" package="org.purplei2p.i2pd"
android:installLocation="auto" android:installLocation="auto"
android:versionCode="1" android:versionCode="1"
android:versionName="2.21.0"> android:versionName="2.22.0">
<uses-sdk <uses-sdk
android:minSdkVersion="14" android:minSdkVersion="14"

13
android/assets/i2pd.conf

@ -4,6 +4,7 @@
#logfile = /sdcard/i2pd/i2pd.log #logfile = /sdcard/i2pd/i2pd.log
loglevel = none loglevel = none
#tunnelsdir = /sdcard/i2pd/tunnels.d
# host = 1.2.3.4 # host = 1.2.3.4
# port = 4567 # port = 4567
@ -36,7 +37,12 @@ port = 7070
enabled = true enabled = true
address = 127.0.0.1 address = 127.0.0.1
port = 4444 port = 4444
# keys = http-proxy-keys.dat inbound.length = 1
inbound.quantity = 5
outbound.length = 1
outbound.quantity = 5
signaturetype=7
keys = proxy-keys.dat
# addresshelper = true # addresshelper = true
# outproxy = http://false.i2p # outproxy = http://false.i2p
## httpproxy section also accepts I2CP parameters, like "inbound.length" etc. ## httpproxy section also accepts I2CP parameters, like "inbound.length" etc.
@ -45,7 +51,7 @@ port = 4444
enabled = true enabled = true
address = 127.0.0.1 address = 127.0.0.1
port = 4447 port = 4447
# keys = socks-proxy-keys.dat keys = proxy-keys.dat
# outproxy.enabled = false # outproxy.enabled = false
# outproxy = 127.0.0.1 # outproxy = 127.0.0.1
# outproxyport = 9050 # outproxyport = 9050
@ -79,3 +85,6 @@ verify = true
[limits] [limits]
transittunnels = 50 transittunnels = 50
[persist]
profiles = false

1
android/assets/tunnels.d

@ -0,0 +1 @@
../../contrib/tunnels.d

2
android/build.gradle

@ -29,7 +29,7 @@ android {
targetSdkVersion 28 targetSdkVersion 28
minSdkVersion 14 minSdkVersion 14
versionCode 1 versionCode 1
versionName "2.21.0" versionName "2.22.0"
ndk { ndk {
abiFilters 'armeabi-v7a' abiFilters 'armeabi-v7a'
abiFilters 'x86' abiFilters 'x86'

5
android/jni/i2pd_android.cpp

@ -58,6 +58,11 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels
i2p::context.SetAcceptsTunnels (false); i2p::context.SetAcceptsTunnels (false);
} }
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels
(JNIEnv * env, jclass clazz) {
i2p::context.SetAcceptsTunnels (true);
}
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
(JNIEnv * env, jclass clazz, jboolean isConnected) (JNIEnv * env, jclass clazz, jboolean isConnected)
{ {

3
android/jni/org_purplei2p_i2pd_I2PD_JNI.h

@ -24,6 +24,9 @@ JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels
(JNIEnv *, jclass); (JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels
(JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged
(JNIEnv * env, jclass clazz, jboolean isConnected); (JNIEnv * env, jclass clazz, jboolean isConnected);

1
android/res/values/strings.xml

@ -3,6 +3,7 @@
<string name="app_name">i2pd</string> <string name="app_name">i2pd</string>
<string name="action_stop">Stop</string> <string name="action_stop">Stop</string>
<string name="action_graceful_stop">Graceful Stop</string> <string name="action_graceful_stop">Graceful Stop</string>
<string name="action_cancel_graceful_stop">Cancel Graceful Stop</string>
<string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string> <string name="graceful_stop_is_already_in_progress">Graceful stop is already in progress</string>
<string name="graceful_stop_is_in_progress">Graceful stop is in progress</string> <string name="graceful_stop_is_in_progress">Graceful stop is in progress</string>
<string name="already_stopped">Already stopped</string> <string name="already_stopped">Already stopped</string>

7
android/src/org/purplei2p/i2pd/DaemonSingleton.java

@ -33,6 +33,13 @@ public class DaemonSingleton {
} }
} }
public synchronized void startAcceptingTunnels() {
if(isStartedOkay()){
setState(State.startedOkay);
I2PD_JNI.startAcceptingTunnels();
}
}
private volatile boolean startedOkay; private volatile boolean startedOkay;
public enum State { public enum State {

70
android/src/org/purplei2p/i2pd/I2PDActivity.java

@ -13,13 +13,16 @@ import java.io.StringWriter;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import android.Manifest;
import android.app.Activity; import android.app.Activity;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
@ -27,12 +30,15 @@ import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
// For future package update checking // For future package update checking
import org.purplei2p.i2pd.BuildConfig; import org.purplei2p.i2pd.BuildConfig;
public class I2PDActivity extends Activity { public class I2PDActivity extends Activity {
private static final String TAG = "i2pdActvt"; private static final String TAG = "i2pdActvt";
private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000; public static final int GRACEFUL_DELAY_MILLIS = 10 * 60 * 1000;
private TextView textView; private TextView textView;
@ -93,6 +99,17 @@ public class I2PDActivity extends Activity {
daemon.addStateChangeListener(daemonStateUpdatedListener); daemon.addStateChangeListener(daemonStateUpdatedListener);
daemonStateUpdatedListener.daemonStateUpdate(); daemonStateUpdatedListener.daemonStateUpdate();
// request permissions
if (Build.VERSION.SDK_INT >= 23)
{
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
}
}
// set the app be foreground // set the app be foreground
doBindService(); doBindService();
@ -119,6 +136,24 @@ public class I2PDActivity extends Activity {
} }
} }
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
{
switch (requestCode)
{
case MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE:
{
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
Log.e(TAG, "Memory permission granted");
else
Log.e(TAG, "Memory permission declined");
// TODO: terminate
return;
}
default: ;
}
}
private static void cancelGracefulStop() { private static void cancelGracefulStop() {
Timer gracefulQuitTimer = getGracefulQuitTimer(); Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null) { if(gracefulQuitTimer!=null) {
@ -205,7 +240,16 @@ public class I2PDActivity extends Activity {
i2pdStop(); i2pdStop();
return true; return true;
case R.id.action_graceful_stop: case R.id.action_graceful_stop:
if (getGracefulQuitTimer()!= null)
{
item.setTitle(R.string.action_graceful_stop);
i2pdCancelGracefulStop ();
}
else
{
item.setTitle(R.string.action_cancel_graceful_stop);
i2pdGracefulStop(); i2pdGracefulStop();
}
return true; return true;
} }
@ -269,6 +313,32 @@ public class I2PDActivity extends Activity {
},"gracInit").start(); },"gracInit").start();
} }
private void i2pdCancelGracefulStop()
{
cancelGracefulStop();
Toast.makeText(this, R.string.startedOkay, Toast.LENGTH_SHORT).show();
new Thread(new Runnable()
{
@Override
public void run()
{
try
{
Log.d(TAG, "grac stopping cancel");
if(daemon.isStartedOkay())
daemon.startAcceptingTunnels();
else
i2pdStop();
}
catch(Throwable tr)
{
Log.e(TAG,"",tr);
}
}
},"gracCancel").start();
}
private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) { private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAtMillis) {
if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel(); if(gracefulQuitTimerOld!=null)gracefulQuitTimerOld.cancel();
final Timer gracefulQuitTimer = new Timer(true); final Timer gracefulQuitTimer = new Timer(true);

2
android/src/org/purplei2p/i2pd/I2PD_JNI.java

@ -12,6 +12,8 @@ public class I2PD_JNI {
public static native void stopAcceptingTunnels(); public static native void stopAcceptingTunnels();
public static native void startAcceptingTunnels();
public static native void onNetworkStateChanged(boolean isConnected); public static native void onNetworkStateChanged(boolean isConnected);
public static void loadLibraries() { public static void loadLibraries() {

2
appveyor.yml

@ -1,4 +1,4 @@
version: 2.21.{build} version: 2.22.0.{build}
pull_requests: pull_requests:
do_not_increment_build_number: true do_not_increment_build_number: true
branches: branches:

10
build/build_mingw.cmd

@ -21,6 +21,8 @@ set MSYSTEM=MINGW32
set "xSH=%WD%bash -lc" set "xSH=%WD%bash -lc"
set "FILELIST=i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates contrib/tunnels.d"
REM detecting number of processors and subtract 1. REM detecting number of processors and subtract 1.
set /a threads=%NUMBER_OF_PROCESSORS%-1 set /a threads=%NUMBER_OF_PROCESSORS%-1
@ -62,12 +64,12 @@ exit /b 0
%xSH% "make clean" >> nul %xSH% "make clean" >> nul
echo Building i2pd %tag% for win%bitness%: echo Building i2pd %tag% for win%bitness%:
echo Build AVX+AESNI... echo Build AVX+AESNI...
%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx_aesni.log 2>&1 %xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_avx_aesni_%tag%.log 2>&1
echo Build AVX... echo Build AVX...
%xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_avx.log 2>&1 %xSH% "make DEBUG=no USE_UPNP=yes USE_AVX=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_avx.zip %FILELIST% && make clean" > build/build_win%bitness%_avx_%tag%.log 2>&1
echo Build AESNI... echo Build AESNI...
%xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%_aesni.log 2>&1 %xSH% "make DEBUG=no USE_UPNP=yes USE_AESNI=1 -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw_aesni.zip %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1
echo Build without extensions... echo Build without extensions...
%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip i2pd.exe README.txt contrib/i2pd.conf contrib/tunnels.conf contrib/certificates && make clean" > build/build_win%bitness%.log 2>&1 %xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1
:EOF :EOF

11
contrib/i2pd.conf

@ -10,6 +10,11 @@
## Default: ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf ## Default: ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf
# tunconf = /var/lib/i2pd/tunnels.conf # tunconf = /var/lib/i2pd/tunnels.conf
## Tunnels config files path
## Use that path to store separated tunnels in different config files.
## Default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d
# tunnelsdir = /var/lib/i2pd/tunnels.conf.d
## Where to write pidfile (don't write by default) ## Where to write pidfile (don't write by default)
# pidfile = /var/run/i2pd.pid # pidfile = /var/run/i2pd.pid
@ -88,6 +93,8 @@ ipv6 = false
## Address and port service will listen on ## Address and port service will listen on
address = 127.0.0.1 address = 127.0.0.1
port = 7070 port = 7070
## Path to web console, default "/"
# webroot = /
## Uncomment following lines to enable Web Console authentication ## Uncomment following lines to enable Web Console authentication
# auth = true # auth = true
# user = i2pd # user = i2pd
@ -218,3 +225,7 @@ verify = true
# inbound.quantity = 3 # inbound.quantity = 3
# outbound.length = 2 # outbound.length = 2
# outbound.quantity = 3 # outbound.quantity = 3
[persist]
## Save peer profiles on disk (default: true)
# profiles = true

6
contrib/i2pd.service

@ -11,7 +11,7 @@ RuntimeDirectoryMode=0700
LogsDirectory=i2pd LogsDirectory=i2pd
LogsDirectoryMode=0700 LogsDirectoryMode=0700
Type=forking Type=forking
ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service ExecStart=/usr/sbin/i2pd --conf=/etc/i2pd/i2pd.conf --tunconf=/etc/i2pd/tunnels.conf --tunnelsdir=/etc/i2pd/tunnels.conf.d --pidfile=/var/run/i2pd/i2pd.pid --logfile=/var/log/i2pd/i2pd.log --daemon --service
ExecReload=/bin/kill -HUP $MAINPID ExecReload=/bin/kill -HUP $MAINPID
PIDFile=/var/run/i2pd/i2pd.pid PIDFile=/var/run/i2pd/i2pd.pid
### Uncomment, if auto restart needed ### Uncomment, if auto restart needed
@ -23,8 +23,10 @@ KillSignal=SIGQUIT
#KillSignal=SIGINT #KillSignal=SIGINT
#TimeoutStopSec=10m #TimeoutStopSec=10m
# If you have problems with hanging i2pd, you can try enable this # If you have problems with hanging i2pd, you can try increase this
LimitNOFILE=4096 LimitNOFILE=4096
# To enable write of coredump uncomment this
#LimitCORE=infinity
PrivateDevices=yes PrivateDevices=yes
[Install] [Install]

36
contrib/rpm/i2pd-git.spec

@ -1,7 +1,7 @@
%define git_hash %(git rev-parse HEAD | cut -c -7) %define git_hash %(git rev-parse HEAD | cut -c -7)
Name: i2pd-git Name: i2pd-git
Version: 2.21.0 Version: 2.22.0
Release: git%{git_hash}%{?dist} Release: git%{git_hash}%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd Conflicts: i2pd
@ -55,15 +55,21 @@ make %{?_smp_mflags}
%install %install
cd build cd build
%if 0%{?mageia}
cd build
%endif
chrpath -d i2pd chrpath -d i2pd
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd %{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf %{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf %{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/subscriptions.txt %{buildroot}%{_sysconfdir}/i2pd/subscriptions.txt
install -d -m 755 %{buildroot}%{_datadir}/i2pd %{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates %{__install} -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.d/README %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d/README
install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service %{__install} -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd %{__install} -D -m 644 %{_builddir}/%{name}-%{version}/debian/i2pd.1 %{buildroot}%{_mandir}/man1/i2pd.1
install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd %{__install} -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
%{__install} -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
%{__install} -d -m 755 %{buildroot}%{_datadir}/%{name}
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/%{name}/certificates
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
@ -87,16 +93,20 @@ getent passwd i2pd >/dev/null || \
%files %files
%doc LICENSE README.md %doc LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf contrib/tunnels.d
%{_sbindir}/i2pd %{_sbindir}/i2pd
%{_datadir}/i2pd/certificates
%config(noreplace) %{_sysconfdir}/i2pd/* %config(noreplace) %{_sysconfdir}/i2pd/*
/%{_unitdir}/i2pd.service %{_unitdir}/i2pd.service
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd %{_mandir}/man1/i2pd.1*
%dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd %dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd
%{_datadir}/%{name}/certificates
%{_sharedstatedir}/i2pd/certificates %{_sharedstatedir}/i2pd/certificates
%changelog %changelog
* Fri Nov 09 2018 r4sas <r4sas@i2pmail.org> - 2.22.0
- add support of tunnelsdir option
* Thu Feb 01 2018 r4sas <r4sas@i2pmail.org> - 2.18.0 * Thu Feb 01 2018 r4sas <r4sas@i2pmail.org> - 2.18.0
- Initial i2pd-git based on i2pd 2.18.0-1 spec - Initial i2pd-git based on i2pd 2.18.0-1 spec

16
contrib/rpm/i2pd.spec

@ -1,5 +1,5 @@
Name: i2pd Name: i2pd
Version: 2.21.0 Version: 2.22.0
Release: 1%{?dist} Release: 1%{?dist}
Summary: I2P router written in C++ Summary: I2P router written in C++
Conflicts: i2pd-git Conflicts: i2pd-git
@ -53,16 +53,22 @@ make %{?_smp_mflags}
%install %install
cd build cd build
%if 0%{?mageia}
cd build
%endif
chrpath -d i2pd chrpath -d i2pd
install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd install -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/i2pd.conf %{buildroot}%{_sysconfdir}/i2pd/i2pd.conf
install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf install -D -m 755 %{_builddir}/%{name}-%{version}/contrib/tunnels.conf %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf
install -d -m 755 %{buildroot}%{_datadir}/i2pd install -d -m 755 %{buildroot}%{_datadir}/i2pd
install -d -m 755 %{buildroot}%{_datadir}/i2pd/tunnels.conf.d
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates %{__cp} -r %{_builddir}/%{name}-%{version}/contrib/certificates/ %{buildroot}%{_datadir}/i2pd/certificates
%{__cp} -r %{_builddir}/%{name}-%{version}/contrib/tunnels.d/ %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service install -D -m 644 %{_builddir}/%{name}-%{version}/contrib/rpm/i2pd.service %{buildroot}%{_unitdir}/i2pd.service
install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd install -d -m 700 %{buildroot}%{_sharedstatedir}/i2pd
install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd install -d -m 700 %{buildroot}%{_localstatedir}/log/i2pd
ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates ln -s %{_datadir}/%{name}/certificates %{buildroot}%{_sharedstatedir}/i2pd/certificates
ln -s %{_datadir}/i2pd/tunnels.conf.d %{buildroot}%{_sysconfdir}/i2pd/tunnels.conf.d
%pre %pre
@ -89,6 +95,7 @@ getent passwd i2pd >/dev/null || \
%{_sbindir}/i2pd %{_sbindir}/i2pd
%{_datadir}/i2pd/certificates %{_datadir}/i2pd/certificates
%config(noreplace) %{_sysconfdir}/i2pd/* %config(noreplace) %{_sysconfdir}/i2pd/*
%config(noreplace) %{_sysconfdir}/i2pd/tunnels.conf.d/*
/%{_unitdir}/i2pd.service /%{_unitdir}/i2pd.service
%dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd %dir %attr(0700,i2pd,i2pd) %{_localstatedir}/log/i2pd
%dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd %dir %attr(0700,i2pd,i2pd) %{_sharedstatedir}/i2pd
@ -96,6 +103,13 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Fri Nov 09 2018 r4sas <r4sas@i2pmail.org> - 2.22.0
- update to 2.22.0
- add support of tunnelsdir option
* Thu Oct 22 2018 orignal <i2porignal@yandex.ru> - 2.21.1
- update to 2.21.1
* Thu Oct 4 2018 orignal <i2porignal@yandex.ru> - 2.21.0 * Thu Oct 4 2018 orignal <i2porignal@yandex.ru> - 2.21.0
- update to 2.21.0 - update to 2.21.0

7
contrib/tunnels.d/IRC-Ilita.conf

@ -0,0 +1,7 @@
#[IRC-ILITA]
#type = client
#address = 127.0.0.1
#port = 6669
#destination = irc.ilita.i2p
#destinationport = 6667
#keys = irc-keys.dat

7
contrib/tunnels.d/IRC-Irc2P.conf

@ -0,0 +1,7 @@
#[IRC-IRC2P]
#type = client
#address = 127.0.0.1
#port = 6668
#destination = irc.postman.i2p
#destinationport = 6667
#keys = irc-keys.dat

4
contrib/tunnels.d/README

@ -0,0 +1,4 @@
# In that directory you can store separated config files for every tunnel.
# Please read documentation for more info.
#
# You can find examples in /usr/share/doc/i2pd/tunnels.d directory

18
daemon/Daemon.cpp

@ -23,6 +23,7 @@
#include "ClientContext.h" #include "ClientContext.h"
#include "Crypto.h" #include "Crypto.h"
#include "UPnP.h" #include "UPnP.h"
#include "Timestamp.h"
#include "util.h" #include "util.h"
#include "Event.h" #include "Event.h"
@ -41,6 +42,7 @@ namespace i2p
std::unique_ptr<i2p::http::HTTPServer> httpServer; std::unique_ptr<i2p::http::HTTPServer> httpServer;
std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService; std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;
std::unique_ptr<i2p::transport::UPnP> UPnP; std::unique_ptr<i2p::transport::UPnP> UPnP;
std::unique_ptr<i2p::util::NTPTimeSync> m_NTPSync;
#ifdef WITH_EVENTS #ifdef WITH_EVENTS
std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer; std::unique_ptr<i2p::event::WebsocketServer> m_WebsocketServer;
#endif #endif
@ -282,6 +284,13 @@ namespace i2p
d.UPnP->Start (); d.UPnP->Start ();
} }
bool nettime; i2p::config::GetOption("nettime.enabled", nettime);
if (nettime)
{
d.m_NTPSync = std::unique_ptr<i2p::util::NTPTimeSync>(new i2p::util::NTPTimeSync);
d.m_NTPSync->Start ();
}
bool ntcp; i2p::config::GetOption("ntcp", ntcp); bool ntcp; i2p::config::GetOption("ntcp", ntcp);
bool ssu; i2p::config::GetOption("ssu", ssu); bool ssu; i2p::config::GetOption("ssu", ssu);
LogPrint(eLogInfo, "Daemon: starting Transports"); LogPrint(eLogInfo, "Daemon: starting Transports");
@ -351,11 +360,18 @@ namespace i2p
LogPrint(eLogInfo, "Daemon: stopping Tunnels"); LogPrint(eLogInfo, "Daemon: stopping Tunnels");
i2p::tunnel::tunnels.Stop(); i2p::tunnel::tunnels.Stop();
if (d.UPnP) { if (d.UPnP)
{
d.UPnP->Stop (); d.UPnP->Stop ();
d.UPnP = nullptr; d.UPnP = nullptr;
} }
if (d.m_NTPSync)
{
d.m_NTPSync->Stop ();
d.m_NTPSync = nullptr;
}
LogPrint(eLogInfo, "Daemon: stopping Transports"); LogPrint(eLogInfo, "Daemon: stopping Transports");
i2p::transport::transports.Stop(); i2p::transport::transports.Stop();
LogPrint(eLogInfo, "Daemon: stopping NetDB"); LogPrint(eLogInfo, "Daemon: stopping NetDB");

77
daemon/HTTPServer.cpp

@ -155,6 +155,8 @@ namespace http {
static void ShowPageHead (std::stringstream& s) static void ShowPageHead (std::stringstream& s)
{ {
std::string webroot;
i2p::config::GetOption("http.webroot", webroot);
s << s <<
"<!DOCTYPE html>\r\n" "<!DOCTYPE html>\r\n"
"<html lang=\"en\">\r\n" /* TODO: Add support for locale */ "<html lang=\"en\">\r\n" /* TODO: Add support for locale */
@ -173,16 +175,16 @@ namespace http {
"<div class=header><b>i2pd</b> webconsole</div>\r\n" "<div class=header><b>i2pd</b> webconsole</div>\r\n"
"<div class=wrapper>\r\n" "<div class=wrapper>\r\n"
"<div class=left>\r\n" "<div class=left>\r\n"
" <a href=\"/\">Main page</a><br>\r\n<br>\r\n" " <a href=\"" << webroot << "\">Main page</a><br>\r\n<br>\r\n"
" <a href=\"/?page=" << HTTP_PAGE_COMMANDS << "\">Router commands</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_COMMANDS << "\">Router commands</a><br>\r\n"
" <a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATIONS << "\">Local destinations</a><br>\r\n"
" <a href=\"/?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_LEASESETS << "\">LeaseSets</a><br>\r\n"
" <a href=\"/?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TUNNELS << "\">Tunnels</a><br>\r\n"
" <a href=\"/?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">Transit tunnels</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSIT_TUNNELS << "\">Transit tunnels</a><br>\r\n"
" <a href=\"/?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n" " <a href=\"" << webroot << "?page=" << HTTP_PAGE_TRANSPORTS << "\">Transports</a><br>\r\n"
" <a href=\"/?page=" << HTTP_PAGE_I2P_TUNNELS << "\">I2P tunnels</a><br>\r\n"; " <a href=\"" << webroot << "?page=" << HTTP_PAGE_I2P_TUNNELS << "\">I2P tunnels</a><br>\r\n";
if (i2p::client::context.GetSAMBridge ()) if (i2p::client::context.GetSAMBridge ())
s << " <a href=\"/?page=" << HTTP_PAGE_SAM_SESSIONS << "\">SAM sessions</a><br>\r\n"; s << " <a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSIONS << "\">SAM sessions</a><br>\r\n";
s << s <<
"</div>\r\n" "</div>\r\n"
"<div class=right>"; "<div class=right>";
@ -321,11 +323,12 @@ namespace http {
void ShowLocalDestinations (std::stringstream& s) void ShowLocalDestinations (std::stringstream& s)
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
s << "<b>Local Destinations:</b><br>\r\n<br>\r\n"; s << "<b>Local Destinations:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetDestinations ()) for (auto& it: i2p::client::context.GetDestinations ())
{ {
auto ident = it.second->GetIdentHash (); auto ident = it.second->GetIdentHash ();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n" << std::endl;
} }
@ -340,7 +343,7 @@ namespace http {
{ {
auto ident = dest->GetIdentHash (); auto ident = dest->GetIdentHash ();
auto& name = dest->GetNickname (); auto& name = dest->GetNickname ();
s << "<a href=\"/?page=" << HTTP_PAGE_I2CP_LOCAL_DESTINATION << "&i2cp_id=" << it.first << "\">[ "; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_I2CP_LOCAL_DESTINATION << "&i2cp_id=" << it.first << "\">[ ";
s << name << " ]</a> &#8660; " << i2p::client::context.GetAddressBook ().ToAddress(ident) <<"<br>\r\n" << std::endl; s << name << " ]</a> &#8660; " << i2p::client::context.GetAddressBook ().ToAddress(ident) <<"<br>\r\n" << std::endl;
} }
} }
@ -510,33 +513,34 @@ namespace http {
static void ShowCommands (std::stringstream& s, uint32_t token) static void ShowCommands (std::stringstream& s, uint32_t token)
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
/* commands */ /* commands */
s << "<b>Router Commands</b><br>\r\n<br>\r\n"; s << "<b>Router Commands</b><br>\r\n<br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_RUN_PEER_TEST << "&token=" << token << "\">Run peer test</a><br>\r\n";
//s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n"; //s << " <a href=\"/?cmd=" << HTTP_COMMAND_RELOAD_CONFIG << "\">Reload config</a><br>\r\n";
if (i2p::context.AcceptsTunnels ()) if (i2p::context.AcceptsTunnels ())
s << " <a href=\"/?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">Decline transit tunnels</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_DISABLE_TRANSIT << "&token=" << token << "\">Decline transit tunnels</a><br>\r\n";
else else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_ENABLE_TRANSIT << "&token=" << token << "\">Accept transit tunnels</a><br>\r\n";
#if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY))
if (Daemon.gracefulShutdownInterval) if (Daemon.gracefulShutdownInterval)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
else else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Start graceful shutdown</a><br>\r\n";
#elif defined(WIN32_APP) #elif defined(WIN32_APP)
if (i2p::util::DaemonWin32::Instance().isGraceful) if (i2p::util::DaemonWin32::Instance().isGraceful)
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_CANCEL << "&token=" << token << "\">Cancel graceful shutdown</a><br>";
else else
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_START << "&token=" << token << "\">Graceful shutdown</a><br>\r\n";
#endif #endif
s << " <a href=\"/?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_SHUTDOWN_NOW << "&token=" << token << "\">Force shutdown</a><br>\r\n";
s << "<br>\r\n<b>Logging level</b><br>\r\n"; s << "<br>\r\n<b>Logging level</b><br>\r\n";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\">[none]</a> "; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=none&token=" << token << "\">[none]</a> ";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> "; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=error&token=" << token << "\">[error]</a> ";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\">[warn]</a> "; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=warn&token=" << token << "\">[warn]</a> ";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\">[info]</a> "; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=info&token=" << token << "\">[info]</a> ";
s << " <a href=\"/?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\">[debug]</a><br>\r\n"; s << " <a href=\"" << webroot << "?cmd=" << HTTP_COMMAND_LOGLEVEL << "&level=debug&token=" << token << "\">[debug]</a><br>\r\n";
} }
void ShowTransitTunnels (std::stringstream& s) void ShowTransitTunnels (std::stringstream& s)
@ -653,6 +657,7 @@ namespace http {
void ShowSAMSessions (std::stringstream& s) void ShowSAMSessions (std::stringstream& s)
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
auto sam = i2p::client::context.GetSAMBridge (); auto sam = i2p::client::context.GetSAMBridge ();
if (!sam) { if (!sam) {
ShowError(s, "SAM disabled"); ShowError(s, "SAM disabled");
@ -662,13 +667,14 @@ namespace http {
for (auto& it: sam->GetSessions ()) for (auto& it: sam->GetSessions ())
{ {
auto& name = it.second->localDestination->GetNickname (); auto& name = it.second->localDestination->GetNickname ();
s << "<a href=\"/?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_SAM_SESSION << "&sam_id=" << it.first << "\">";
s << name << " (" << it.first << ")</a><br>\r\n" << std::endl; s << name << " (" << it.first << ")</a><br>\r\n" << std::endl;
} }
} }
static void ShowSAMSession (std::stringstream& s, const std::string& id) static void ShowSAMSession (std::stringstream& s, const std::string& id)
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
s << "<b>SAM Session:</b><br>\r\n<br>\r\n"; s << "<b>SAM Session:</b><br>\r\n<br>\r\n";
auto sam = i2p::client::context.GetSAMBridge (); auto sam = i2p::client::context.GetSAMBridge ();
if (!sam) { if (!sam) {
@ -681,7 +687,7 @@ namespace http {
return; return;
} }
auto& ident = session->localDestination->GetIdentHash(); auto& ident = session->localDestination->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n"; s << i2p::client::context.GetAddressBook ().ToAddress(ident) << "</a><br>\r\n";
s << "<br>\r\n"; s << "<br>\r\n";
s << "<b>Streams:</b><br>\r\n"; s << "<b>Streams:</b><br>\r\n";
@ -701,11 +707,12 @@ namespace http {
void ShowI2PTunnels (std::stringstream& s) void ShowI2PTunnels (std::stringstream& s)
{ {
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n"; s << "<b>Client Tunnels:</b><br>\r\n<br>\r\n";
for (auto& it: i2p::client::context.GetClientTunnels ()) for (auto& it: i2p::client::context.GetClientTunnels ())
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; "; s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -714,7 +721,7 @@ namespace http {
if (httpProxy) if (httpProxy)
{ {
auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash(); auto& ident = httpProxy->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "HTTP Proxy" << "</a> &#8656; "; s << "HTTP Proxy" << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -723,7 +730,7 @@ namespace http {
if (socksProxy) if (socksProxy)
{ {
auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash(); auto& ident = socksProxy->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << "SOCKS Proxy" << "</a> &#8656; "; s << "SOCKS Proxy" << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -734,7 +741,7 @@ namespace http {
for (auto& it: serverTunnels) for (auto& it: serverTunnels)
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8658; "; s << it.second->GetName () << "</a> &#8658; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << ":" << it.second->GetLocalPort (); s << ":" << it.second->GetLocalPort ();
@ -748,7 +755,7 @@ namespace http {
for (auto& it: clientForwards) for (auto& it: clientForwards)
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; "; s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -761,7 +768,7 @@ namespace http {
for (auto& it: serverForwards) for (auto& it: serverForwards)
{ {
auto& ident = it.second->GetLocalDestination ()->GetIdentHash(); auto& ident = it.second->GetLocalDestination ()->GetIdentHash();
s << "<a href=\"/?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">"; s << "<a href=\"" << webroot << "?page=" << HTTP_PAGE_LOCAL_DESTINATION << "&b32=" << ident.ToBase32 () << "\">";
s << it.second->GetName () << "</a> &#8656; "; s << it.second->GetName () << "</a> &#8656; ";
s << i2p::client::context.GetAddressBook ().ToAddress(ident); s << i2p::client::context.GetAddressBook ().ToAddress(ident);
s << "<br>\r\n"<< std::endl; s << "<br>\r\n"<< std::endl;
@ -1025,10 +1032,12 @@ namespace http {
ShowError(s, "Unknown command: " + cmd); ShowError(s, "Unknown command: " + cmd);
return; return;
} }
std::string webroot; i2p::config::GetOption("http.webroot", webroot);
std::string redirect = "5; url=" + webroot + "?page=commands";
s << "<b>SUCCESS</b>:&nbsp;Command accepted<br><br>\r\n"; s << "<b>SUCCESS</b>:&nbsp;Command accepted<br><br>\r\n";
s << "<a href=\"/?page=commands\">Back to commands list</a><br>\r\n"; s << "<a href=\"" << webroot << "?page=commands\">Back to commands list</a><br>\r\n";
s << "<p>You will be redirected in 5 seconds</b>"; s << "<p>You will be redirected in 5 seconds</b>";
res.add_header("Refresh", "5; url=/?page=commands"); res.add_header("Refresh", redirect.c_str());
} }
void HTTPConnection::SendReply (HTTPRes& reply, std::string& content) void HTTPConnection::SendReply (HTTPRes& reply, std::string& content)

4
debian/.gitignore vendored

@ -1,9 +1,9 @@
debhelper-build-stamp
files files
i2pd-dbg.substvars i2pd-dbg.substvars
i2pd-dbg/
i2pd.postinst.debhelper i2pd.postinst.debhelper
i2pd.postrm.debhelper i2pd.postrm.debhelper
i2pd.prerm.debhelper i2pd.prerm.debhelper
i2pd.substvars i2pd.substvars
i2pd/ i2pd/
i2pd-dbg/

15
debian/changelog vendored

@ -1,3 +1,18 @@
i2pd (2.22.0-1) unstable; urgency=medium
* updated to version 2.22.0/0.9.37
* update manpage (1)
* update links, install files to support tunnelsdir option
* renamed and updated patch (#1210)
-- r4sas <r4sas@i2pmail.org> Fri, 09 Nov 2018 02:00:00 +0000
i2pd (2.21.1-1) unstable; urgency=medium
* updated to version 2.21.1
-- orignal <orignal@i2pmail.org> Thu, 22 Oct 2018 16:00:00 +0000
i2pd (2.21.0-1) unstable; urgency=medium i2pd (2.21.0-1) unstable; urgency=medium
* updated to version 2.21.0/0.9.37 * updated to version 2.21.0/0.9.37

1
debian/docs vendored

@ -2,3 +2,4 @@ README.md
contrib/i2pd.conf contrib/i2pd.conf
contrib/subscriptions.txt contrib/subscriptions.txt
contrib/tunnels.conf contrib/tunnels.conf
contrib/tunnels.d

3
debian/i2pd.1 vendored

@ -45,6 +45,9 @@ Log messages with full CLF-formatted date and time (\fIdisabled\fR by default)
\fB\-\-datadir=\fR \fB\-\-datadir=\fR
Path to storage of i2pd data (RI, keys, peer profiles, ...) Path to storage of i2pd data (RI, keys, peer profiles, ...)
.TP .TP
\fB\-\-tunnelsdir=\fR
Path to tunnels configuration files (default: \fI~/.i2pd/tunnels.d\fR or \fI/var/lib/i2pd/tunnels.d\fR)
.TP
\fB\-\-host=\fR \fB\-\-host=\fR
The external IP address The external IP address
.TP .TP

3
debian/i2pd.init vendored

@ -18,6 +18,7 @@ DAEMON_OPTS="" # Arguments to run the daemon with
PIDFILE=/var/run/$NAME/$NAME.pid PIDFILE=/var/run/$NAME/$NAME.pid
I2PCONF=/etc/$NAME/i2pd.conf I2PCONF=/etc/$NAME/i2pd.conf
TUNCONF=/etc/$NAME/tunnels.conf TUNCONF=/etc/$NAME/tunnels.conf
TUNDIR=/etc/$NAME/tunnels.conf.d
LOGFILE=/var/log/$NAME/$NAME.log LOGFILE=/var/log/$NAME/$NAME.log
USER="i2pd" USER="i2pd"
@ -53,7 +54,7 @@ do_start()
|| return 1 || return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \ start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --chuid "$USER" -- \
--service --daemon --log=file --logfile=$LOGFILE --conf=$I2PCONF --tunconf=$TUNCONF \ --service --daemon --log=file --logfile=$LOGFILE --conf=$I2PCONF --tunconf=$TUNCONF \
--pidfile=$PIDFILE $DAEMON_OPTS > /dev/null 2>&1 \ --tunnelsdir=$TUNDIR --pidfile=$PIDFILE $DAEMON_OPTS > /dev/null 2>&1 \
|| return 2 || return 2
return $? return $?
} }

1
debian/i2pd.install vendored

@ -3,4 +3,5 @@ contrib/i2pd.conf etc/i2pd/
contrib/tunnels.conf etc/i2pd/ contrib/tunnels.conf etc/i2pd/
contrib/subscriptions.txt etc/i2pd/ contrib/subscriptions.txt etc/i2pd/
contrib/certificates/ usr/share/i2pd/ contrib/certificates/ usr/share/i2pd/
contrib/tunnels.d/README etc/i2pd/tunnels.conf.d/
contrib/apparmor/usr.sbin.i2pd etc/apparmor.d contrib/apparmor/usr.sbin.i2pd etc/apparmor.d

1
debian/i2pd.links vendored

@ -1,4 +1,5 @@
etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf etc/i2pd/i2pd.conf var/lib/i2pd/i2pd.conf
etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.conf etc/i2pd/tunnels.conf var/lib/i2pd/tunnels.conf
etc/i2pd/subscriptions.txt var/lib/i2pd/subscriptions.txt etc/i2pd/subscriptions.txt var/lib/i2pd/subscriptions.txt
etc/i2pd/tunnels.conf.d var/lib/i2pd/tunnels.d
usr/share/i2pd/certificates var/lib/i2pd/certificates usr/share/i2pd/certificates var/lib/i2pd/certificates

3
debian/i2pd.openrc vendored

@ -4,10 +4,11 @@ pidfile="/var/run/i2pd/i2pd.pid"
logfile="/var/log/i2pd/i2pd.log" logfile="/var/log/i2pd/i2pd.log"
mainconf="/etc/i2pd/i2pd.conf" mainconf="/etc/i2pd/i2pd.conf"
tunconf="/etc/i2pd/tunnels.conf" tunconf="/etc/i2pd/tunnels.conf"
tundir="/etc/i2pd/tunnels.conf.d"
name="i2pd" name="i2pd"
command="/usr/sbin/i2pd" command="/usr/sbin/i2pd"
command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf --pidfile=$pidfile" command_args="--service --daemon --log=file --logfile=$logfile --conf=$mainconf --tunconf=$tunconf --tunnelsdir=$tundir --pidfile=$pidfile"
description="i2p router written in C++" description="i2p router written in C++"
required_dirs="/var/lib/i2pd" required_dirs="/var/lib/i2pd"
required_files="$mainconf" required_files="$mainconf"

6
debian/patches/fix-#1210 → debian/patches/02-fix-1210.patch vendored

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

2
debian/patches/series vendored

@ -1,2 +1,2 @@
01-tune-build-opts.patch 01-tune-build-opts.patch
fix-#1210 02-fix-1210.patch

4
libi2pd/ChaCha20.cpp

@ -7,6 +7,8 @@
Kovri go write your own code Kovri go write your own code
*/ */
#if LEGACY_OPENSSL
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
@ -145,3 +147,5 @@ void chacha20(uint8_t * buf, size_t sz, const uint8_t * nonce, const uint8_t * k
} }
} }
#endif

3
libi2pd/ChaCha20.h

@ -9,7 +9,9 @@
#define LIBI2PD_CHACHA20_H #define LIBI2PD_CHACHA20_H
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include "Crypto.h"
#if LEGACY_OPENSSL
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
@ -22,5 +24,6 @@ namespace crypto
} }
} }
#endif
#endif #endif

38
libi2pd/Config.cpp

@ -32,6 +32,7 @@ namespace config {
options_description general("General options"); options_description general("General options");
general.add_options() general.add_options()
("help", "Show this message") ("help", "Show this message")
("version", "Show i2pd version")
("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)") ("conf", value<std::string>()->default_value(""), "Path to main i2pd config file (default: try ~/.i2pd/i2pd.conf or /var/lib/i2pd/i2pd.conf)")
("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)") ("tunconf", value<std::string>()->default_value(""), "Path to config with tunnels list and options (default: try ~/.i2pd/tunnels.conf or /var/lib/i2pd/tunnels.conf)")
("tunnelsdir", value<std::string>()->default_value(""), "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d") ("tunnelsdir", value<std::string>()->default_value(""), "Path to extra tunnels' configs folder (default: ~/.i2pd/tunnels.d or /var/lib/i2pd/tunnels.d")
@ -87,6 +88,7 @@ namespace config {
("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)") ("http.pass", value<std::string>()->default_value(""), "Password for basic auth (default: random, see logs)")
("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI") ("http.strictheaders", value<bool>()->default_value(true), "Enable strict host checking on WebUI")
("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI") ("http.hostname", value<std::string>()->default_value("localhost"), "Expected hostname for WebUI")
("http.webroot", value<std::string>()->default_value("/"), "WebUI root path (default: / )")
; ;
options_description httpproxy("HTTP Proxy options"); options_description httpproxy("HTTP Proxy options");
@ -239,6 +241,23 @@ namespace config {
("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)") ("ntcp2.port", value<uint16_t>()->default_value(0), "Port to listen for incoming NTCP2 connections (default: auto)")
; ;
options_description nettime("Time sync options");
nettime.add_options()
("nettime.enabled", value<bool>()->default_value(false), "Disable time sync (default: disabled)")
("nettime.ntpservers", value<std::string>()->default_value(
"0.pool.ntp.org,"
"1.pool.ntp.org,"
"2.pool.ntp.org,"
"3.pool.ntp.org"
), "Comma separated list of NTCP servers")
("nettime.ntpsyncinterval", value<int>()->default_value(72), "NTP sync interval in hours (default: 72)")
;
options_description persist("Network information persisting options");
persist.add_options()
("persist.profiles", value<bool>()->default_value(true), "Persist peer profiles (default: true)")
;
m_OptionsDesc m_OptionsDesc
.add(general) .add(general)
.add(limits) .add(limits)
@ -257,6 +276,8 @@ namespace config {
.add(websocket) .add(websocket)
.add(exploratory) .add(exploratory)
.add(ntcp2) .add(ntcp2)
.add(nettime)
.add(persist)
; ;
} }
@ -284,6 +305,23 @@ namespace config {
std::cout << m_OptionsDesc; std::cout << m_OptionsDesc;
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
else if (m_Options.count("version"))
{
std::cout << "i2pd version " << I2PD_VERSION << " (" << I2P_VERSION << ")" << std::endl;
std::cout << "Boost version "
<< BOOST_VERSION / 100000 << "." // maj. version
<< BOOST_VERSION / 100 % 1000 << "." // min. version
<< BOOST_VERSION % 100 // patch version
<< std::endl;
#if defined(OPENSSL_VERSION_TEXT)
std::cout << OPENSSL_VERSION_TEXT << std::endl;
#endif
#if defined(LIBRESSL_VERSION_TEXT)
std::cout << LIBRESSL_VERSION_TEXT << std::endl;
#endif
exit(EXIT_SUCCESS);
}
} }
void ParseConfig(const std::string& path) void ParseConfig(const std::string& path)

10
libi2pd/Crypto.cpp

@ -341,6 +341,16 @@ namespace crypto
#endif #endif
} }
void X25519Keys::GetPrivateKey (uint8_t * priv) const
{
#if OPENSSL_X25519
size_t len = 32;
EVP_PKEY_get_raw_private_key (m_Pkey, priv, &len);
#else
memcpy (priv, m_PrivateKey, 32);
#endif
}
// ElGamal // ElGamal
void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding) void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, uint8_t * encrypted, BN_CTX * ctx, bool zeroPadding)
{ {

24
libi2pd/Crypto.h

@ -72,6 +72,7 @@ namespace crypto
void GenerateKeys (); void GenerateKeys ();
const uint8_t * GetPublicKey () const { return m_PublicKey; }; const uint8_t * GetPublicKey () const { return m_PublicKey; };
void GetPrivateKey (uint8_t * priv) const;
void Agree (const uint8_t * pub, uint8_t * shared); void Agree (const uint8_t * pub, uint8_t * shared);
private: private:
@ -124,10 +125,31 @@ namespace crypto
else else
#endif #endif
{ {
// TODO: implement it better #if defined(__SSE__) // SSE
__asm__
(
"movups (%[buf]), %%xmm0 \n"
"movups (%[other]), %%xmm1 \n"
"pxor %%xmm1, %%xmm0 \n"
"movups %%xmm0, (%[buf]) \n"
:
: [buf]"r"(buf), [other]"r"(other.buf)
: "%xmm0", "%xmm1", "memory"
);
#else
if (!(((size_t)buf | (size_t)other.buf) & 0x03)) // multiple of 4 ?
{
// we are good to cast to uint32_t *
for (int i = 0; i < 4; i++)
((uint32_t *)buf)[i] ^= ((uint32_t *)other.buf)[i];
}
else
{
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
buf[i] ^= other.buf[i]; buf[i] ^= other.buf[i];
} }
#endif
}
} }
}; };

2
libi2pd/Ed25519.cpp

@ -411,6 +411,7 @@ namespace crypto
} }
} }
#if !OPENSSL_X25519
BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const BIGNUM * Ed25519::ScalarMul (const BIGNUM * u, const BIGNUM * k, BN_CTX * ctx) const
{ {
BN_CTX_start (ctx); BN_CTX_start (ctx);
@ -488,6 +489,7 @@ namespace crypto
EncodeBN (q1, buf, 32); EncodeBN (q1, buf, 32);
BN_free (p1); BN_free (n); BN_free (q1); BN_free (p1); BN_free (n); BN_free (q1);
} }
#endif
void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey) void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey)
{ {

5
libi2pd/Ed25519.h

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include <openssl/bn.h> #include <openssl/bn.h>
#include "Crypto.h"
namespace i2p namespace i2p
{ {
@ -75,8 +76,10 @@ namespace crypto
EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const; EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const;
EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const; EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const;
void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const; void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const;
#if !OPENSSL_X25519
void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519 void ScalarMul (const uint8_t * p, const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; // p is point, e is number for x25519
void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const; void ScalarMulB (const uint8_t * e, uint8_t * buf, BN_CTX * ctx) const;
#endif
bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const; bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const;
void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const; void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, uint8_t * signature) const;
@ -100,8 +103,10 @@ namespace crypto
BIGNUM * DecodeBN (const uint8_t * buf) const; BIGNUM * DecodeBN (const uint8_t * buf) const;
void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const; void EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const;
#if !OPENSSL_X25519
// for x25519 // for x25519
BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const; BIGNUM * ScalarMul (const BIGNUM * p, const BIGNUM * e, BN_CTX * ctx) const;
#endif
private: private:

1
libi2pd/I2NPProtocol.h

@ -75,6 +75,7 @@ namespace i2p
enum I2NPMessageType enum I2NPMessageType
{ {
eI2NPDummyMsg = 0,
eI2NPDatabaseStore = 1, eI2NPDatabaseStore = 1,
eI2NPDatabaseLookup = 2, eI2NPDatabaseLookup = 2,
eI2NPDatabaseSearchReply = 3, eI2NPDatabaseSearchReply = 3,

122
libi2pd/NTCP2.cpp

@ -40,7 +40,7 @@ namespace transport
delete[] m_SessionConfirmedBuffer; delete[] m_SessionConfirmedBuffer;
} }
void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived) void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial)
{ {
// temp_key = HMAC-SHA256(ck, input_key_material) // temp_key = HMAC-SHA256(ck, input_key_material)
uint8_t tempKey[32]; unsigned int len; uint8_t tempKey[32]; unsigned int len;
@ -50,7 +50,16 @@ namespace transport
HMAC(EVP_sha256(), tempKey, 32, one, 1, m_CK, &len); HMAC(EVP_sha256(), tempKey, 32, one, 1, m_CK, &len);
// derived = HMAC-SHA256(temp_key, ck || byte(0x02)) // derived = HMAC-SHA256(temp_key, ck || byte(0x02))
m_CK[32] = 2; m_CK[32] = 2;
HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, derived, &len); HMAC(EVP_sha256(), tempKey, 32, m_CK, 33, m_K, &len);
}
void NTCP2Establisher::MixHash (const uint8_t * buf, size_t len)
{
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, buf, len);
SHA256_Final (m_H, &ctx);
} }
void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub) void NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub)
@ -73,14 +82,11 @@ namespace transport
SHA256_Update (&ctx, rs, 32); SHA256_Update (&ctx, rs, 32);
SHA256_Final (m_H, &ctx); SHA256_Final (m_H, &ctx);
// h = SHA256(h || epub) // h = SHA256(h || epub)
SHA256_Init (&ctx); MixHash (epub, 32);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, epub, 32);
SHA256_Final (m_H, &ctx);
// x25519 between pub and priv // x25519 between pub and priv
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
priv.Agree (pub, inputKeyMaterial); priv.Agree (pub, inputKeyMaterial);
MixKey (inputKeyMaterial, m_K); MixKey (inputKeyMaterial);
} }
void NTCP2Establisher::KDF1Alice () void NTCP2Establisher::KDF1Alice ()
@ -95,30 +101,18 @@ namespace transport
void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub) void NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub)
{ {
SHA256_CTX ctx; MixHash (sessionRequest + 32, 32); // encrypted payload
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, sessionRequest + 32, 32); // encrypted payload
SHA256_Final (m_H, &ctx);
int paddingLength = sessionRequestLen - 64; int paddingLength = sessionRequestLen - 64;
if (paddingLength > 0) if (paddingLength > 0)
{ MixHash (sessionRequest + 64, paddingLength);
SHA256_Init (&ctx); MixHash (epub, 32);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, sessionRequest + 64, paddingLength);
SHA256_Final (m_H, &ctx);
}
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, epub, 32);
SHA256_Final (m_H, &ctx);
// x25519 between remote pub and ephemaral priv // x25519 between remote pub and ephemaral priv
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
m_EphemeralKeys.Agree (GetRemotePub (), inputKeyMaterial); m_EphemeralKeys.Agree (GetRemotePub (), inputKeyMaterial);
MixKey (inputKeyMaterial, m_K); MixKey (inputKeyMaterial);
} }
void NTCP2Establisher::KDF2Alice () void NTCP2Establisher::KDF2Alice ()
@ -135,14 +129,14 @@ namespace transport
{ {
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial); i2p::context.GetStaticKeys ().Agree (GetRemotePub (), inputKeyMaterial);
MixKey (inputKeyMaterial, m_K); MixKey (inputKeyMaterial);
} }
void NTCP2Establisher::KDF3Bob () void NTCP2Establisher::KDF3Bob ()
{ {
uint8_t inputKeyMaterial[32]; uint8_t inputKeyMaterial[32];
m_EphemeralKeys.Agree (m_RemoteStaticKey, inputKeyMaterial); m_EphemeralKeys.Agree (m_RemoteStaticKey, inputKeyMaterial);
MixKey (inputKeyMaterial, m_K); MixKey (inputKeyMaterial);
} }
void NTCP2Establisher::CreateEphemeralKey () void NTCP2Establisher::CreateEphemeralKey ()
@ -170,8 +164,17 @@ namespace transport
memset (options, 0, 16); memset (options, 0, 16);
options[1] = 2; // ver options[1] = 2; // ver
htobe16buf (options + 2, paddingLength); // padLen htobe16buf (options + 2, paddingLength); // padLen
m3p2Len = i2p::context.GetRouterInfo ().GetBufferLen () + 20; // (RI header + RI + MAC for now) TODO: implement options // m3p2Len
auto bufLen = i2p::context.GetRouterInfo ().GetBufferLen ();
m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
htobe16buf (options + 4, m3p2Len); htobe16buf (options + 4, m3p2Len);
// fill m3p2 payload (RouterInfo block)
m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; // m3p1 is 48 bytes
uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
m3p2[0] = eNTCP2BlkRouterInfo; // block
htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI
m3p2[3] = 0; // flag
memcpy (m3p2 + 4, i2p::context.GetRouterInfo ().GetBuffer (), bufLen); // TODO: own RI should be protected by mutex
// 2 bytes reserved // 2 bytes reserved
htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA htobe32buf (options + 8, i2p::util::GetSecondsSinceEpoch ()); // tsA
// 4 bytes reserved // 4 bytes reserved
@ -208,23 +211,12 @@ namespace transport
void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce) void NTCP2Establisher::CreateSessionConfirmedMessagePart1 (const uint8_t * nonce)
{ {
// update AD // update AD
SHA256_CTX ctx; MixHash (m_SessionCreatedBuffer + 32, 32); // encrypted payload
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, m_SessionCreatedBuffer + 32, 32); // encrypted payload
SHA256_Final (m_H, &ctx);
int paddingLength = m_SessionCreatedBufferLen - 64; int paddingLength = m_SessionCreatedBufferLen - 64;
if (paddingLength > 0) if (paddingLength > 0)
{ MixHash (m_SessionCreatedBuffer + 64, paddingLength);
SHA256_CTX ctx1;
SHA256_Init (&ctx1);
SHA256_Update (&ctx1, m_H, 32);
SHA256_Update (&ctx1, m_SessionCreatedBuffer + 64, paddingLength);
SHA256_Final (m_H, &ctx1);
}
// part1 48 bytes // part1 48 bytes
m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48];
i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, m_H, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetNTCP2StaticPublicKey (), 32, m_H, 32, m_K, nonce, m_SessionConfirmedBuffer, 48, true); // encrypt
} }
@ -232,24 +224,13 @@ namespace transport
{ {
// part 2 // part 2
// update AD again // update AD again
SHA256_CTX ctx; MixHash (m_SessionConfirmedBuffer, 48);
SHA256_Init (&ctx); // encrypt m3p2, it must be filled in SessionRequest
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48);
SHA256_Final (m_H, &ctx);
// fill and encrypt
uint8_t * buf = m_SessionConfirmedBuffer + 48;
buf[0] = eNTCP2BlkRouterInfo; // block
htobe16buf (buf + 1, i2p::context.GetRouterInfo ().GetBufferLen () + 1); // flag + RI
buf[3] = 0; // flag
memcpy (buf + 4, i2p::context.GetRouterInfo ().GetBuffer (), i2p::context.GetRouterInfo ().GetBufferLen ());
KDF3Alice (); KDF3Alice ();
i2p::crypto::AEADChaCha20Poly1305 (buf, m3p2Len - 16, m_H, 32, m_K, nonce, buf, m3p2Len, true); // encrypt uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
i2p::crypto::AEADChaCha20Poly1305 (m3p2, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2, m3p2Len, true); // encrypt
// update h again // update h again
SHA256_Init (&ctx); MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext)
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, buf, m3p2Len);
SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext)
} }
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen) bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen)
@ -339,21 +320,11 @@ namespace transport
bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce) bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce)
{ {
// update AD // update AD
SHA256_CTX ctx; MixHash (m_SessionCreatedBuffer + 32, 32); // encrypted payload
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, m_SessionCreatedBuffer + 32, 32); // encrypted payload
SHA256_Final (m_H, &ctx);
int paddingLength = m_SessionCreatedBufferLen - 64; int paddingLength = m_SessionCreatedBufferLen - 64;
if (paddingLength > 0) if (paddingLength > 0)
{ MixHash (m_SessionCreatedBuffer + 64, paddingLength);
SHA256_CTX ctx1;
SHA256_Init (&ctx1);
SHA256_Update (&ctx1, m_H, 32);
SHA256_Update (&ctx1, m_SessionCreatedBuffer + 64, paddingLength);
SHA256_Final (m_H, &ctx1);
}
if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, m_H, 32, m_K, nonce, m_RemoteStaticKey, 32, false)) // decrypt S if (!i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer, 32, m_H, 32, m_K, nonce, m_RemoteStaticKey, 32, false)) // decrypt S
{ {
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed "); LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
@ -365,11 +336,7 @@ namespace transport
bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf) bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf)
{ {
// update AD again // update AD again
SHA256_CTX ctx; MixHash (m_SessionConfirmedBuffer, 48);
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48);
SHA256_Final (m_H, &ctx);
KDF3Bob (); KDF3Bob ();
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
@ -728,8 +695,7 @@ namespace transport
SendTerminationAndTerminate (eNTCP2IncorrectSParameter); SendTerminationAndTerminate (eNTCP2IncorrectSParameter);
return; return;
} }
i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, buf.data () + 3, size)); // TODO: should insert ri and not parse it twice
i2p::data::netdb.AddRouterInfo (buf.data () + 4, size - 1); // TODO: should insert ri and not parse it twice
// TODO: process options // TODO: process options
// ready to communicate // ready to communicate
@ -894,7 +860,7 @@ namespace transport
case eNTCP2BlkRouterInfo: case eNTCP2BlkRouterInfo:
{ {
LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]); LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]);
i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1); i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, frame + offset, size));
break; break;
} }
case eNTCP2BlkI2NPMessage: case eNTCP2BlkI2NPMessage:
@ -1041,7 +1007,7 @@ namespace transport
void NTCP2Session::SendTermination (NTCP2TerminationReason reason) void NTCP2Session::SendTermination (NTCP2TerminationReason reason)
{ {
if (!IsEstablished ()) return; if (!m_SendKey || !m_SendSipKey) return;
uint8_t payload[12] = { eNTCP2BlkTermination, 0, 9 }; uint8_t payload[12] = { eNTCP2BlkTermination, 0, 9 };
htobe64buf (payload + 3, m_ReceiveSequenceNumber); htobe64buf (payload + 3, m_ReceiveSequenceNumber);
payload[11] = (uint8_t)reason; payload[11] = (uint8_t)reason;

5
libi2pd/NTCP2.h

@ -73,6 +73,8 @@ namespace transport
eNTCP2Banned, // 17 eNTCP2Banned, // 17
}; };
// RouterInfo flags
const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01;
typedef std::array<uint8_t, NTCP2_UNENCRYPTED_FRAME_MAX_SIZE> NTCP2FrameBuffer; typedef std::array<uint8_t, NTCP2_UNENCRYPTED_FRAME_MAX_SIZE> NTCP2FrameBuffer;
struct NTCP2Establisher struct NTCP2Establisher
@ -95,7 +97,8 @@ namespace transport
void KDF3Alice (); // for SessionConfirmed part 2 void KDF3Alice (); // for SessionConfirmed part 2
void KDF3Bob (); void KDF3Bob ();
void MixKey (const uint8_t * inputKeyMaterial, uint8_t * derived); void MixKey (const uint8_t * inputKeyMaterial);
void MixHash (const uint8_t * buf, size_t len);
void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH void KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub); // for SessionRequest, (pub, priv) for DH
void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate
void CreateEphemeralKey (); void CreateEphemeralKey ();

92
libi2pd/NetDb.cpp

@ -12,6 +12,7 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Tunnel.h" #include "Tunnel.h"
#include "Transports.h" #include "Transports.h"
#include "NTCP2.h"
#include "RouterContext.h" #include "RouterContext.h"
#include "Garlic.h" #include "Garlic.h"
#include "NetDb.hpp" #include "NetDb.hpp"
@ -25,7 +26,7 @@ namespace data
{ {
NetDb netdb; NetDb netdb;
NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_FloodfillBootstrap(nullptr), m_HiddenMode(false) NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_PersistProfiles (true), m_HiddenMode(false)
{ {
} }
@ -47,6 +48,8 @@ namespace data
if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold if (m_RouterInfos.size () < threshold) // reseed if # of router less than threshold
Reseed (); Reseed ();
i2p::config::GetOption("persist.profiles", m_PersistProfiles);
m_IsRunning = true; m_IsRunning = true;
m_Thread = new std::thread (std::bind (&NetDb::Run, this)); m_Thread = new std::thread (std::bind (&NetDb::Run, this));
} }
@ -55,6 +58,7 @@ namespace data
{ {
if (m_IsRunning) if (m_IsRunning)
{ {
if (m_PersistProfiles)
for (auto& it: m_RouterInfos) for (auto& it: m_RouterInfos)
it.second->SaveProfile (); it.second->SaveProfile ();
DeleteObsoleteProfiles (); DeleteObsoleteProfiles ();
@ -98,6 +102,10 @@ namespace data
case eI2NPDatabaseLookup: case eI2NPDatabaseLookup:
HandleDatabaseLookupMsg (msg); HandleDatabaseLookupMsg (msg);
break; break;
case eI2NPDummyMsg:
// plain RouterInfo from NTCP2 with flags for now
HandleNTCP2RouterInfoMsg (msg);
break;
default: // WTF? default: // WTF?
LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ()); LogPrint (eLogError, "NetDb: unexpected message type ", (int) msg->GetTypeID ());
//i2p::HandleI2NPMessage (msg); //i2p::HandleI2NPMessage (msg);
@ -162,22 +170,38 @@ namespace data
} }
} }
void NetDb::SetHidden(bool hide)
{
// TODO: remove reachable addresses from router info
m_HiddenMode = hide;
}
bool NetDb::AddRouterInfo (const uint8_t * buf, int len) bool NetDb::AddRouterInfo (const uint8_t * buf, int len)
{
bool updated;
AddRouterInfo (buf, len, updated);
return updated;
}
std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const uint8_t * buf, int len, bool& updated)
{ {
IdentityEx identity; IdentityEx identity;
if (identity.FromBuffer (buf, len)) if (identity.FromBuffer (buf, len))
return AddRouterInfo (identity.GetIdentHash (), buf, len); return AddRouterInfo (identity.GetIdentHash (), buf, len, updated);
return false; updated = false;
return nullptr;
} }
void NetDb::SetHidden(bool hide) { bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len)
// TODO: remove reachable addresses from router info {
m_HiddenMode = hide; bool updated;
AddRouterInfo (ident, buf, len, updated);
return updated;
} }
bool NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len) std::shared_ptr<const RouterInfo> NetDb::AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated)
{ {
bool updated = true; updated = true;
auto r = FindRouter (ident); auto r = FindRouter (ident);
if (r) if (r)
{ {
@ -223,7 +247,7 @@ namespace data
} }
// take care about requested destination // take care about requested destination
m_Requests.RequestComplete (ident, r); m_Requests.RequestComplete (ident, r);
return updated; return r;
} }
bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len, bool NetDb::AddLeaseSet (const IdentHash& ident, const uint8_t * buf, int len,
@ -518,7 +542,7 @@ namespace data
{ {
if (it->second->IsUnreachable ()) if (it->second->IsUnreachable ())
{ {
it->second->SaveProfile (); if (m_PersistProfiles) it->second->SaveProfile ();
it = m_RouterInfos.erase (it); it = m_RouterInfos.erase (it);
continue; continue;
} }
@ -570,6 +594,17 @@ namespace data
transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr)); transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr));
} }
void NetDb::HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m)
{
uint8_t flood = m->GetPayload ()[0] & NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD;
bool updated;
auto ri = AddRouterInfo (m->GetPayload () + 1, m->GetPayloadLength () - 1, updated); // without flags
if (flood && updated && context.IsFloodfill () && ri)
{
auto floodMsg = CreateDatabaseStoreMsg (ri, 0); // replyToken = 0
Flood (ri->GetIdentHash (), floodMsg);
}
}
void NetDb::HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> m) void NetDb::HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> m)
{ {
@ -649,22 +684,7 @@ namespace data
{ {
memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen); memcpy (payload + DATABASE_STORE_HEADER_SIZE, buf + payloadOffset, msgLen);
floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore); floodMsg->FillI2NPMessageHeader (eI2NPDatabaseStore);
std::set<IdentHash> excluded; Flood (ident, floodMsg);
excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
excluded.insert (ident); // don't flood back
for (int i = 0; i < 3; i++)
{
auto floodfill = GetClosestFloodfill (ident, excluded);
if (floodfill)
{
auto h = floodfill->GetIdentHash();
LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64());
transports.SendMessage (h, CopyI2NPMessage(floodMsg));
excluded.insert (h);
}
else
break;
}
} }
else else
LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len); LogPrint (eLogError, "NetDb: Database store message is too long ", floodMsg->len);
@ -965,6 +985,26 @@ namespace data
} }
} }
void NetDb::Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg)
{
std::set<IdentHash> excluded;
excluded.insert (i2p::context.GetIdentHash ()); // don't flood to itself
excluded.insert (ident); // don't flood back
for (int i = 0; i < 3; i++)
{
auto floodfill = GetClosestFloodfill (ident, excluded);
if (floodfill)
{
auto h = floodfill->GetIdentHash();
LogPrint(eLogDebug, "NetDb: Flood lease set for ", ident.ToBase32(), " to ", h.ToBase64());
transports.SendMessage (h, CopyI2NPMessage(floodMsg));
excluded.insert (h);
}
else
break;
}
}
std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter () const std::shared_ptr<const RouterInfo> NetDb::GetRandomRouter () const
{ {
return GetRandomRouter ( return GetRandomRouter (

6
libi2pd/NetDb.hpp

@ -65,6 +65,7 @@ namespace data
void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseStoreMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg); void HandleDatabaseLookupMsg (std::shared_ptr<const I2NPMessage> msg);
void HandleNTCP2RouterInfoMsg (std::shared_ptr<const I2NPMessage> m);
std::shared_ptr<const RouterInfo> GetRandomRouter () const; std::shared_ptr<const RouterInfo> GetRandomRouter () const;
std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const; std::shared_ptr<const RouterInfo> GetRandomRouter (std::shared_ptr<const RouterInfo> compatibleWith) const;
@ -110,11 +111,14 @@ namespace data
void Run (); // exploratory thread void Run (); // exploratory thread
void Explore (int numDestinations); void Explore (int numDestinations);
void Publish (); void Publish ();
void Flood (const IdentHash& ident, std::shared_ptr<I2NPMessage> floodMsg);
void ManageLeaseSets (); void ManageLeaseSets ();
void ManageRequests (); void ManageRequests ();
void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20);
std::shared_ptr<const RouterInfo> AddRouterInfo (const uint8_t * buf, int len, bool& updated);
std::shared_ptr<const RouterInfo> AddRouterInfo (const IdentHash& ident, const uint8_t * buf, int len, bool& updated);
template<typename Filter> template<typename Filter>
std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const; std::shared_ptr<const RouterInfo> GetRandomRouter (Filter filter) const;
@ -140,6 +144,8 @@ namespace data
friend class NetDbRequests; friend class NetDbRequests;
NetDbRequests m_Requests; NetDbRequests m_Requests;
bool m_PersistProfiles;
/** router info we are bootstrapping from or nullptr if we are not currently doing that*/ /** router info we are bootstrapping from or nullptr if we are not currently doing that*/
std::shared_ptr<RouterInfo> m_FloodfillBootstrap; std::shared_ptr<RouterInfo> m_FloodfillBootstrap;

4
libi2pd/Poly1305.cpp

@ -6,6 +6,8 @@
Kovri go write your own code Kovri go write your own code
*/ */
#if LEGACY_OPENSSL
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
@ -19,3 +21,5 @@ namespace crypto
} }
} }
} }
#endif

3
libi2pd/Poly1305.h

@ -9,7 +9,9 @@
#define LIBI2PD_POLY1305_H #define LIBI2PD_POLY1305_H
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include "Crypto.h"
#if LEGACY_OPENSSL
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
@ -254,5 +256,6 @@ namespace crypto
} }
} }
#endif
#endif #endif

8
libi2pd/RouterContext.cpp

@ -116,12 +116,12 @@ namespace i2p
void RouterContext::NewNTCP2Keys () void RouterContext::NewNTCP2Keys ()
{ {
m_StaticKeys.reset (new i2p::crypto::X25519Keys ());
m_StaticKeys->GenerateKeys ();
m_NTCP2Keys.reset (new NTCP2PrivateKeys ()); m_NTCP2Keys.reset (new NTCP2PrivateKeys ());
RAND_bytes (m_NTCP2Keys->staticPrivateKey, 32); m_StaticKeys->GetPrivateKey (m_NTCP2Keys->staticPrivateKey);
memcpy (m_NTCP2Keys->staticPublicKey, m_StaticKeys->GetPublicKey (), 32);
RAND_bytes (m_NTCP2Keys->iv, 16); RAND_bytes (m_NTCP2Keys->iv, 16);
BN_CTX * ctx = BN_CTX_new ();
i2p::crypto::GetEd25519 ()->ScalarMulB (m_NTCP2Keys->staticPrivateKey, m_NTCP2Keys->staticPublicKey, ctx);
BN_CTX_free (ctx);
// save // save
std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out); std::ofstream fk (i2p::fs::DataDirPath (NTCP2_KEYS), std::ofstream::binary | std::ofstream::out);
fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys)); fk.write ((char *)m_NTCP2Keys.get (), sizeof (NTCP2PrivateKeys));

3
libi2pd/Siphash.h

@ -9,7 +9,9 @@
#define SIPHASH_H #define SIPHASH_H
#include <cstdint> #include <cstdint>
#include "Crypto.h"
#if !OPENSSL_SIPHASH
namespace i2p namespace i2p
{ {
namespace crypto namespace crypto
@ -148,5 +150,6 @@ namespace crypto
} }
} }
} }
#endif
#endif #endif

125
libi2pd/Timestamp.cpp

@ -1,6 +1,10 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include <chrono>
#include <future>
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/algorithm/string.hpp>
#include "Config.h"
#include "Log.h" #include "Log.h"
#include "I2PEndian.h" #include "I2PEndian.h"
#include "Timestamp.h" #include "Timestamp.h"
@ -15,10 +19,30 @@ namespace i2p
{ {
namespace util namespace util
{ {
static uint64_t GetLocalMillisecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
static uint32_t GetLocalHoursSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::hours>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
static uint64_t GetLocalSecondsSinceEpoch ()
{
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count ();
}
static int64_t g_TimeOffset = 0; // in seconds static int64_t g_TimeOffset = 0; // in seconds
void SyncTimeWithNTP (const std::string& address) static void SyncTimeWithNTP (const std::string& address)
{ {
LogPrint (eLogInfo, "Timestamp: NTP request to ", address);
boost::asio::io_service service; boost::asio::io_service service;
boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), address, "ntp"); boost::asio::ip::udp::resolver::query query (boost::asio::ip::udp::v4 (), address, "ntp");
boost::system::error_code ec; boost::system::error_code ec;
@ -48,19 +72,112 @@ namespace util
} }
catch (std::exception& e) catch (std::exception& e)
{ {
LogPrint (eLogError, "NTP error: ", e.what ()); LogPrint (eLogError, "Timestamp: NTP error: ", e.what ());
} }
if (len >= 8) if (len >= 8)
{ {
auto ourTs = GetSecondsSinceEpoch (); auto ourTs = GetLocalSecondsSinceEpoch ();
uint32_t ts = bufbe32toh (buf + 32); uint32_t ts = bufbe32toh (buf + 32);
if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900 if (ts > 2208988800U) ts -= 2208988800U; // 1/1/1970 from 1/1/1900
g_TimeOffset = ts - ourTs; g_TimeOffset = ts - ourTs;
LogPrint (eLogInfo, address, " time offset from system time is ", g_TimeOffset, " seconds"); LogPrint (eLogInfo, "Timestamp: ", address, " time offset from system time is ", g_TimeOffset, " seconds");
}
}
else
LogPrint (eLogError, "Timestamp: Couldn't open UDP socket");
}
else
LogPrint (eLogError, "Timestamp: Couldn't resove address ", address);
}
NTPTimeSync::NTPTimeSync (): m_IsRunning (false), m_Timer (m_Service)
{
i2p::config::GetOption("nettime.ntpsyncinterval", m_SyncInterval);
std::string ntpservers; i2p::config::GetOption("nettime.ntpservers", ntpservers);
boost::split (m_NTPServersList, ntpservers, boost::is_any_of(","), boost::token_compress_on);
}
NTPTimeSync::~NTPTimeSync ()
{
Stop ();
}
void NTPTimeSync::Start()
{
if (m_NTPServersList.size () > 0)
{
m_IsRunning = true;
LogPrint(eLogInfo, "Timestamp: NTP time sync starting");
m_Service.post (std::bind (&NTPTimeSync::Sync, this));
m_Thread.reset (new std::thread (std::bind (&NTPTimeSync::Run, this)));
}
else
LogPrint (eLogWarning, "Timestamp: No NTP server found");
}
void NTPTimeSync::Stop ()
{
if (m_IsRunning)
{
LogPrint(eLogInfo, "Timestamp: NTP time sync stopping");
m_IsRunning = false;
m_Timer.cancel ();
m_Service.stop ();
if (m_Thread)
{
m_Thread->join ();
m_Thread.reset (nullptr);
}
}
}
void NTPTimeSync::Run ()
{
while (m_IsRunning)
{
try
{
m_Service.run ();
} }
catch (std::exception& ex)
{
LogPrint (eLogError, "Timestamp: NTP time sync exception: ", ex.what ());
} }
} }
} }
void NTPTimeSync::Sync ()
{
if (m_NTPServersList.size () > 0)
SyncTimeWithNTP (m_NTPServersList[rand () % m_NTPServersList.size ()]);
else
m_IsRunning = false;
if (m_IsRunning)
{
m_Timer.expires_from_now (boost::posix_time::hours (m_SyncInterval));
m_Timer.async_wait ([this](const boost::system::error_code& ecode)
{
if (ecode != boost::asio::error::operation_aborted)
Sync ();
});
}
}
uint64_t GetMillisecondsSinceEpoch ()
{
return GetLocalMillisecondsSinceEpoch () + g_TimeOffset*1000;
}
uint32_t GetHoursSinceEpoch ()
{
return GetLocalHoursSinceEpoch () + g_TimeOffset/3600;
}
uint64_t GetSecondsSinceEpoch ()
{
return GetLocalSecondsSinceEpoch () + g_TimeOffset;
}
} }
} }

44
libi2pd/Timestamp.h

@ -2,29 +2,43 @@
#define TIMESTAMP_H__ #define TIMESTAMP_H__
#include <inttypes.h> #include <inttypes.h>
#include <chrono> #include <thread>
#include <vector>
#include <string>
#include <boost/asio.hpp>
namespace i2p namespace i2p
{ {
namespace util namespace util
{ {
inline uint64_t GetMillisecondsSinceEpoch () uint64_t GetMillisecondsSinceEpoch ();
{ uint32_t GetHoursSinceEpoch ();
return std::chrono::duration_cast<std::chrono::milliseconds>( uint64_t GetSecondsSinceEpoch ();
std::chrono::system_clock::now().time_since_epoch()).count ();
}
inline uint32_t GetHoursSinceEpoch () class NTPTimeSync
{ {
return std::chrono::duration_cast<std::chrono::hours>( public:
std::chrono::system_clock::now().time_since_epoch()).count ();
}
inline uint64_t GetSecondsSinceEpoch () NTPTimeSync ();
{ ~NTPTimeSync ();
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch()).count (); void Start ();
} void Stop ();
private:
void Run ();
void Sync ();
private:
bool m_IsRunning;
std::unique_ptr<std::thread> m_Thread;
boost::asio::io_service m_Service;
boost::asio::deadline_timer m_Timer;
int m_SyncInterval;
std::vector<std::string> m_NTPServersList;
};
} }
} }

9
libi2pd/Transports.cpp

@ -35,8 +35,11 @@ namespace transport
void DHKeysPairSupplier::Stop () void DHKeysPairSupplier::Stop ()
{ {
{
std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_IsRunning = false; m_IsRunning = false;
m_Acquired.notify_one (); m_Acquired.notify_one ();
}
if (m_Thread) if (m_Thread)
{ {
m_Thread->join (); m_Thread->join ();
@ -50,12 +53,12 @@ namespace transport
while (m_IsRunning) while (m_IsRunning)
{ {
int num, total = 0; int num, total = 0;
while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 20) while ((num = m_QueueSize - (int)m_Queue.size ()) > 0 && total < 10)
{ {
CreateDHKeysPairs (num); CreateDHKeysPairs (num);
total += num; total += num;
} }
if (total >= 20) if (total >= 10)
{ {
LogPrint (eLogWarning, "Transports: ", total, " DH keys generated at the time"); LogPrint (eLogWarning, "Transports: ", total, " DH keys generated at the time");
std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break std::this_thread::sleep_for (std::chrono::seconds(1)); // take a break
@ -63,6 +66,7 @@ namespace transport
else else
{ {
std::unique_lock<std::mutex> l(m_AcquiredMutex); std::unique_lock<std::mutex> l(m_AcquiredMutex);
if (!m_IsRunning) break;
m_Acquired.wait (l); // wait for element gets acquired m_Acquired.wait (l); // wait for element gets acquired
} }
} }
@ -813,7 +817,6 @@ namespace transport
if (profile) if (profile)
{ {
profile->TunnelNonReplied(); profile->TunnelNonReplied();
profile->Save(it->first);
} }
std::unique_lock<std::mutex> l(m_PeersMutex); std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.erase (it); it = m_Peers.erase (it);

6
libi2pd/util.cpp

@ -21,9 +21,9 @@
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
/* // No more needed. Exists in MinGW.
int inet_pton(int af, const char *src, void *dst) int inet_pton(int af, const char *src, void *dst)
{ /* This function was written by Petar Korponai?. See { // This function was written by Petar Korponai?. See http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found
http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */
struct sockaddr_storage ss; struct sockaddr_storage ss;
int size = sizeof (ss); int size = sizeof (ss);
char src_copy[INET6_ADDRSTRLEN + 1]; char src_copy[INET6_ADDRSTRLEN + 1];
@ -45,7 +45,7 @@ http://stackoverflow.com/questions/15660203/inet-pton-identifier-not-found */
} }
} }
return 0; return 0;
} }*/
#else /* !WIN32 => UNIX */ #else /* !WIN32 => UNIX */
#include <sys/types.h> #include <sys/types.h>
#include <ifaddrs.h> #include <ifaddrs.h>

2
libi2pd/version.h

@ -7,7 +7,7 @@
#define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c) #define MAKE_VERSION(a,b,c) STRINGIZE(a) "." STRINGIZE(b) "." STRINGIZE(c)
#define I2PD_VERSION_MAJOR 2 #define I2PD_VERSION_MAJOR 2
#define I2PD_VERSION_MINOR 21 #define I2PD_VERSION_MINOR 22
#define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_MICRO 0
#define I2PD_VERSION_PATCH 0 #define I2PD_VERSION_PATCH 0
#define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO)

2
qt/i2pd_qt/android/AndroidManifest.xml

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.21.0" android:versionCode="1" android:installLocation="auto"> <manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.22.0" android:versionCode="1" android:installLocation="auto">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/> <uses-sdk android:minSdkVersion="11" android:targetSdkVersion="23"/>
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
<!-- <application android:hardwareAccelerated="true" --> <!-- <application android:hardwareAccelerated="true" -->

BIN
qt/i2pd_qt/data/icons/128x128/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
qt/i2pd_qt/data/icons/16x16/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
qt/i2pd_qt/data/icons/22x22/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
qt/i2pd_qt/data/icons/24x24/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
qt/i2pd_qt/data/icons/256x256/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
qt/i2pd_qt/data/icons/32x32/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
qt/i2pd_qt/data/icons/48x48/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
qt/i2pd_qt/data/icons/512x512/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
qt/i2pd_qt/data/icons/64x64/website.i2pd.i2pd.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

43
qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2018 Viktor Villainov <supervillain@riseup.net> -->
<component type="desktop">
<id>website.i2pd.i2pd</id>
<launchable type="desktop-id">website.i2pd.i2pd.desktop</launchable>
<metadata_license>CC0-1.0</metadata_license>
<project_license>BSD-3-Clause</project_license>
<name>i2pd</name>
<summary>Invisible Internet</summary>
<description>
<p>i2pd (I2P Daemon) is a full-featured C++ implementation of I2P client.</p>
<p>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. </p>
<p>I2P allows people from all around the world to communicate and share information
without restrictions.</p>
<p>Features:</p>
<ul>
<li>Distributed anonymous networking framework</li>
<li>End-to-end encrypted communications</li>
<li>Small footprint, simple dependencies, fast performance</li>
<li>Rich set of APIs for developers of secure applications</li>
</ul>
</description>
<screenshots>
<screenshot type="default">
<image height="590" width="923">https://i2pd.website/images/i2pd_qt.png</image>
</screenshot>
</screenshots>
<url type="homepage">https://i2pd.website/</url>
<url type="bugtracker">https://github.com/PurpleI2P/i2pd/issues</url>
<url type="help">https://i2pd.readthedocs.io/en/latest/</url>
<update_contact>supervillain@riseup.net</update_contact>
<developer_name>PurpleI2P Team</developer_name>
<translation type="qt" />
<releases>
<release version="2.22.0" date="2018-11-09" />
<release version="2.21.1" date="2018-10-22" />
<release version="2.21.0" date="2018-10-04" />
</releases>
<content_rating type="oars-1.1" />
</component>

11
qt/i2pd_qt/data/website.i2pd.i2pd.desktop

@ -0,0 +1,11 @@
[Desktop Entry]
Categories=Network;P2P;Qt;
Exec=i2pd_qt
GenericName=Invisible Internet
Comment=A universal anonymous network layer
Icon=website.i2pd.i2pd
Name=i2pd
Terminal=false
Type=Application
StartupNotify=false
Keywords=i2p;i2pd;vpn;p2p;
Loading…
Cancel
Save