Browse Source

Merge pull request #1229 from PurpleI2P/openssl

2.20
pull/1268/head
orignal 6 years ago committed by GitHub
parent
commit
73b6338f62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      ChangeLog
  2. 14
      Makefile.osx
  3. 2
      Win32/installer.iss
  4. 2
      android/AndroidManifest.xml
  5. 5
      android/assets/i2pd.conf
  6. 2
      android/build.gradle
  7. 4
      android/jni/Android.mk
  8. 4
      android/jni/Application.mk
  9. 20
      android/jni/DaemonAndroid.cpp
  10. 176
      android/src/org/purplei2p/i2pd/I2PDActivity.java
  11. 4
      android_binary_only/jni/Android.mk
  12. 2
      appveyor.yml
  13. 2
      contrib/docker/Dockerfile
  14. 2
      contrib/rpm/i2pd-git.spec
  15. 5
      contrib/rpm/i2pd.spec
  16. 28
      daemon/HTTPServer.cpp
  17. 6
      daemon/UPnP.cpp
  18. 6
      debian/changelog
  19. 2
      libi2pd/Config.cpp
  20. 278
      libi2pd/NTCP2.cpp
  21. 17
      libi2pd/NTCP2.h
  22. 4
      libi2pd/NTCPSession.cpp
  23. 2
      libi2pd/RouterContext.cpp
  24. 4
      libi2pd/RouterInfo.cpp
  25. 4
      libi2pd/version.h
  26. 2
      qt/i2pd_qt/android/AndroidManifest.xml

11
ChangeLog

@ -1,6 +1,17 @@
# 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.20.0] - 2018-08-23
### Added
- Full implementation of NTCP2
- Assets for android
### Changed
- armeabi-v7a and x86 in one apk for android
- NTCP2 is enabled by default
- Show lease's expiration time in readable format in the web console
### Fixed
- Correct names for transports in the web console
## [2.19.0] - 2018-06-26 ## [2.19.0] - 2018-06-26
### Added ### Added
- ECIES support for RouterInfo - ECIES support for RouterInfo

14
Makefile.osx vendored

@ -31,6 +31,14 @@ endif
# Disabled, since it will be the default make rule. I think its better # Disabled, since it will be the default make rule. I think its better
# to define the default rule in Makefile and not Makefile.<ostype> - torkel # to define the default rule in Makefile and not Makefile.<ostype> - torkel
#install: all install-brew: all
# test -d ${PREFIX} || mkdir -p ${PREFIX}/ install -d ${PREFIX}/bin ${PREFIX}/etc/i2pd ${PREFIX}/share/doc/i2pd ${PREFIX}/share/i2pd ${PREFIX}/share/man/man1 ${PREFIX}/var/lib/i2pd
# cp -r i2p ${PREFIX}/ install -m 755 ${I2PD} ${PREFIX}/bin/
install -m 644 contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/etc/i2pd
@cp -R contrib/certificates ${PREFIX}/share/i2pd/
install -m 644 ChangeLog LICENSE README.md contrib/i2pd.conf contrib/subscriptions.txt contrib/tunnels.conf ${PREFIX}/share/doc/i2pd
@gzip debian/i2pd.1 && install debian/i2pd.1.gz ${PREFIX}/share/man/man1
@ln -sf ${PREFIX}/share/i2pd/certificates ${PREFIX}/var/lib/i2pd/
@ln -sf ${PREFIX}/etc/i2pd/i2pd.conf ${PREFIX}/var/lib/i2pd/i2pd.conf
@ln -sf ${PREFIX}/etc/i2pd/subscriptions.txt ${PREFIX}/var/lib/i2pd/subscriptions.txt
@ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf

2
Win32/installer.iss

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

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.19.0"> android:versionName="2.20.0">
<uses-sdk <uses-sdk
android:minSdkVersion="14" android:minSdkVersion="14"

5
android/assets/i2pd.conf

@ -15,12 +15,15 @@ ipv6 = false
# ntcpproxy = http://127.0.0.1:8118 # ntcpproxy = http://127.0.0.1:8118
# ssu = true # ssu = true
bandwidth = O bandwidth = L
# share = 100 # share = 100
# notransit = true # notransit = true
# floodfill = true # floodfill = true
[ntcp2]
enabled = true
[http] [http]
enabled = true enabled = true
address = 127.0.0.1 address = 127.0.0.1

2
android/build.gradle

@ -25,7 +25,7 @@ android {
targetSdkVersion 28 targetSdkVersion 28
minSdkVersion 14 minSdkVersion 14
versionCode 1 versionCode 1
versionName "2.19.0" versionName "2.20.0"
ndk { ndk {
abiFilters 'armeabi-v7a' abiFilters 'armeabi-v7a'
abiFilters 'x86' abiFilters 'x86'

4
android/jni/Android.mk

@ -68,6 +68,6 @@ include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := miniupnpc LOCAL_MODULE := miniupnpc
LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a
LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include
include $(PREBUILT_STATIC_LIBRARY) include $(PREBUILT_STATIC_LIBRARY)

4
android/jni/Application.mk

@ -1,8 +1,8 @@
#APP_ABI := all #APP_ABI := all
#APP_ABI := armeabi-v7a x86 APP_ABI := armeabi-v7a x86
#APP_ABI := x86 #APP_ABI := x86
#APP_ABI := x86_64 #APP_ABI := x86_64
APP_ABI := armeabi-v7a #APP_ABI := armeabi-v7a
#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there. #can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there.
APP_PLATFORM := android-14 APP_PLATFORM := android-14

20
android/jni/DaemonAndroid.cpp

@ -1,10 +1,13 @@
#include "DaemonAndroid.h"
#include "Daemon.h"
#include <iostream> #include <iostream>
#include <chrono>
#include <thread>
#include <exception>
#include <boost/exception/diagnostic_information.hpp> #include <boost/exception/diagnostic_information.hpp>
#include <boost/exception_ptr.hpp> #include <boost/exception_ptr.hpp>
#include <exception>
//#include "mainwindow.h" //#include "mainwindow.h"
#include "FS.h"
#include "DaemonAndroid.h"
#include "Daemon.h"
namespace i2p namespace i2p
{ {
@ -80,6 +83,17 @@ namespace android
//mutex=new QMutex(QMutex::Recursive); //mutex=new QMutex(QMutex::Recursive);
//setRunningCallback(0); //setRunningCallback(0);
//m_IsRunning=false; //m_IsRunning=false;
// make sure assets are ready before proceed
i2p::fs::DetectDataDir("", false);
int numAttempts = 0;
do
{
if (i2p::fs::Exists (i2p::fs::DataDirPath("assets.ready"))) break; // assets ready
numAttempts++;
std::this_thread::sleep_for (std::chrono::seconds(1)); // otherwise wait for 1 more second
}
while (numAttempts <= 10); // 10 seconds max
return Daemon.init(argc,argv); return Daemon.init(argc,argv);
} }

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

@ -1,6 +1,9 @@
package org.purplei2p.i2pd; package org.purplei2p.i2pd;
import java.io.File; import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -25,21 +28,27 @@ import android.view.MenuItem;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
// For future package update checking
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";
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;
private boolean assetsCopied;
private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/";
private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); private static final DaemonSingleton daemon = DaemonSingleton.getInstance();
private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() { new DaemonSingleton.StateUpdateListener() {
@Override @Override
public void daemonStateUpdate() { public void daemonStateUpdate()
{
processAssets();
runOnUiThread(new Runnable(){ runOnUiThread(new Runnable(){
@Override @Override
public void run() { public void run() {
try { try {
@ -55,7 +64,7 @@ public class I2PDActivity extends Activity {
(DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+ (DaemonSingleton.State.startFailed.equals(state)?": "+daemon.getDaemonStartResult():"")+
(DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"") (DaemonSingleton.State.gracefulShutdownInProgress.equals(state)?": "+formatGraceTimeRemaining()+" "+getText(R.string.remaining):"")
); );
} catch (Throwable tr) { } catch (Throwable tr) {
Log.e(TAG,"error ignored",tr); Log.e(TAG,"error ignored",tr);
} }
} }
@ -64,7 +73,7 @@ public class I2PDActivity extends Activity {
}; };
private static volatile long graceStartedMillis; private static volatile long graceStartedMillis;
private static final Object graceStartedMillis_LOCK=new Object(); private static final Object graceStartedMillis_LOCK=new Object();
private static String formatGraceTimeRemaining() { private static String formatGraceTimeRemaining() {
long remainingSeconds; long remainingSeconds;
synchronized (graceStartedMillis_LOCK){ synchronized (graceStartedMillis_LOCK){
@ -74,25 +83,19 @@ public class I2PDActivity extends Activity {
long remSec=remainingSeconds-remainingMinutes*60; long remSec=remainingSeconds-remainingMinutes*60;
return remainingMinutes+":"+(remSec/10)+remSec%10; return remainingMinutes+":"+(remSec/10)+remSec%10;
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// copy assets
copyAsset("certificates");
copyAsset("i2pd.conf");
copyAsset("subsciptions.txt");
copyAsset("tunnels.conf");
textView = new TextView(this); textView = new TextView(this);
setContentView(textView); setContentView(textView);
daemon.addStateChangeListener(daemonStateUpdatedListener); daemon.addStateChangeListener(daemonStateUpdatedListener);
daemonStateUpdatedListener.daemonStateUpdate(); daemonStateUpdatedListener.daemonStateUpdate();
// set the app be foreground // set the app be foreground
doBindService(); doBindService();
final Timer gracefulQuitTimer = getGracefulQuitTimer(); final Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null){ if(gracefulQuitTimer!=null){
long gracefulStopAtMillis; long gracefulStopAtMillis;
@ -102,7 +105,7 @@ public class I2PDActivity extends Activity {
rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis); rescheduleGraceStop(gracefulQuitTimer, gracefulStopAtMillis);
} }
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
@ -115,7 +118,7 @@ public class I2PDActivity extends Activity {
Log.e(TAG, "", tr); Log.e(TAG, "", tr);
} }
} }
private static void cancelGracefulStop() { private static void cancelGracefulStop() {
Timer gracefulQuitTimer = getGracefulQuitTimer(); Timer gracefulQuitTimer = getGracefulQuitTimer();
if(gracefulQuitTimer!=null) { if(gracefulQuitTimer!=null) {
@ -123,7 +126,7 @@ public class I2PDActivity extends Activity {
setGracefulQuitTimer(null); setGracefulQuitTimer(null);
} }
} }
private CharSequence throwableToString(Throwable tr) { private CharSequence throwableToString(Throwable tr) {
StringWriter sw = new StringWriter(8192); StringWriter sw = new StringWriter(8192);
PrintWriter pw = new PrintWriter(sw); PrintWriter pw = new PrintWriter(sw);
@ -131,9 +134,9 @@ public class I2PDActivity extends Activity {
pw.close(); pw.close();
return sw.toString(); return sw.toString();
} }
// private LocalService mBoundService; // private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() { private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) { public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been // This is called when the connection with the service has been
@ -142,12 +145,12 @@ public class I2PDActivity extends Activity {
// service that we know is running in our own process, we can // service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it. // cast its IBinder to a concrete class and directly access it.
// mBoundService = ((LocalService.LocalBinder)service).getService(); // mBoundService = ((LocalService.LocalBinder)service).getService();
// Tell the user about this for our demo. // Tell the user about this for our demo.
// Toast.makeText(Binding.this, R.string.local_service_connected, // Toast.makeText(Binding.this, R.string.local_service_connected,
// Toast.LENGTH_SHORT).show(); // Toast.LENGTH_SHORT).show();
} }
public void onServiceDisconnected(ComponentName className) { public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been // This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed. // unexpectedly disconnected -- that is, its process crashed.
@ -158,10 +161,9 @@ public class I2PDActivity extends Activity {
// Toast.LENGTH_SHORT).show(); // Toast.LENGTH_SHORT).show();
} }
}; };
private static volatile boolean mIsBound; private static volatile boolean mIsBound;
private void doBindService() { private void doBindService() {
synchronized (I2PDActivity.class) { synchronized (I2PDActivity.class) {
if (mIsBound) return; if (mIsBound) return;
@ -173,7 +175,7 @@ public class I2PDActivity extends Activity {
mIsBound = true; mIsBound = true;
} }
} }
private void doUnbindService() { private void doUnbindService() {
synchronized (I2PDActivity.class) { synchronized (I2PDActivity.class) {
if (mIsBound) { if (mIsBound) {
@ -183,21 +185,21 @@ public class I2PDActivity extends Activity {
} }
} }
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present. // Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.options_main, menu); getMenuInflater().inflate(R.menu.options_main, menu);
return true; return true;
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will // Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long // automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml. // as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); int id = item.getItemId();
switch(id){ switch(id){
case R.id.action_stop: case R.id.action_stop:
i2pdStop(); i2pdStop();
@ -206,14 +208,14 @@ public class I2PDActivity extends Activity {
i2pdGracefulStop(); i2pdGracefulStop();
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
private void i2pdStop() { private void i2pdStop() {
cancelGracefulStop(); cancelGracefulStop();
new Thread(new Runnable(){ new Thread(new Runnable(){
@Override @Override
public void run() { public void run() {
Log.d(TAG, "stopping"); Log.d(TAG, "stopping");
@ -223,12 +225,12 @@ public class I2PDActivity extends Activity {
Log.e(TAG, "", tr); Log.e(TAG, "", tr);
} }
} }
},"stop").start(); },"stop").start();
} }
private static volatile Timer gracefulQuitTimer; private static volatile Timer gracefulQuitTimer;
private void i2pdGracefulStop() { private void i2pdGracefulStop() {
if(daemon.getState()==DaemonSingleton.State.stopped){ if(daemon.getState()==DaemonSingleton.State.stopped){
Toast.makeText(this, R.string.already_stopped, Toast.makeText(this, R.string.already_stopped,
@ -243,7 +245,7 @@ public class I2PDActivity extends Activity {
Toast.makeText(this, R.string.graceful_stop_is_in_progress, Toast.makeText(this, R.string.graceful_stop_is_in_progress,
Toast.LENGTH_SHORT).show(); Toast.LENGTH_SHORT).show();
new Thread(new Runnable(){ new Thread(new Runnable(){
@Override @Override
public void run() { public void run() {
try{ try{
@ -263,21 +265,21 @@ public class I2PDActivity extends Activity {
Log.e(TAG,"",tr); Log.e(TAG,"",tr);
} }
} }
},"gracInit").start(); },"gracInit").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);
setGracefulQuitTimer(gracefulQuitTimer); setGracefulQuitTimer(gracefulQuitTimer);
gracefulQuitTimer.schedule(new TimerTask(){ gracefulQuitTimer.schedule(new TimerTask(){
@Override @Override
public void run() { public void run() {
i2pdStop(); i2pdStop();
} }
}, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis())); }, Math.max(0,gracefulStopAtMillis-System.currentTimeMillis()));
final TimerTask tickerTask = new TimerTask() { final TimerTask tickerTask = new TimerTask() {
@Override @Override
@ -287,30 +289,30 @@ public class I2PDActivity extends Activity {
}; };
gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/); gracefulQuitTimer.scheduleAtFixedRate(tickerTask,0/*start delay*/,1000/*millis period*/);
} }
private static Timer getGracefulQuitTimer() { private static Timer getGracefulQuitTimer() {
return gracefulQuitTimer; return gracefulQuitTimer;
} }
private static void setGracefulQuitTimer(Timer gracefulQuitTimer) { private static void setGracefulQuitTimer(Timer gracefulQuitTimer) {
I2PDActivity.gracefulQuitTimer = gracefulQuitTimer; I2PDActivity.gracefulQuitTimer = gracefulQuitTimer;
} }
/** /**
* Copy the asset at the specified path to this app's data directory. If the * Copy the asset at the specified path to this app's data directory. If the
* asset is a directory, its contents are also copied. * asset is a directory, its contents are also copied.
* *
* @param path * @param path
* Path to asset, relative to app's assets directory. * Path to asset, relative to app's assets directory.
*/ */
private void copyAsset(String path) { private void copyAsset(String path) {
AssetManager manager = getAssets(); AssetManager manager = getAssets();
// If we have a directory, we make it and recurse. If a file, we copy its // If we have a directory, we make it and recurse. If a file, we copy its
// contents. // contents.
try { try {
String[] contents = manager.list(path); String[] contents = manager.list(path);
// The documentation suggests that list throws an IOException, but doesn't // The documentation suggests that list throws an IOException, but doesn't
// say under what conditions. It'd be nice if it did so when the path was // say under what conditions. It'd be nice if it did so when the path was
// to a file. That doesn't appear to be the case. If the returned array is // to a file. That doesn't appear to be the case. If the returned array is
@ -318,30 +320,30 @@ public class I2PDActivity extends Activity {
// directories will get turned into files. // directories will get turned into files.
if (contents == null || contents.length == 0) if (contents == null || contents.length == 0)
throw new IOException(); throw new IOException();
// Make the directory. // Make the directory.
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); File dir = new File(i2pdpath, path);
dir.mkdirs(); dir.mkdirs();
// Recurse on the contents. // Recurse on the contents.
for (String entry : contents) { for (String entry : contents) {
copyAsset(path + "/" + entry); copyAsset(path + "/" + entry);
} }
} catch (IOException e) { } catch (IOException e) {
copyFileAsset(path); copyFileAsset(path);
} }
} }
/** /**
* Copy the asset file specified by path to app's data directory. Assumes * Copy the asset file specified by path to app's data directory. Assumes
* parent directories have already been created. * parent directories have already been created.
* *
* @param path * @param path
* Path to asset, relative to app's assets directory. * Path to asset, relative to app's assets directory.
*/ */
private void copyFileAsset(String path) { private void copyFileAsset(String path) {
File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/", path); File file = new File(i2pdpath, path);
try { if(!file.exists()) try {
InputStream in = getAssets().open(path); InputStream in = getAssets().open(path);
OutputStream out = new FileOutputStream(file); OutputStream out = new FileOutputStream(file);
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
@ -352,8 +354,66 @@ public class I2PDActivity extends Activity {
} }
out.close(); out.close();
in.close(); in.close();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "", e); Log.e(TAG, "", e);
} }
} }
private void deleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) {
for (File child : fileOrDirectory.listFiles()) {
deleteRecursive(child);
}
}
fileOrDirectory.delete();
}
private void processAssets() {
if (!assetsCopied) try {
assetsCopied = true; // prevent from running on every state update
File holderfile = new File(i2pdpath, "assets.ready");
String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX
StringBuilder text = new StringBuilder();
if (holderfile.exists()) try { // if holder file exists, read assets version string
BufferedReader br = new BufferedReader(new FileReader(holderfile));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
}
br.close();
}
catch (IOException e) {
Log.e(TAG, "", e);
}
// if version differs from current app version or null, try to delete certificates folder
if (!text.toString().contains(versionName)) try {
holderfile.delete();
File certpath = new File(i2pdpath, "certificates");
deleteRecursive(certpath);
}
catch (Throwable tr) {
Log.e(TAG, "", tr);
}
// copy assets. If processed file exists, it won't be overwrited
copyAsset("certificates");
copyAsset("i2pd.conf");
copyAsset("subscriptions.txt");
copyAsset("tunnels.conf");
// update holder file about successful copying
FileWriter writer = new FileWriter(holderfile);
writer.append(versionName);
writer.flush();
writer.close();
}
catch (Throwable tr)
{
Log.e(TAG,"copy assets",tr);
}
}
} }

4
android_binary_only/jni/Android.mk

@ -69,6 +69,6 @@ include $(PREBUILT_STATIC_LIBRARY)
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
LOCAL_MODULE := miniupnpc LOCAL_MODULE := miniupnpc
LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnpc-2.1/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a
LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc-2.1/include
include $(PREBUILT_STATIC_LIBRARY) include $(PREBUILT_STATIC_LIBRARY)

2
appveyor.yml

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

2
contrib/docker/Dockerfile

@ -2,7 +2,7 @@ FROM alpine:latest
LABEL authors "Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>" LABEL authors "Mikal Villa <mikal@sigterm.no>, Darknet Villain <supervillain@riseup.net>"
# Expose git branch, tag and URL variables as arguments # Expose git branch, tag and URL variables as arguments
ARG GIT_BRANCH="master" ARG GIT_BRANCH="openssl"
ENV GIT_BRANCH=${GIT_BRANCH} ENV GIT_BRANCH=${GIT_BRANCH}
ARG GIT_TAG="" ARG GIT_TAG=""
ENV GIT_TAG=${GIT_TAG} ENV GIT_TAG=${GIT_TAG}

2
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.19.0 Version: 2.20.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

5
contrib/rpm/i2pd.spec

@ -1,5 +1,5 @@
Name: i2pd Name: i2pd
Version: 2.19.0 Version: 2.20.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
@ -96,6 +96,9 @@ getent passwd i2pd >/dev/null || \
%changelog %changelog
* Thu Aug 23 2018 orignal <i2porignal@yandex.ru> - 2.20.0
- update to 2.20.0
* Tue Jun 26 2018 orignal <i2porignal@yandex.ru> - 2.19.0 * Tue Jun 26 2018 orignal <i2porignal@yandex.ru> - 2.19.0
- update to 2.19.0 - update to 2.19.0

28
daemon/HTTPServer.cpp

@ -92,6 +92,8 @@ namespace http {
const char HTTP_PARAM_SAM_SESSION_ID[] = "id"; const char HTTP_PARAM_SAM_SESSION_ID[] = "id";
const char HTTP_PARAM_ADDRESS[] = "address"; const char HTTP_PARAM_ADDRESS[] = "address";
static std::string ConvertTime (uint64_t time);
static void ShowUptime (std::stringstream& s, int seconds) static void ShowUptime (std::stringstream& s, int seconds)
{ {
int num; int num;
@ -262,7 +264,9 @@ namespace http {
{ {
if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ()) if (address->IsNTCP2 () && !address->IsPublishedNTCP2 ())
{ {
s << "NTCP2&nbsp;&nbsp; supported <br>\r\n"; s << "NTCP2";
if (address->host.is_v6 ()) s << "v6";
s << "&nbsp;&nbsp; supported <br>\r\n";
continue; continue;
} }
switch (address->transportStyle) switch (address->transportStyle)
@ -271,13 +275,13 @@ namespace http {
{ {
s << "NTCP"; s << "NTCP";
if (address->IsPublishedNTCP2 ()) s << "2"; if (address->IsPublishedNTCP2 ()) s << "2";
if (address->host.is_v6 ()) s << "6"; if (address->host.is_v6 ()) s << "v6";
s << "&nbsp;&nbsp;"; s << "&nbsp;&nbsp;";
break; break;
} }
case i2p::data::RouterInfo::eTransportSSU: case i2p::data::RouterInfo::eTransportSSU:
if (address->host.is_v6 ()) if (address->host.is_v6 ())
s << "SSU6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"; s << "SSUv6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
else else
s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"; s << "SSU&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
break; break;
@ -462,14 +466,14 @@ namespace http {
s << "<div class='invalid'>!! Invalid !! </div>\r\n"; s << "<div class='invalid'>!! Invalid !! </div>\r\n";
s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n"; s << "<div class='slide'><label for='slide" << counter << "'>" << dest.ToBase32() << "</label>\r\n";
s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<p class='content'>\r\n"; s << "<input type='checkbox' id='slide" << (counter++) << "'/>\r\n<p class='content'>\r\n";
s << "<b>Expires:</b> " << ls.GetExpirationTime() << "<br>\r\n"; s << "<b>Expires:</b> " << ConvertTime(ls.GetExpirationTime()) << "<br>\r\n";
auto leases = ls.GetNonExpiredLeases(); auto leases = ls.GetNonExpiredLeases();
s << "<b>Non Expired Leases: " << leases.size() << "</b><br>\r\n"; s << "<b>Non Expired Leases: " << leases.size() << "</b><br>\r\n";
for ( auto & l : leases ) for ( auto & l : leases )
{ {
s << "<b>Gateway:</b> " << l->tunnelGateway.ToBase64() << "<br>\r\n"; s << "<b>Gateway:</b> " << l->tunnelGateway.ToBase64() << "<br>\r\n";
s << "<b>TunnelID:</b> " << l->tunnelID << "<br>\r\n"; s << "<b>TunnelID:</b> " << l->tunnelID << "<br>\r\n";
s << "<b>EndDate:</b> " << l->endDate << "<br>\r\n"; s << "<b>EndDate:</b> " << ConvertTime(l->endDate) << "<br>\r\n";
} }
s << "</p>\r\n</div>\r\n</div>\r\n"; s << "</p>\r\n</div>\r\n</div>\r\n";
} }
@ -583,7 +587,7 @@ namespace http {
} }
if (!tmp_s6.str ().empty ()) if (!tmp_s6.str ().empty ())
{ {
s << "<div class='slide'><label for='slide_ntcp6'><b>" << name << "6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_ntcp6'/>\r\n<p class='content'>"; s << "<div class='slide'><label for='slide_" << boost::algorithm::to_lower_copy(name) << "v6'><b>" << name << "v6</b> ( " << cnt6 << " )</label>\r\n<input type='checkbox' id='slide_" << boost::algorithm::to_lower_copy(name) << "v6'/>\r\n<p class='content'>";
s << tmp_s6.str () << "</p>\r\n</div>\r\n"; s << tmp_s6.str () << "</p>\r\n</div>\r\n";
} }
} }
@ -628,7 +632,7 @@ namespace http {
auto sessions6 = ssuServer->GetSessionsV6 (); auto sessions6 = ssuServer->GetSessionsV6 ();
if (!sessions6.empty ()) if (!sessions6.empty ())
{ {
s << "<div class='slide'><label for='slide_ssu6'><b>SSU6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssu6'/>\r\n<p class='content'>"; s << "<div class='slide'><label for='slide_ssuv6'><b>SSUv6</b> ( " << (int) sessions6.size() << " )</label>\r\n<input type='checkbox' id='slide_ssuv6'/>\r\n<p class='content'>";
for (const auto& it: sessions6) for (const auto& it: sessions6)
{ {
auto endpoint = it.second->GetRemoteEndpoint (); auto endpoint = it.second->GetRemoteEndpoint ();
@ -763,6 +767,16 @@ namespace http {
} }
} }
std::string ConvertTime (uint64_t time)
{
ldiv_t divTime = ldiv(time,1000);
time_t t = divTime.quot;
struct tm *tm = localtime(&t);
char date[128];
snprintf(date, sizeof(date), "%02d/%02d/%d %02d:%02d:%02d.%03ld", tm->tm_mday, tm->tm_mon + 1, tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec, divTime.rem);
return date;
}
HTTPConnection::HTTPConnection (std::string hostname, std::shared_ptr<boost::asio::ip::tcp::socket> socket): HTTPConnection::HTTPConnection (std::string hostname, std::shared_ptr<boost::asio::ip::tcp::socket> socket):
m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0), m_Socket (socket), m_Timer (socket->get_io_service ()), m_BufferLen (0),
expected_host(hostname) expected_host(hostname)

6
daemon/UPnP.cpp

@ -131,8 +131,8 @@ namespace transport
const auto& a = context.GetRouterInfo().GetAddresses(); const auto& a = context.GetRouterInfo().GetAddresses();
for (const auto& address : a) for (const auto& address : a)
{ {
if (!address->host.is_v6 ()) if (!address->host.is_v6 () && address->port)
TryPortMapping (address); TryPortMapping (address);
} }
m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes m_Timer.expires_from_now (boost::posix_time::minutes(20)); // every 20 minutes
m_Timer.async_wait ([this](const boost::system::error_code& ecode) m_Timer.async_wait ([this](const boost::system::error_code& ecode)
@ -148,7 +148,7 @@ namespace transport
const auto& a = context.GetRouterInfo().GetAddresses(); const auto& a = context.GetRouterInfo().GetAddresses();
for (const auto& address : a) for (const auto& address : a)
{ {
if (!address->host.is_v6 ()) if (!address->host.is_v6 () && address->port)
CloseMapping (address); CloseMapping (address);
} }
} }

6
debian/changelog vendored

@ -1,3 +1,9 @@
i2pd (2.20.0-1) unstable; urgency=medium
* updated to version 2.20.0/0.9.36
-- orignal <orignal@i2pmail.org> Thu, 23 Aug 2018 16:00:00 +0000
i2pd (2.19.0-1) unstable; urgency=medium i2pd (2.19.0-1) unstable; urgency=medium
* updated to version 2.19.0/0.9.35 * updated to version 2.19.0/0.9.35

2
libi2pd/Config.cpp

@ -233,7 +233,7 @@ namespace config {
options_description ntcp2("NTCP2 Options"); options_description ntcp2("NTCP2 Options");
ntcp2.add_options() ntcp2.add_options()
("ntcp2.enabled", value<bool>()->default_value(false), "Enable NTCP2 (default: disabled)") ("ntcp2.enabled", value<bool>()->default_value(true), "Enable NTCP2 (default: enabled)")
("ntcp2.published", value<bool>()->default_value(false), "Publish NTCP2 (default: disabled)") ("ntcp2.published", value<bool>()->default_value(false), "Publish NTCP2 (default: disabled)")
("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)")
; ;

278
libi2pd/NTCP2.cpp

@ -1,3 +1,14 @@
/*
* Copyright (c) 2013-2018, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*
* Kovri go write your own code
*
*/
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/sha.h> #include <openssl/sha.h>
#include <openssl/hmac.h> #include <openssl/hmac.h>
@ -244,6 +255,140 @@ namespace transport
SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext) SHA256_Final (m_H, &ctx); //h = SHA256(h || ciphertext)
} }
bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen)
{
// decrypt X
i2p::crypto::CBCDecryption decryption;
decryption.SetKey (i2p::context.GetIdentHash ());
decryption.SetIV (i2p::context.GetNTCP2IV ());
decryption.Decrypt (m_SessionRequestBuffer, 32, GetRemotePub ());
decryption.GetIV (m_IV); // save IV for SessionCreated
// decryption key for next block
KDF1Bob ();
// verify MAC and decrypt options block (32 bytes), use m_H as AD
uint8_t nonce[12], options[16];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionRequestBuffer + 32, 16, m_H, 32, m_K, nonce, options, 16, false)) // decrypt
{
// options
if (options[1] == 2) // ver is always 2
{
paddingLen = bufbe16toh (options + 2);
m_SessionRequestBufferLen = paddingLen + 64;
m3p2Len = bufbe16toh (options + 4);
if (m3p2Len < 16)
{
LogPrint (eLogWarning, "NTCP2: SessionRequest m3p2len=", m3p2Len, " is too short");
return false;
}
// check timestamp
auto ts = i2p::util::GetSecondsSinceEpoch ();
uint32_t tsA = bufbe32toh (options + 8);
if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
{
LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew");
return false;
}
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]);
return false;
}
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
return false;
}
return true;
}
bool NTCP2Establisher::ProcessSessionCreatedMessage (uint16_t& paddingLen)
{
m_SessionCreatedBufferLen = 64;
// decrypt Y
i2p::crypto::CBCDecryption decryption;
decryption.SetKey (m_RemoteIdentHash);
decryption.SetIV (m_IV);
decryption.Decrypt (m_SessionCreatedBuffer, 32, GetRemotePub ());
// decryption key for next block (m_K)
KDF2Alice ();
// decrypt and verify MAC
uint8_t payload[16];
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionCreatedBuffer + 32, 16, m_H, 32, m_K, nonce, payload, 16, false)) // decrypt
{
// options
paddingLen = bufbe16toh(payload + 2);
// check timestamp
auto ts = i2p::util::GetSecondsSinceEpoch ();
uint32_t tsB = bufbe32toh (payload + 8);
if (tsB < ts - NTCP2_CLOCK_SKEW || tsB > ts + NTCP2_CLOCK_SKEW)
{
LogPrint (eLogWarning, "NTCP2: SessionCreated time difference ", (int)(ts - tsB), " exceeds clock skew");
return false;
}
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
return false;
}
return true;
}
bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce)
{
// update AD
SHA256_CTX ctx;
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;
if (paddingLength > 0)
{
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
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
return false;
}
return true;
}
bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf)
{
// update AD again
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, m_H, 32);
SHA256_Update (&ctx, m_SessionConfirmedBuffer, 48);
SHA256_Final (m_H, &ctx);
KDF3Bob ();
if (i2p::crypto::AEADChaCha20Poly1305 (m_SessionConfirmedBuffer + 48, m3p2Len - 16, m_H, 32, m_K, nonce, m3p2Buf, m3p2Len - 16, false)) // decrypt
{
// caclulate new h again for KDF data
memcpy (m_SessionConfirmedBuffer + 16, m_H, 32); // h || ciphertext
SHA256 (m_SessionConfirmedBuffer + 16, m3p2Len + 32, m_H); //h = SHA256(h || ciphertext);
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
return false;
}
return true;
}
NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter): NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter):
TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT), TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT),
m_Server (server), m_Socket (m_Server.GetService ()), m_Server (server), m_Socket (m_Server.GetService ()),
@ -368,52 +513,28 @@ namespace transport
} }
else else
{ {
// decrypt X LogPrint (eLogDebug, "NTCP2: SessionRequest received ", bytes_transferred);
i2p::crypto::CBCDecryption decryption; uint16_t paddingLen = 0;
decryption.SetKey (i2p::context.GetIdentHash ()); if (m_Establisher->ProcessSessionRequestMessage (paddingLen))
decryption.SetIV (i2p::context.GetNTCP2IV ());
decryption.Decrypt (m_Establisher->m_SessionRequestBuffer, 32, m_Establisher->GetRemotePub ());
decryption.GetIV (m_Establisher->m_IV); // save IV for SessionCreated
// decryption key for next block
m_Establisher->KDF1Bob ();
// verify MAC and decrypt options block (32 bytes), use m_H as AD
uint8_t nonce[12], options[16];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionRequestBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, options, 16, false)) // decrypt
{ {
if (options[1] == 2) if (paddingLen > 0)
{ {
uint16_t paddingLen = bufbe16toh (options + 2); if (paddingLen <= 287 - 64) // session request is 287 bytes max
m_Establisher->m_SessionRequestBufferLen = paddingLen + 64;
m_Establisher->m3p2Len = bufbe16toh (options + 4);
// TODO: check tsA
if (paddingLen > 0)
{ {
if (paddingLen <= 287 - 64) // session request is 287 bytes max boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
{ std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionRequestBuffer + 64, paddingLen), boost::asio::transfer_all (),
std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
}
else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
Terminate ();
}
} }
else else
SendSessionCreated (); {
LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
Terminate ();
}
} }
else else
{ SendSessionCreated ();
LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]); }
Terminate ();
}
}
else else
{
LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
Terminate (); Terminate ();
}
} }
} }
@ -446,23 +567,9 @@ namespace transport
else else
{ {
LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred); LogPrint (eLogDebug, "NTCP2: SessionCreated received ", bytes_transferred);
m_Establisher->m_SessionCreatedBufferLen = 64; uint16_t paddingLen = 0;
// decrypt Y if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
i2p::crypto::CBCDecryption decryption; {
decryption.SetKey (GetRemoteIdentity ()->GetIdentHash ());
decryption.SetIV (m_Establisher->m_IV);
decryption.Decrypt (m_Establisher->m_SessionCreatedBuffer, 32, m_Establisher->GetRemotePub ());
// decryption key for next block (m_K)
m_Establisher->KDF2Alice ();
// decrypt and verify MAC
uint8_t payload[16];
uint8_t nonce[12];
memset (nonce, 0, 12); // set nonce to zero
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionCreatedBuffer + 32, 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, payload, 16, false)) // decrypt
{
uint16_t paddingLen = bufbe16toh(payload + 2);
LogPrint (eLogDebug, "NTCP2: padding length ", paddingLen);
// TODO: check tsB
if (paddingLen > 0) if (paddingLen > 0)
{ {
if (paddingLen <= 287 - 64) // session created is 287 bytes max if (paddingLen <= 287 - 64) // session created is 287 bytes max
@ -480,10 +587,7 @@ namespace transport
SendSessionConfirmed (); SendSessionConfirmed ();
} }
else else
{
LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
Terminate (); Terminate ();
}
} }
} }
@ -559,38 +663,16 @@ namespace transport
else else
{ {
LogPrint (eLogDebug, "NTCP2: SessionConfirmed received"); LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
// update AD
uint8_t h[80];
memcpy (h, m_Establisher->GetH (), 32);
memcpy (h + 32, m_Establisher->m_SessionCreatedBuffer + 32, 32); // encrypted payload
SHA256 (h, 64, h);
int paddingLength = m_Establisher->m_SessionCreatedBufferLen - 64;
if (paddingLength > 0)
{
SHA256_CTX ctx;
SHA256_Init (&ctx);
SHA256_Update (&ctx, h, 32);
SHA256_Update (&ctx, m_Establisher->m_SessionCreatedBuffer + 64, paddingLength);
SHA256_Final (h, &ctx);
}
// part 1 // part 1
uint8_t nonce[12]; uint8_t nonce[12];
CreateNonce (1, nonce); CreateNonce (1, nonce);
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer, 32, h, 32, m_Establisher->GetK (), nonce, m_Establisher->m_RemoteStaticKey, 32, false)) // decrypt S if (m_Establisher->ProcessSessionConfirmedMessagePart1 (nonce))
{ {
// part 2 // part 2
// update AD again
memcpy (h + 32, m_Establisher->m_SessionConfirmedBuffer, 48);
SHA256 (h, 80, m_Establisher->m_H);
std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC std::vector<uint8_t> buf(m_Establisher->m3p2Len - 16); // -MAC
m_Establisher->KDF3Bob ();
memset (nonce, 0, 12); // set nonce to 0 again memset (nonce, 0, 12); // set nonce to 0 again
if (i2p::crypto::AEADChaCha20Poly1305 (m_Establisher->m_SessionConfirmedBuffer + 48, m_Establisher->m3p2Len - 16, m_Establisher->GetH (), 32, m_Establisher->GetK (), nonce, buf.data (), m_Establisher->m3p2Len - 16, false)) // decrypt if (m_Establisher->ProcessSessionConfirmedMessagePart2 (nonce, buf.data ()))
{ {
// caclulate new h again for KDF data
memcpy (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->GetH (), 32); // h || ciphertext
SHA256 (m_Establisher->m_SessionConfirmedBuffer + 16, m_Establisher->m3p2Len + 32, m_Establisher->m_H); //h = SHA256(h || ciphertext);
KeyDerivationFunctionDataPhase (); KeyDerivationFunctionDataPhase ();
// Bob data phase keys // Bob data phase keys
m_SendKey = m_Kba; m_SendKey = m_Kba;
@ -599,7 +681,7 @@ namespace transport
m_ReceiveSipKey = m_Sipkeysab; m_ReceiveSipKey = m_Sipkeysab;
memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8); memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8); memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
// payload
// process RI // process RI
if (buf[0] != eNTCP2BlkRouterInfo) if (buf[0] != eNTCP2BlkRouterInfo)
{ {
@ -644,19 +726,13 @@ namespace transport
SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ()); SetRemoteIdentity (existing ? existing->GetRouterIdentity () : ri.GetRouterIdentity ());
m_Server.AddNTCP2Session (shared_from_this ()); m_Server.AddNTCP2Session (shared_from_this ());
Established (); Established ();
ReceiveLength (); ReceiveLength ();
} }
else else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
Terminate (); Terminate ();
}
} }
else else
{
LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
Terminate (); Terminate ();
}
} }
} }
@ -691,12 +767,20 @@ namespace transport
else else
{ {
i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey); i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey);
// m_NextRecivedLen comes from the network in BigEndian // m_NextReceivedLen comes from the network in BigEndian
m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key); m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key);
LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen); LogPrint (eLogDebug, "NTCP2: received length ", m_NextReceivedLen);
if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer; if (m_NextReceivedLen >= 16)
m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen]; {
Receive (); if (m_NextReceivedBuffer) delete[] m_NextReceivedBuffer;
m_NextReceivedBuffer = new uint8_t[m_NextReceivedLen];
Receive ();
}
else
{
LogPrint (eLogError, "NTCP2: received length ", m_NextReceivedLen, " is too short");
Terminate ();
}
} }
} }
@ -865,7 +949,7 @@ namespace transport
payload[s] = eNTCP2BlkPadding; // blk payload[s] = eNTCP2BlkPadding; // blk
htobe16buf (payload + s + 1, paddingSize); // size htobe16buf (payload + s + 1, paddingSize); // size
s += 3; s += 3;
RAND_bytes (payload + s, paddingSize); memset (payload + s, 0, paddingSize);
s += paddingSize; s += paddingSize;
// send // send
SendNextFrame (payload, s); SendNextFrame (payload, s);
@ -875,6 +959,7 @@ namespace transport
void NTCP2Session::SendRouterInfo () void NTCP2Session::SendRouterInfo ()
{ {
if (!IsEstablished ()) return;
auto riLen = i2p::context.GetRouterInfo ().GetBufferLen (); auto riLen = i2p::context.GetRouterInfo ().GetBufferLen ();
int paddingSize = (riLen*NTCP2_MAX_PADDING_RATIO)/100; int paddingSize = (riLen*NTCP2_MAX_PADDING_RATIO)/100;
size_t payloadLen = riLen + paddingSize + 7; // 7 = 2*3 bytes header + 1 byte RI flag size_t payloadLen = riLen + paddingSize + 7; // 7 = 2*3 bytes header + 1 byte RI flag
@ -892,6 +977,7 @@ namespace transport
void NTCP2Session::SendTermination (NTCP2TerminationReason reason) void NTCP2Session::SendTermination (NTCP2TerminationReason reason)
{ {
if (!IsEstablished ()) 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;
@ -921,7 +1007,7 @@ namespace transport
void NTCP2Session::SendLocalRouterInfo () void NTCP2Session::SendLocalRouterInfo ()
{ {
if (!IsOutgoing ()) // we send it in SessionConfirmed if (!IsOutgoing ()) // we send it in SessionConfirmed
SendRouterInfo (); m_Server.GetService ().post (std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
} }
NTCP2Server::NTCP2Server (): NTCP2Server::NTCP2Server ():

17
libi2pd/NTCP2.h

@ -1,3 +1,13 @@
/*
* Copyright (c) 2013-2018, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*
* Kovri go write your own code
*
*/
#ifndef NTCP2_H__ #ifndef NTCP2_H__
#define NTCP2_H__ #define NTCP2_H__
@ -26,6 +36,8 @@ namespace transport
const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes const int NTCP2_TERMINATION_TIMEOUT = 120; // 2 minutes
const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds const int NTCP2_TERMINATION_CHECK_TIMEOUT = 30; // 30 seconds
const int NTCP2_CLOCK_SKEW = 60; // in seconds
enum NTCP2BlockType enum NTCP2BlockType
{ {
eNTCP2BlkDateTime = 0, eNTCP2BlkDateTime = 0,
@ -91,6 +103,11 @@ namespace transport
void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart1 (const uint8_t * nonce);
void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce); void CreateSessionConfirmedMessagePart2 (const uint8_t * nonce);
bool ProcessSessionRequestMessage (uint16_t& paddingLen);
bool ProcessSessionCreatedMessage (uint16_t& paddingLen);
bool ProcessSessionConfirmedMessagePart1 (const uint8_t * nonce);
bool ProcessSessionConfirmedMessagePart2 (const uint8_t * nonce, uint8_t * m3p2Buf);
BN_CTX * m_Ctx; BN_CTX * m_Ctx;
uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519 uint8_t m_EphemeralPrivateKey[32], m_EphemeralPublicKey[32], m_RemoteEphemeralPublicKey[32]; // x25519
uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/; uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[33] /*ck*/, m_K[32] /*k*/;

4
libi2pd/NTCPSession.cpp

@ -402,7 +402,7 @@ namespace transport
uint32_t tsA1 = be32toh (tsA); uint32_t tsA1 = be32toh (tsA);
if (tsA1 < ts - NTCP_CLOCK_SKEW || tsA1 > ts + NTCP_CLOCK_SKEW) if (tsA1 < ts - NTCP_CLOCK_SKEW || tsA1 > ts + NTCP_CLOCK_SKEW)
{ {
LogPrint (eLogError, "NTCP: Phase3 time difference ", ts - tsA1, " exceeds clock skew"); LogPrint (eLogError, "NTCP: Phase3 time difference ", (int)(ts - tsA1), " exceeds clock skew");
Terminate (); Terminate ();
return; return;
} }
@ -485,7 +485,7 @@ namespace transport
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
if (tsB < ts - NTCP_CLOCK_SKEW || tsB > ts + NTCP_CLOCK_SKEW) if (tsB < ts - NTCP_CLOCK_SKEW || tsB > ts + NTCP_CLOCK_SKEW)
{ {
LogPrint (eLogError, "NTCP: Phase4 time difference ", ts - tsB, " exceeds clock skew"); LogPrint (eLogError, "NTCP: Phase4 time difference ", (int)(ts - tsB), " exceeds clock skew");
Terminate (); Terminate ();
return; return;
} }

2
libi2pd/RouterContext.cpp

@ -164,6 +164,7 @@ namespace i2p
void RouterContext::PublishNTCP2Address (int port, bool publish) void RouterContext::PublishNTCP2Address (int port, bool publish)
{ {
if (!m_NTCP2Keys) return;
if (!port) if (!port)
port = rand () % (30777 - 9111) + 9111; // I2P network ports range port = rand () % (30777 - 9111) + 9111; // I2P network ports range
bool updated = false; bool updated = false;
@ -173,6 +174,7 @@ namespace i2p
{ {
address->port = port; address->port = port;
address->ntcp2->isPublished = publish; address->ntcp2->isPublished = publish;
address->ntcp2->iv = m_NTCP2Keys->iv;
updated = true; updated = true;
} }
} }

4
libi2pd/RouterInfo.cpp

@ -668,7 +668,7 @@ namespace data
addr->host = boost::asio::ip::address::from_string (host); addr->host = boost::asio::ip::address::from_string (host);
addr->port = port; addr->port = port;
addr->transportStyle = eTransportNTCP; addr->transportStyle = eTransportNTCP;
addr->cost = 2; addr->cost = 6;
addr->date = 0; addr->date = 0;
for (const auto& it: *m_Addresses) // don't insert same address twice for (const auto& it: *m_Addresses) // don't insert same address twice
if (*it == *addr) return; if (*it == *addr) return;
@ -703,7 +703,7 @@ namespace data
auto addr = std::make_shared<Address>(); auto addr = std::make_shared<Address>();
addr->port = 0; addr->port = 0;
addr->transportStyle = eTransportNTCP; addr->transportStyle = eTransportNTCP;
addr->cost = 14; addr->cost = 3;
addr->date = 0; addr->date = 0;
addr->ntcp2.reset (new NTCP2Ext ()); addr->ntcp2.reset (new NTCP2Ext ());
addr->ntcp2->isNTCP2Only = true; // NTCP2 only address addr->ntcp2->isNTCP2Only = true; // NTCP2 only address

4
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 19 #define I2PD_VERSION_MINOR 20
#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)
@ -21,7 +21,7 @@
#define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MAJOR 0
#define I2P_VERSION_MINOR 9 #define I2P_VERSION_MINOR 9
#define I2P_VERSION_MICRO 35 #define I2P_VERSION_MICRO 36
#define I2P_VERSION_PATCH 0 #define I2P_VERSION_PATCH 0
#define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_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.19.0" android:versionCode="2" android:installLocation="auto"> <manifest package="org.purplei2p.i2pd" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.20.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" -->

Loading…
Cancel
Save