From b6175132eb84649dd98d84a8475d29a9cb9072e1 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 23 Oct 2020 21:41:42 +0800 Subject: [PATCH 01/75] android: fix for pre-init jni calls; processAssets moved to a logical place --- .../org/purplei2p/i2pd/DaemonSingleton.java | 181 -------- .../src/org/purplei2p/i2pd/DaemonWrapper.java | 387 ++++++++++++++++++ .../org/purplei2p/i2pd/ForegroundService.java | 98 +++-- .../src/org/purplei2p/i2pd/I2PDActivity.java | 236 +---------- 4 files changed, 466 insertions(+), 436 deletions(-) delete mode 100644 android/src/org/purplei2p/i2pd/DaemonSingleton.java create mode 100644 android/src/org/purplei2p/i2pd/DaemonWrapper.java diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java deleted file mode 100644 index e9e4fc06..00000000 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.purplei2p.i2pd; - -import java.util.HashSet; -import java.util.Set; -import android.os.Environment; -import android.util.Log; - -import org.purplei2p.i2pd.R; - -public class DaemonSingleton { - private static final String TAG = "i2pd"; - private static final DaemonSingleton instance = new DaemonSingleton(); - - public interface StateUpdateListener { - void daemonStateUpdate(); - } - - private final Set stateUpdateListeners = new HashSet<>(); - - public static DaemonSingleton getInstance() { - return instance; - } - - public synchronized void addStateChangeListener(StateUpdateListener listener) { - stateUpdateListeners.add(listener); - } - - public synchronized void removeStateChangeListener(StateUpdateListener listener) { - stateUpdateListeners.remove(listener); - } - - private synchronized void setState(State newState) { - if (newState == null) - throw new NullPointerException(); - - State oldState = state; - - if (oldState == null) - throw new NullPointerException(); - - if (oldState.equals(newState)) - return; - - state = newState; - fireStateUpdate1(); - } - - public synchronized void stopAcceptingTunnels() { - if (isStartedOkay()) { - setState(State.gracefulShutdownInProgress); - I2PD_JNI.stopAcceptingTunnels(); - } - } - - public synchronized void startAcceptingTunnels() { - if (isStartedOkay()) { - setState(State.startedOkay); - I2PD_JNI.startAcceptingTunnels(); - } - } - - public synchronized void reloadTunnelsConfigs() { - if (isStartedOkay()) { - I2PD_JNI.reloadTunnelsConfigs(); - } - } - - public synchronized int GetTransitTunnelsCount() { - return I2PD_JNI.GetTransitTunnelsCount(); - } - - private volatile boolean startedOkay; - - public enum State { - uninitialized(R.string.uninitialized), - starting(R.string.starting), - jniLibraryLoaded(R.string.jniLibraryLoaded), - startedOkay(R.string.startedOkay), - startFailed(R.string.startFailed), - gracefulShutdownInProgress(R.string.gracefulShutdownInProgress), - stopped(R.string.stopped); - - State(int statusStringResourceId) { - this.statusStringResourceId = statusStringResourceId; - } - - private final int statusStringResourceId; - - public int getStatusStringResourceId() { - return statusStringResourceId; - } - }; - - private volatile State state = State.uninitialized; - - public State getState() { - return state; - } - - { - setState(State.starting); - new Thread(new Runnable() { - - @Override - public void run() { - try { - I2PD_JNI.loadLibraries(); - setState(State.jniLibraryLoaded); - } catch (Throwable tr) { - lastThrowable = tr; - setState(State.startFailed); - return; - } - try { - synchronized (DaemonSingleton.this) { - I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd"); - daemonStartResult = I2PD_JNI.startDaemon(); - if ("ok".equals(daemonStartResult)) { - setState(State.startedOkay); - setStartedOkay(true); - } else - setState(State.startFailed); - } - } catch (Throwable tr) { - lastThrowable = tr; - setState(State.startFailed); - } - } - - }, "i2pdDaemonStart").start(); - } - - private Throwable lastThrowable; - private String daemonStartResult = "N/A"; - - private void fireStateUpdate1() { - Log.i(TAG, "daemon state change: " + state); - for (StateUpdateListener listener : stateUpdateListeners) { - try { - listener.daemonStateUpdate(); - } catch (Throwable tr) { - Log.e(TAG, "exception in listener ignored", tr); - } - } - } - - public Throwable getLastThrowable() { - return lastThrowable; - } - - public String getDaemonStartResult() { - return daemonStartResult; - } - - private final Object startedOkayLock = new Object(); - - public boolean isStartedOkay() { - synchronized (startedOkayLock) { - return startedOkay; - } - } - - private void setStartedOkay(boolean startedOkay) { - synchronized (startedOkayLock) { - this.startedOkay = startedOkay; - } - } - - public synchronized void stopDaemon() { - if (isStartedOkay()) { - try { - I2PD_JNI.stopDaemon(); - } catch(Throwable tr) { - Log.e(TAG, "", tr); - } - - setStartedOkay(false); - setState(State.stopped); - } - } -} diff --git a/android/src/org/purplei2p/i2pd/DaemonWrapper.java b/android/src/org/purplei2p/i2pd/DaemonWrapper.java new file mode 100644 index 00000000..7f9fcd93 --- /dev/null +++ b/android/src/org/purplei2p/i2pd/DaemonWrapper.java @@ -0,0 +1,387 @@ +package org.purplei2p.i2pd; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Set; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.AssetManager; +import android.net.ConnectivityManager; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; +import android.os.Build; +import android.os.Environment; +import android.util.Log; + +import androidx.annotation.RequiresApi; + +public class DaemonWrapper { + private static final String TAG = "i2pd"; + private final AssetManager assetManager; + private final ConnectivityManager connectivityManager; + private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/"; + private boolean assetsCopied; + + public interface StateUpdateListener { + void daemonStateUpdate(); + } + + private final Set stateUpdateListeners = new HashSet<>(); + + public synchronized void addStateChangeListener(StateUpdateListener listener) { + stateUpdateListeners.add(listener); + } + + public synchronized void removeStateChangeListener(StateUpdateListener listener) { + stateUpdateListeners.remove(listener); + } + + private synchronized void setState(State newState) { + if (newState == null) + throw new NullPointerException(); + + State oldState = state; + + if (oldState == null) + throw new NullPointerException(); + + if (oldState.equals(newState)) + return; + + state = newState; + fireStateUpdate1(); + } + + public synchronized void stopAcceptingTunnels() { + if (isStartedOkay()) { + setState(State.gracefulShutdownInProgress); + I2PD_JNI.stopAcceptingTunnels(); + } + } + + public synchronized void startAcceptingTunnels() { + if (isStartedOkay()) { + setState(State.startedOkay); + I2PD_JNI.startAcceptingTunnels(); + } + } + + public synchronized void reloadTunnelsConfigs() { + if (isStartedOkay()) { + I2PD_JNI.reloadTunnelsConfigs(); + } + } + + public synchronized int GetTransitTunnelsCount() { + return I2PD_JNI.GetTransitTunnelsCount(); + } + + private volatile boolean startedOkay; + + public enum State { + uninitialized(R.string.uninitialized), + starting(R.string.starting), + jniLibraryLoaded(R.string.jniLibraryLoaded), + startedOkay(R.string.startedOkay), + startFailed(R.string.startFailed), + gracefulShutdownInProgress(R.string.gracefulShutdownInProgress), + stopped(R.string.stopped); + + State(int statusStringResourceId) { + this.statusStringResourceId = statusStringResourceId; + } + + private final int statusStringResourceId; + + public int getStatusStringResourceId() { + return statusStringResourceId; + } + }; + + private volatile State state = State.uninitialized; + + public State getState() { + return state; + } + + public DaemonWrapper(AssetManager assetManager, ConnectivityManager connectivityManager){ + this.assetManager = assetManager; + this.connectivityManager = connectivityManager; + setState(State.starting); + new Thread(() -> { + try { + processAssets(); + I2PD_JNI.loadLibraries(); + setState(State.jniLibraryLoaded); + registerNetworkCallback(); + } catch (Throwable tr) { + lastThrowable = tr; + setState(State.startFailed); + return; + } + try { + synchronized (DaemonWrapper.this) { + I2PD_JNI.setDataDir(Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd"); + daemonStartResult = I2PD_JNI.startDaemon(); + if ("ok".equals(daemonStartResult)) { + setState(State.startedOkay); + setStartedOkay(true); + } else + setState(State.startFailed); + } + } catch (Throwable tr) { + lastThrowable = tr; + setState(State.startFailed); + } + }, "i2pdDaemonStart").start(); + } + + private Throwable lastThrowable; + private String daemonStartResult = "N/A"; + + private void fireStateUpdate1() { + Log.i(TAG, "daemon state change: " + state); + for (StateUpdateListener listener : stateUpdateListeners) { + try { + listener.daemonStateUpdate(); + } catch (Throwable tr) { + Log.e(TAG, "exception in listener ignored", tr); + } + } + } + + public Throwable getLastThrowable() { + return lastThrowable; + } + + public String getDaemonStartResult() { + return daemonStartResult; + } + + private final Object startedOkayLock = new Object(); + + public boolean isStartedOkay() { + synchronized (startedOkayLock) { + return startedOkay; + } + } + + private void setStartedOkay(boolean startedOkay) { + synchronized (startedOkayLock) { + this.startedOkay = startedOkay; + } + } + + public synchronized void stopDaemon() { + if (isStartedOkay()) { + try { + I2PD_JNI.stopDaemon(); + } catch(Throwable tr) { + Log.e(TAG, "", tr); + } + + setStartedOkay(false); + setState(State.stopped); + } + } + + 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 + FileReader fileReader = new FileReader(holderFile); + + try { + BufferedReader br = new BufferedReader(fileReader); + + try { + String line; + + while ((line = br.readLine()) != null) { + text.append(line); + } + }finally { + try { + br.close(); + } catch (IOException e) { + Log.e(TAG, "", e); + } + } + } finally { + try { + fileReader.close(); + } catch (IOException e) { + Log.e(TAG, "", e); + } + } + } 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 { + boolean deleteResult = holderFile.delete(); + if (!deleteResult) + Log.e(TAG, "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile.getAbsolutePath() + "'"); + 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 overwritten + copyAsset("addressbook"); + copyAsset("certificates"); + copyAsset("tunnels.d"); + copyAsset("i2pd.conf"); + copyAsset("subscriptions.txt"); + copyAsset("tunnels.conf"); + + // update holder file about successful copying + FileWriter writer = new FileWriter(holderFile); + try { + writer.append(versionName); + } finally { + try { + writer.close(); + } catch (IOException e) { + Log.e(TAG,"on writer close", e); + } + } + } + catch (Throwable tr) + { + Log.e(TAG,"on assets copying", tr); + } + } + } + + /** + * Copy the asset at the specified path to this app's data directory. If the + * asset is a directory, its contents are also copied. + * + * @param path + * Path to asset, relative to app's assets directory. + */ + private void copyAsset(String path) { + AssetManager manager = assetManager; + + // If we have a directory, we make it and recurse. If a file, we copy its + // contents. + try { + String[] contents = manager.list(path); + + // 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 + // to a file. That doesn't appear to be the case. If the returned array is + // null or has 0 length, we assume the path is to a file. This means empty + // directories will get turned into files. + if (contents == null || contents.length == 0) { + copyFileAsset(path); + return; + } + + // Make the directory. + File dir = new File(i2pdpath, path); + boolean result = dir.mkdirs(); + Log.d(TAG, "dir.mkdirs() returned " + result); + + // Recurse on the contents. + for (String entry : contents) { + copyAsset(path + '/' + entry); + } + } catch (IOException e) { + Log.e(TAG, "ex ignored for path='" + path + "'", e); + } + } + + /** + * Copy the asset file specified by path to app's data directory. Assumes + * parent directories have already been created. + * + * @param path + * Path to asset, relative to app's assets directory. + */ + private void copyFileAsset(String path) { + File file = new File(i2pdpath, path); + if (!file.exists()) { + try { + try (InputStream in = assetManager.open(path)) { + try (OutputStream out = new FileOutputStream(file)) { + byte[] buffer = new byte[1024]; + int read = in.read(buffer); + while (read != -1) { + out.write(buffer, 0, read); + read = in.read(buffer); + } + } + } + } catch (IOException e) { + Log.e(TAG, "", e); + } + } + } + + private void deleteRecursive(File fileOrDirectory) { + if (fileOrDirectory.isDirectory()) { + File[] files = fileOrDirectory.listFiles(); + if (files != null) { + for (File child : files) { + deleteRecursive(child); + } + } + } + boolean deleteResult = fileOrDirectory.delete(); + if (!deleteResult) + Log.e(TAG, "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory.getAbsolutePath() + "'"); + } + + public void registerNetworkCallback(){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) registerNetworkCallback0(); + } + + @TargetApi(Build.VERSION_CODES.M) + private void registerNetworkCallback0() { + NetworkRequest request = new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) + .build(); + NetworkStateCallbackImpl networkCallback = new NetworkStateCallbackImpl(); + connectivityManager.registerNetworkCallback(request, networkCallback); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + private static final class NetworkStateCallbackImpl extends ConnectivityManager.NetworkCallback { + @Override + public void onAvailable(Network network) { + super.onAvailable(network); + I2PD_JNI.onNetworkStateChanged(true); + Log.i(TAG, "NetworkCallback.onAvailable"); + } + + @Override + public void onLost(Network network) { + super.onLost(network); + I2PD_JNI.onNetworkStateChanged(false); + Log.i(TAG, " NetworkCallback.onLost"); + } + } +} diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index c1b1cc26..c1c918ac 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -19,8 +19,12 @@ public class ForegroundService extends Service { private volatile boolean shown; - private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = - new DaemonSingleton.StateUpdateListener() { + private static ForegroundService instance; + + private static volatile DaemonWrapper daemon; + + private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener = + new DaemonWrapper.StateUpdateListener() { @Override public void daemonStateUpdate() { @@ -40,7 +44,7 @@ public class ForegroundService extends Service { // Unique Identification Number for the Notification. // We use it on Notification start, and to cancel it. - private int NOTIFICATION = 1; + private static final int NOTIFICATION = 1; /** * Class for clients to access. Because we know this service always @@ -53,16 +57,25 @@ public class ForegroundService extends Service { } } + public static void init(DaemonWrapper daemon) { + ForegroundService.daemon = daemon; + initCheck(); + } + + private static void initCheck() { + if(instance!=null && daemon!=null) instance.setListener(); + } + @Override public void onCreate() { notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + instance = this; + initCheck(); + } - synchronized (this) { - DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); - if (!shown) daemonStateUpdatedListener.daemonStateUpdate(); - } - // Tell the user we started. -// Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); + private void setListener() { + daemon.addStateChangeListener(daemonStateUpdatedListener); + if (!shown) daemonStateUpdatedListener.daemonStateUpdate(); } @Override @@ -73,8 +86,17 @@ public class ForegroundService extends Service { @Override public void onDestroy() { - DaemonSingleton.getInstance().removeStateChangeListener(daemonStateUpdatedListener); cancelNotification(); + deinitCheck(); + instance=null; + } + + public static void deinit() { + deinitCheck(); + } + + private static void deinitCheck() { + if(daemon!=null && instance!=null)daemon.removeStateChangeListener(instance.daemonStateUpdatedListener); } private synchronized void cancelNotification() { @@ -101,35 +123,39 @@ public class ForegroundService extends Service { * Show a notification while this service is running. */ private synchronized void showNotification() { - // In this sample, we'll use the same text for the ticker and the expanded notification - CharSequence text = getText(DaemonSingleton.getInstance().getState().getStatusStringResourceId()); + if(daemon!=null) { + // In this sample, we'll use the same text for the ticker and the expanded notification + CharSequence text = getText(daemon.getState().getStatusStringResourceId()); - // The PendingIntent to launch our activity if the user selects this notification - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, - new Intent(this, I2PDActivity.class), 0); + // The PendingIntent to launch our activity if the user selects this notification + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + new Intent(this, I2PDActivity.class), 0); - // If earlier version channel ID is not used - // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) - String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : ""; + // If earlier version channel ID is not used + // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) + String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : ""; - // Set the info for the views that show in the notification panel. - NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId) - .setOngoing(true) - .setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon - if(Build.VERSION.SDK_INT >= 16) builder = builder.setPriority(Notification.PRIORITY_DEFAULT); - if(Build.VERSION.SDK_INT >= 21) builder = builder.setCategory(Notification.CATEGORY_SERVICE); - Notification notification = builder - .setTicker(text) // the status text - .setWhen(System.currentTimeMillis()) // the time stamp - .setContentTitle(getText(R.string.app_name)) // the label of the entry - .setContentText(text) // the contents of the entry - .setContentIntent(contentIntent) // The intent to send when the entry is clicked - .build(); + // Set the info for the views that show in the notification panel. + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId) + .setOngoing(true) + .setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon + if (Build.VERSION.SDK_INT >= 16) + builder = builder.setPriority(Notification.PRIORITY_DEFAULT); + if (Build.VERSION.SDK_INT >= 21) + builder = builder.setCategory(Notification.CATEGORY_SERVICE); + Notification notification = builder + .setTicker(text) // the status text + .setWhen(System.currentTimeMillis()) // the time stamp + .setContentTitle(getText(R.string.app_name)) // the label of the entry + .setContentText(text) // the contents of the entry + .setContentIntent(contentIntent) // The intent to send when the entry is clicked + .build(); - // Send the notification. - //mNM.notify(NOTIFICATION, notification); - startForeground(NOTIFICATION, notification); - shown = true; + // Send the notification. + //mNM.notify(NOTIFICATION, notification); + startForeground(NOTIFICATION, notification); + shown = true; + } } @RequiresApi(Build.VERSION_CODES.O) @@ -144,6 +170,4 @@ public class ForegroundService extends Service { else Log.e(TAG, "error: NOTIFICATION_SERVICE is null"); return channelId; } - - private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); } diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 777ca748..0801a655 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -1,13 +1,5 @@ package org.purplei2p.i2pd; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.BufferedReader; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Timer; @@ -24,7 +16,6 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.content.SharedPreferences; -import android.content.res.AssetManager; import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.Network; @@ -33,7 +24,6 @@ import android.net.NetworkRequest; import android.net.Uri; import android.os.Bundle; import android.os.Build; -import android.os.Environment; import android.os.IBinder; import android.os.PowerManager; import android.preference.PreferenceManager; @@ -60,25 +50,19 @@ import android.webkit.WebViewClient; import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS; public class I2PDActivity extends Activity { - private WebView webView; - 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 String PACKAGE_URI_SCHEME = "package:"; private TextView textView; - private boolean assetsCopied; - private NetworkStateCallback networkCallback; - private String i2pdpath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd/"; - //private ConfigParser parser = new ConfigParser(i2pdpath); // TODO: + //private ConfigParser parser = new ConfigParser(i2pdpath); // TODO - private static final DaemonSingleton daemon = DaemonSingleton.getInstance(); + private static volatile DaemonWrapper daemon; - private final DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton.StateUpdateListener() { + private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener = new DaemonWrapper.StateUpdateListener() { @Override public void daemonStateUpdate() { - processAssets(); runOnUiThread(() -> { try { if (textView == null) @@ -88,9 +72,9 @@ public class I2PDActivity extends Activity { textView.setText(throwableToString(tr)); return; } - DaemonSingleton.State state = daemon.getState(); - String startResultStr = DaemonSingleton.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : ""; - String graceStr = DaemonSingleton.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; + DaemonWrapper.State state = daemon.getState(); + String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : ""; + String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr)); } catch (Throwable tr) { Log.e(TAG,"error ignored",tr); @@ -117,6 +101,12 @@ public class I2PDActivity extends Activity { Log.i(TAG, "onCreate"); super.onCreate(savedInstanceState); + if (daemon==null) { + ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + daemon = new DaemonWrapper(getAssets(), connectivityManager); + } + ForegroundService.init(daemon); + textView = new TextView(this); setContentView(textView); daemon.addStateChangeListener(daemonStateUpdatedListener); @@ -145,15 +135,13 @@ public class I2PDActivity extends Activity { openBatteryOptimizationDialogIfNeeded(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - registerNetworkCallback(); - } } @Override protected void onDestroy() { super.onDestroy(); textView = null; + ForegroundService.deinit(); daemon.removeStateChangeListener(daemonStateUpdatedListener); //cancelGracefulStop0(); try { @@ -289,13 +277,13 @@ public class I2PDActivity extends Activity { case R.id.action_start_webview: setContentView(R.layout.webview); - this.webView = (WebView) findViewById(R.id.webview1); - this.webView.setWebViewClient(new WebViewClient()); + final WebView webView = findViewById(R.id.webview1); + webView.setWebViewClient(new WebViewClient()); - WebSettings webSettings = this.webView.getSettings(); + final WebSettings webSettings = webView.getSettings(); webSettings.setBuiltInZoomControls(true); webSettings.setJavaScriptEnabled(false); - this.webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort + webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort break; } @@ -335,7 +323,7 @@ public class I2PDActivity extends Activity { private static volatile Timer gracefulQuitTimer; private void i2pdGracefulStop() { - if (daemon.getState() == DaemonSingleton.State.stopped) { + if (daemon.getState() == DaemonWrapper.State.stopped) { Toast.makeText(this, R.string.already_stopped, Toast.LENGTH_SHORT).show(); return; } @@ -427,167 +415,6 @@ public class I2PDActivity extends Activity { }); } - /** - * Copy the asset at the specified path to this app's data directory. If the - * asset is a directory, its contents are also copied. - * - * @param path - * Path to asset, relative to app's assets directory. - */ - private void copyAsset(String path) { - AssetManager manager = getAssets(); - - // If we have a directory, we make it and recurse. If a file, we copy its - // contents. - try { - String[] contents = manager.list(path); - - // 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 - // to a file. That doesn't appear to be the case. If the returned array is - // null or has 0 length, we assume the path is to a file. This means empty - // directories will get turned into files. - if (contents == null || contents.length == 0) { - copyFileAsset(path); - return; - } - - // Make the directory. - File dir = new File(i2pdpath, path); - boolean result = dir.mkdirs(); - Log.d(TAG, "dir.mkdirs() returned " + result); - - // Recurse on the contents. - for (String entry : contents) { - copyAsset(path + '/' + entry); - } - } catch (IOException e) { - Log.e(TAG, "ex ignored for path='" + path + "'", e); - } - } - - /** - * Copy the asset file specified by path to app's data directory. Assumes - * parent directories have already been created. - * - * @param path - * Path to asset, relative to app's assets directory. - */ - private void copyFileAsset(String path) { - File file = new File(i2pdpath, path); - if (!file.exists()) { - try { - try (InputStream in = getAssets().open(path)) { - try (OutputStream out = new FileOutputStream(file)) { - byte[] buffer = new byte[1024]; - int read = in.read(buffer); - while (read != -1) { - out.write(buffer, 0, read); - read = in.read(buffer); - } - } - } - } catch (IOException e) { - Log.e(TAG, "", e); - } - } - } - - private void deleteRecursive(File fileOrDirectory) { - if (fileOrDirectory.isDirectory()) { - File[] files = fileOrDirectory.listFiles(); - if (files != null) { - for (File child : files) { - deleteRecursive(child); - } - } - } - boolean deleteResult = fileOrDirectory.delete(); - if (!deleteResult) - Log.e(TAG, "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory.getAbsolutePath() + "'"); - } - - 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 - FileReader fileReader = new FileReader(holderFile); - - try { - BufferedReader br = new BufferedReader(fileReader); - - try { - String line; - - while ((line = br.readLine()) != null) { - text.append(line); - } - }finally { - try { - br.close(); - } catch (IOException e) { - Log.e(TAG, "", e); - } - } - } finally { - try { - fileReader.close(); - } catch (IOException e) { - Log.e(TAG, "", e); - } - } - } 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 { - boolean deleteResult = holderFile.delete(); - if (!deleteResult) - Log.e(TAG, "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile.getAbsolutePath() + "'"); - 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 overwritten - copyAsset("addressbook"); - copyAsset("certificates"); - copyAsset("tunnels.d"); - copyAsset("i2pd.conf"); - copyAsset("subscriptions.txt"); - copyAsset("tunnels.conf"); - - // update holder file about successful copying - FileWriter writer = new FileWriter(holderFile); - try { - writer.append(versionName); - } finally { - try { - writer.close(); - } catch (IOException e) { - Log.e(TAG,"on writer close", e); - } - } - } - catch (Throwable tr) - { - Log.e(TAG,"on assets copying", tr); - } - } - } - @SuppressLint("BatteryLife") private void openBatteryOptimizationDialogIfNeeded() { boolean questionEnabled = getPreferences().getBoolean(getBatteryOptimizationPreferenceKey(), true); @@ -642,33 +469,6 @@ public class I2PDActivity extends Activity { return "show_battery_optimization" + (device == null ? "" : device); } - @TargetApi(Build.VERSION_CODES.M) - private void registerNetworkCallback() { - ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkRequest request = new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) - .build(); - networkCallback = new NetworkStateCallback(); - connectivityManager.registerNetworkCallback(request, networkCallback); - } - - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - private final class NetworkStateCallback extends ConnectivityManager.NetworkCallback { - @Override - public void onAvailable(Network network) { - super.onAvailable(network); - I2PD_JNI.onNetworkStateChanged(true); - Log.i(TAG, "NetworkCallback.onAvailable"); - } - - @Override - public void onLost(Network network) { - super.onLost(network); - I2PD_JNI.onNetworkStateChanged(false); - Log.i(TAG, " NetworkCallback.onLost"); - } - } - private void quit() { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { From db3e48a81a87c8ce70e727f815c011c7a3f62d52 Mon Sep 17 00:00:00 2001 From: user Date: Sat, 24 Oct 2020 03:52:53 +0800 Subject: [PATCH 02/75] android: more logical daemon state changes --- .../src/org/purplei2p/i2pd/DaemonWrapper.java | 41 +++---- .../org/purplei2p/i2pd/ForegroundService.java | 111 ++++++++++-------- .../src/org/purplei2p/i2pd/I2PDActivity.java | 53 +++++---- 3 files changed, 104 insertions(+), 101 deletions(-) diff --git a/android/src/org/purplei2p/i2pd/DaemonWrapper.java b/android/src/org/purplei2p/i2pd/DaemonWrapper.java index 7f9fcd93..414a3ed1 100644 --- a/android/src/org/purplei2p/i2pd/DaemonWrapper.java +++ b/android/src/org/purplei2p/i2pd/DaemonWrapper.java @@ -12,7 +12,6 @@ import java.util.HashSet; import java.util.Set; import android.annotation.TargetApi; -import android.content.Context; import android.content.res.AssetManager; import android.net.ConnectivityManager; import android.net.Network; @@ -32,7 +31,7 @@ public class DaemonWrapper { private boolean assetsCopied; public interface StateUpdateListener { - void daemonStateUpdate(); + void daemonStateUpdate(State oldValue, State newValue); } private final Set stateUpdateListeners = new HashSet<>(); @@ -58,7 +57,7 @@ public class DaemonWrapper { return; state = newState; - fireStateUpdate1(); + fireStateUpdate1(oldState, newState); } public synchronized void stopAcceptingTunnels() { @@ -81,12 +80,10 @@ public class DaemonWrapper { } } - public synchronized int GetTransitTunnelsCount() { + public int getTransitTunnelsCount() { return I2PD_JNI.GetTransitTunnelsCount(); } - private volatile boolean startedOkay; - public enum State { uninitialized(R.string.uninitialized), starting(R.string.starting), @@ -105,7 +102,11 @@ public class DaemonWrapper { public int getStatusStringResourceId() { return statusStringResourceId; } - }; + + public boolean isStartedOkay() { + return equals(State.startedOkay) || equals(State.gracefulShutdownInProgress); + } + } private volatile State state = State.uninitialized; @@ -134,7 +135,6 @@ public class DaemonWrapper { daemonStartResult = I2PD_JNI.startDaemon(); if ("ok".equals(daemonStartResult)) { setState(State.startedOkay); - setStartedOkay(true); } else setState(State.startFailed); } @@ -148,11 +148,11 @@ public class DaemonWrapper { private Throwable lastThrowable; private String daemonStartResult = "N/A"; - private void fireStateUpdate1() { + private void fireStateUpdate1(State oldValue, State newValue) { Log.i(TAG, "daemon state change: " + state); for (StateUpdateListener listener : stateUpdateListeners) { try { - listener.daemonStateUpdate(); + listener.daemonStateUpdate(oldValue, newValue); } catch (Throwable tr) { Log.e(TAG, "exception in listener ignored", tr); } @@ -167,18 +167,8 @@ public class DaemonWrapper { return daemonStartResult; } - private final Object startedOkayLock = new Object(); - public boolean isStartedOkay() { - synchronized (startedOkayLock) { - return startedOkay; - } - } - - private void setStartedOkay(boolean startedOkay) { - synchronized (startedOkayLock) { - this.startedOkay = startedOkay; - } + return getState().isStartedOkay(); } public synchronized void stopDaemon() { @@ -189,7 +179,6 @@ public class DaemonWrapper { Log.e(TAG, "", tr); } - setStartedOkay(false); setState(State.stopped); } } @@ -197,7 +186,7 @@ public class DaemonWrapper { private void processAssets() { if (!assetsCopied) { try { - assetsCopied = true; // prevent from running on every state update + assetsCopied = true; File holderFile = new File(i2pdpath, "assets.ready"); String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX @@ -283,12 +272,10 @@ public class DaemonWrapper { * Path to asset, relative to app's assets directory. */ private void copyAsset(String path) { - AssetManager manager = assetManager; - // If we have a directory, we make it and recurse. If a file, we copy its // contents. try { - String[] contents = manager.list(path); + String[] contents = assetManager.list(path); // 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 @@ -355,7 +342,7 @@ public class DaemonWrapper { Log.e(TAG, "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory.getAbsolutePath() + "'"); } - public void registerNetworkCallback(){ + private void registerNetworkCallback(){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) registerNetworkCallback0(); } diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index c1c918ac..c97b7f1f 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -23,22 +23,28 @@ public class ForegroundService extends Service { private static volatile DaemonWrapper daemon; + private static final Object initDeinitLock = new Object(); + private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener = new DaemonWrapper.StateUpdateListener() { @Override - public void daemonStateUpdate() { - try { - synchronized (ForegroundService.this) { - if (shown) cancelNotification(); - showNotification(); - } - } catch (Throwable tr) { - Log.e(TAG,"error ignored",tr); - } + public void daemonStateUpdate(DaemonWrapper.State oldValue, DaemonWrapper.State newValue) { + updateNotificationText(); } }; + private void updateNotificationText() { + try { + synchronized (initDeinitLock) { + if (shown) cancelNotification(); + showNotification(); + } + } catch (Throwable tr) { + Log.e(TAG,"error ignored",tr); + } + } + private NotificationManager notificationManager; @@ -63,7 +69,9 @@ public class ForegroundService extends Service { } private static void initCheck() { - if(instance!=null && daemon!=null) instance.setListener(); + synchronized (initDeinitLock) { + if (instance != null && daemon != null) instance.setListener(); + } } @Override @@ -75,7 +83,7 @@ public class ForegroundService extends Service { private void setListener() { daemon.addStateChangeListener(daemonStateUpdatedListener); - if (!shown) daemonStateUpdatedListener.daemonStateUpdate(); + updateNotificationText(); } @Override @@ -96,18 +104,23 @@ public class ForegroundService extends Service { } private static void deinitCheck() { - if(daemon!=null && instance!=null)daemon.removeStateChangeListener(instance.daemonStateUpdatedListener); + synchronized (initDeinitLock) { + if (daemon != null && instance != null) + daemon.removeStateChangeListener(instance.daemonStateUpdatedListener); + } } - private synchronized void cancelNotification() { - // Cancel the persistent notification. - notificationManager.cancel(NOTIFICATION); + private void cancelNotification() { + synchronized (initDeinitLock) { + // Cancel the persistent notification. + notificationManager.cancel(NOTIFICATION); - stopForeground(true); + stopForeground(true); - // Tell the user we stopped. - //Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show(); - shown=false; + // Tell the user we stopped. + //Toast.makeText(this, R.string.i2pd_service_stopped, Toast.LENGTH_SHORT).show(); + shown = false; + } } @Override @@ -122,39 +135,41 @@ public class ForegroundService extends Service { /** * Show a notification while this service is running. */ - private synchronized void showNotification() { - if(daemon!=null) { - // In this sample, we'll use the same text for the ticker and the expanded notification - CharSequence text = getText(daemon.getState().getStatusStringResourceId()); + private void showNotification() { + synchronized (initDeinitLock) { + if (daemon != null) { + // In this sample, we'll use the same text for the ticker and the expanded notification + CharSequence text = getText(daemon.getState().getStatusStringResourceId()); - // The PendingIntent to launch our activity if the user selects this notification - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, - new Intent(this, I2PDActivity.class), 0); + // The PendingIntent to launch our activity if the user selects this notification + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + new Intent(this, I2PDActivity.class), 0); - // If earlier version channel ID is not used - // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) - String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : ""; + // If earlier version channel ID is not used + // https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context) + String channelId = Build.VERSION.SDK_INT >= 26 ? createNotificationChannel() : ""; - // Set the info for the views that show in the notification panel. - NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId) - .setOngoing(true) - .setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon - if (Build.VERSION.SDK_INT >= 16) - builder = builder.setPriority(Notification.PRIORITY_DEFAULT); - if (Build.VERSION.SDK_INT >= 21) - builder = builder.setCategory(Notification.CATEGORY_SERVICE); - Notification notification = builder - .setTicker(text) // the status text - .setWhen(System.currentTimeMillis()) // the time stamp - .setContentTitle(getText(R.string.app_name)) // the label of the entry - .setContentText(text) // the contents of the entry - .setContentIntent(contentIntent) // The intent to send when the entry is clicked - .build(); + // Set the info for the views that show in the notification panel. + NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId) + .setOngoing(true) + .setSmallIcon(R.drawable.itoopie_notification_icon); // the status icon + if (Build.VERSION.SDK_INT >= 16) + builder = builder.setPriority(Notification.PRIORITY_DEFAULT); + if (Build.VERSION.SDK_INT >= 21) + builder = builder.setCategory(Notification.CATEGORY_SERVICE); + Notification notification = builder + .setTicker(text) // the status text + .setWhen(System.currentTimeMillis()) // the time stamp + .setContentTitle(getText(R.string.app_name)) // the label of the entry + .setContentText(text) // the contents of the entry + .setContentIntent(contentIntent) // The intent to send when the entry is clicked + .build(); - // Send the notification. - //mNM.notify(NOTIFICATION, notification); - startForeground(NOTIFICATION, notification); - shown = true; + // Send the notification. + //mNM.notify(NOTIFICATION, notification); + startForeground(NOTIFICATION, notification); + shown = true; + } } } diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 0801a655..97870e63 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -7,7 +7,6 @@ import java.util.TimerTask; import android.Manifest; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.content.ActivityNotFoundException; @@ -18,9 +17,6 @@ import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.net.ConnectivityManager; -import android.net.Network; -import android.net.NetworkCapabilities; -import android.net.NetworkRequest; import android.net.Uri; import android.os.Bundle; import android.os.Build; @@ -36,7 +32,6 @@ import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -62,26 +57,31 @@ public class I2PDActivity extends Activity { private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener = new DaemonWrapper.StateUpdateListener() { @Override - public void daemonStateUpdate() { - runOnUiThread(() -> { - try { - if (textView == null) - return; - Throwable tr = daemon.getLastThrowable(); - if (tr!=null) { - textView.setText(throwableToString(tr)); - return; - } - DaemonWrapper.State state = daemon.getState(); - String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : ""; - String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; - textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr)); - } catch (Throwable tr) { - Log.e(TAG,"error ignored",tr); - } - }); + public void daemonStateUpdate(DaemonWrapper.State oldValue, DaemonWrapper.State newValue) { + updateStatusText(); } }; + + private void updateStatusText() { + runOnUiThread(() -> { + try { + if (textView == null) + return; + Throwable tr = daemon.getLastThrowable(); + if (tr!=null) { + textView.setText(throwableToString(tr)); + return; + } + DaemonWrapper.State state = daemon.getState(); + String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : ""; + String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; + textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr)); + } catch (Throwable tr) { + Log.e(TAG,"error ignored",tr); + } + }); + } + private static volatile long graceStartedMillis; private static final Object graceStartedMillis_LOCK = new Object(); private Menu optionsMenu; @@ -110,7 +110,7 @@ public class I2PDActivity extends Activity { textView = new TextView(this); setContentView(textView); daemon.addStateChangeListener(daemonStateUpdatedListener); - daemonStateUpdatedListener.daemonStateUpdate(); + daemonStateUpdatedListener.daemonStateUpdate(DaemonWrapper.State.uninitialized, daemon.getState()); // request permissions if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -372,9 +372,10 @@ public class I2PDActivity extends Activity { if (gracefulQuitTimerOld != null) gracefulQuitTimerOld.cancel(); - if(daemon.GetTransitTunnelsCount() <= 0) { // no tunnels left + if(daemon.getTransitTunnelsCount() <= 0) { // no tunnels left Log.d(TAG, "no transit tunnels left, stopping"); i2pdStop(); + return; } final Timer gracefulQuitTimer = new Timer(true); @@ -390,7 +391,7 @@ public class I2PDActivity extends Activity { final TimerTask tickerTask = new TimerTask() { @Override public void run() { - daemonStateUpdatedListener.daemonStateUpdate(); + updateStatusText(); } }; gracefulQuitTimer.scheduleAtFixedRate(tickerTask, 0/*start delay*/, 1000/*millis period*/); From bfcf3cfbf132ff904bcfca6557da061db4090bd5 Mon Sep 17 00:00:00 2001 From: user Date: Sat, 24 Oct 2020 12:40:22 +0800 Subject: [PATCH 03/75] Fixes #1563 --- android/AndroidManifest.xml | 11 ++--- android/build.gradle | 4 +- .../{webview.xml => activity_web_console.xml} | 4 +- .../src/org/purplei2p/i2pd/I2PDActivity.java | 11 +---- .../purplei2p/i2pd/WebConsoleActivity.java | 41 +++++++++++++++++++ 5 files changed, 55 insertions(+), 16 deletions(-) rename android/res/layout/{webview.xml => activity_web_console.xml} (82%) create mode 100644 android/src/org/purplei2p/i2pd/WebConsoleActivity.java diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 88985138..8b011b8e 100755 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -15,10 +15,10 @@ android:allowBackup="true" android:icon="@drawable/icon" android:label="@string/app_name" - android:theme="@android:style/Theme.Holo.Light.DarkActionBar" android:requestLegacyExternalStorage="true" - android:usesCleartextTraffic="true" - > + android:theme="@android:style/Theme.Holo.Light.DarkActionBar" + android:usesCleartextTraffic="true"> + @@ -31,10 +31,10 @@ android:label="@string/app_name"> + - @@ -52,4 +52,5 @@ android:value="org.purplei2p.i2pd.I2PDPermsAskerActivity" /> - + + \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index ace2047a..7d25e28b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,6 +21,8 @@ repositories { dependencies { implementation 'androidx.core:core:1.0.2' + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' } android { @@ -90,7 +92,7 @@ android { } } -ext.abiCodes = ['armeabi-v7a':1, 'x86':2, 'arm64-v8a':3, 'x86_64':4] +ext.abiCodes = ['armeabi-v7a': 1, 'x86': 2, 'arm64-v8a': 3, 'x86_64': 4] import com.android.build.OutputFile android.applicationVariants.all { variant -> diff --git a/android/res/layout/webview.xml b/android/res/layout/activity_web_console.xml similarity index 82% rename from android/res/layout/webview.xml rename to android/res/layout/activity_web_console.xml index 887896a7..5724b387 100644 --- a/android/res/layout/webview.xml +++ b/android/res/layout/activity_web_console.xml @@ -1,12 +1,14 @@ + + tools:context=".WebConsoleActivity"> + diff --git a/android/src/org/purplei2p/i2pd/I2PDActivity.java b/android/src/org/purplei2p/i2pd/I2PDActivity.java index 97870e63..9645d4f7 100755 --- a/android/src/org/purplei2p/i2pd/I2PDActivity.java +++ b/android/src/org/purplei2p/i2pd/I2PDActivity.java @@ -276,15 +276,8 @@ public class I2PDActivity extends Activity { return true; case R.id.action_start_webview: - setContentView(R.layout.webview); - final WebView webView = findViewById(R.id.webview1); - webView.setWebViewClient(new WebViewClient()); - - final WebSettings webSettings = webView.getSettings(); - webSettings.setBuiltInZoomControls(true); - webSettings.setJavaScriptEnabled(false); - webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort - break; + startActivity(new Intent(getApplicationContext(), WebConsoleActivity.class)); + return true; } return super.onOptionsItemSelected(item); diff --git a/android/src/org/purplei2p/i2pd/WebConsoleActivity.java b/android/src/org/purplei2p/i2pd/WebConsoleActivity.java new file mode 100644 index 00000000..24e6baeb --- /dev/null +++ b/android/src/org/purplei2p/i2pd/WebConsoleActivity.java @@ -0,0 +1,41 @@ +package org.purplei2p.i2pd; + +import androidx.appcompat.app.AppCompatActivity; + +import android.app.Activity; +import android.os.Bundle; +import android.view.MenuItem; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import java.util.Objects; + +public class WebConsoleActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_web_console); + + Objects.requireNonNull(getActionBar()).setDisplayHomeAsUpEnabled(true); + + final WebView webView = findViewById(R.id.webview1); + webView.setWebViewClient(new WebViewClient()); + + final WebSettings webSettings = webView.getSettings(); + webSettings.setBuiltInZoomControls(true); + webSettings.setJavaScriptEnabled(false); + webView.loadUrl("http://127.0.0.1:7070"); // TODO: instead 7070 I2Pd....HttpPort + } + + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + + if (id==android.R.id.home) { + finish(); + return true; + } + return false; + } +} From e9f11e204e02314c455da391940d33a2834e7be2 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 24 Oct 2020 21:22:48 -0400 Subject: [PATCH 04/75] check if session is terminated before send --- libi2pd_client/I2CP.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 80274d86..d5436936 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -806,17 +806,23 @@ namespace client void I2CPSession::SendMessagePayloadMessage (const uint8_t * payload, size_t len) { // we don't use SendI2CPMessage to eliminate additional copy - auto l = len + 10 + I2CP_HEADER_SIZE; - uint8_t * buf = new uint8_t[l]; - htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); - buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE; - htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID); - htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++); - htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); - memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); - boost::asio::async_write (*m_Socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (), - std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, buf)); + auto socket = m_Socket; + if (socket) + { + auto l = len + 10 + I2CP_HEADER_SIZE; + uint8_t * buf = new uint8_t[l]; + htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); + buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE; + htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID); + htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++); + htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); + memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); + boost::asio::async_write (*socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (), + std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), + std::placeholders::_1, std::placeholders::_2, buf)); + } + else + LogPrint (eLogError, "I2CP: Can't write to the socket"); } I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread): From b35f43d79e48116e18931c994a416497e3107924 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 25 Oct 2020 17:20:15 -0400 Subject: [PATCH 05/75] initial implementation of STREAM FORWARD --- libi2pd_client/SAM.cpp | 92 ++++++++++++++++++++++++++++++++++++++---- libi2pd_client/SAM.h | 9 ++++- 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 63b9c7ed..2bdbf1ee 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -54,6 +54,7 @@ namespace client break; } case eSAMSocketTypeAcceptor: + case eSAMSocketTypeForward: { if (Session) { @@ -263,6 +264,8 @@ namespace client ProcessStreamConnect (separator + 1, bytes_transferred - (separator - m_Buffer) - 1, bytes_transferred - (eol - m_Buffer) - 1); else if (!strcmp (m_Buffer, SAM_STREAM_ACCEPT)) ProcessStreamAccept (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); + else if (!strcmp (m_Buffer, SAM_STREAM_FORWARD)) + ProcessStreamForward (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); else if (!strcmp (m_Buffer, SAM_DEST_GENERATE)) ProcessDestGenerate (separator + 1, bytes_transferred - (separator - m_Buffer) - 1); else if (!strcmp (m_Buffer, SAM_NAMING_LOOKUP)) @@ -358,12 +361,12 @@ namespace client std::shared_ptr forward = nullptr; if ((type == eSAMSessionTypeDatagram || type == eSAMSessionTypeRaw) && - params.find(SAM_VALUE_HOST) != params.end() && params.find(SAM_VALUE_PORT) != params.end()) + params.find(SAM_PARAM_HOST) != params.end() && params.find(SAM_PARAM_PORT) != params.end()) { // udp forward selected boost::system::error_code e; // TODO: support hostnames in udp forward - auto addr = boost::asio::ip::address::from_string(params[SAM_VALUE_HOST], e); + auto addr = boost::asio::ip::address::from_string(params[SAM_PARAM_HOST], e); if (e) { // not an ip address @@ -371,7 +374,7 @@ namespace client return; } - auto port = std::stoi(params[SAM_VALUE_PORT]); + auto port = std::stoi(params[SAM_PARAM_PORT]); if (port == -1) { SendI2PError("Invalid port"); @@ -565,6 +568,51 @@ namespace client SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); } + void SAMSocket::ProcessStreamForward (char * buf, size_t len) + { + LogPrint (eLogDebug, "SAM: stream forward: ", buf); + std::map params; + ExtractParams (buf, params); + std::string& id = params[SAM_PARAM_ID]; + auto session = m_Owner.FindSession (id); + if (!session) + { + SendMessageReply (SAM_STREAM_STATUS_INVALID_ID, strlen(SAM_STREAM_STATUS_INVALID_ID), true); + return; + } + if (session->localDestination->IsAcceptingStreams ()) + { + SendI2PError ("Already accepting"); + return; + } + auto it = params.find (SAM_PARAM_PORT); + if (it == params.end ()) + { + SendI2PError ("PORT is missing"); + return; + } + auto port = std::stoi (it->second); + if (port <= 0 || port >= 0xFFFF) + { + SendI2PError ("Invalid PORT"); + return; + } + boost::system::error_code ec; + auto ep = m_Socket.remote_endpoint (ec); + if (ec) + { + SendI2PError ("Socket error"); + return; + } + ep.port (port); + m_SocketType = eSAMSocketTypeForward; + m_ID = id; + m_IsAccepting = true; + session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward, + shared_from_this (), std::placeholders::_1, ep)); + SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); + } + size_t SAMSocket::ProcessDatagramSend (char * buf, size_t len, const char * data) { LogPrint (eLogDebug, "SAM: datagram send: ", buf, " ", len); @@ -917,6 +965,33 @@ namespace client LogPrint (eLogWarning, "SAM: I2P acceptor has been reset"); } + void SAMSocket::HandleI2PForward (std::shared_ptr stream, + boost::asio::ip::tcp::endpoint ep) + { + if (stream) + { + LogPrint (eLogDebug, "SAM: incoming forward I2P connection for session ", m_ID); + auto newSocket = std::make_shared(m_Owner); + newSocket->SetSocketType (eSAMSocketTypeStream); + auto s = shared_from_this (); + newSocket->GetSocket ().async_connect (ep, + [s, newSocket, stream](const boost::system::error_code& ecode) + { + if (!ecode) + { + s->m_Owner.AddSocket (newSocket); + newSocket->Receive (); + newSocket->m_Stream = stream; + newSocket->I2PReceive (); + } + else + stream->AsyncClose (); + }); + } + else + LogPrint (eLogWarning, "SAM: I2P forward acceptor has been reset"); + } + void SAMSocket::HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len) { LogPrint (eLogDebug, "SAM: datagram received ", len); @@ -1072,6 +1147,12 @@ namespace client std::placeholders::_1, newSocket)); } + void SAMBridge::AddSocket(std::shared_ptr socket) + { + std::unique_lock lock(m_OpenSocketsMutex); + m_OpenSockets.push_back(socket); + } + void SAMBridge::RemoveSocket(const std::shared_ptr & socket) { std::unique_lock lock(m_OpenSocketsMutex); @@ -1087,10 +1168,7 @@ namespace client if (!ec) { LogPrint (eLogDebug, "SAM: new connection from ", ep); - { - std::unique_lock l(m_OpenSocketsMutex); - m_OpenSockets.push_back(socket); - } + AddSocket (socket); socket->ReceiveHandshake (); } else diff --git a/libi2pd_client/SAM.h b/libi2pd_client/SAM.h index 7b1702f5..fafd7d1c 100644 --- a/libi2pd_client/SAM.h +++ b/libi2pd_client/SAM.h @@ -48,6 +48,7 @@ namespace client const char SAM_STREAM_STATUS_CANT_REACH_PEER[] = "STREAM STATUS RESULT=CANT_REACH_PEER\n"; const char SAM_STREAM_STATUS_I2P_ERROR[] = "STREAM STATUS RESULT=I2P_ERROR\n"; const char SAM_STREAM_ACCEPT[] = "STREAM ACCEPT"; + const char SAM_STREAM_FORWARD[] = "STREAM FORWARD"; const char SAM_DATAGRAM_SEND[] = "DATAGRAM SEND"; const char SAM_RAW_SEND[] = "RAW SEND"; const char SAM_DEST_GENERATE[] = "DEST GENERATE"; @@ -69,14 +70,14 @@ namespace client const char SAM_PARAM_SIGNATURE_TYPE[] = "SIGNATURE_TYPE"; const char SAM_PARAM_CRYPTO_TYPE[] = "CRYPTO_TYPE"; const char SAM_PARAM_SIZE[] = "SIZE"; + const char SAM_PARAM_HOST[] = "HOST"; + const char SAM_PARAM_PORT[] = "PORT"; const char SAM_VALUE_TRANSIENT[] = "TRANSIENT"; const char SAM_VALUE_STREAM[] = "STREAM"; const char SAM_VALUE_DATAGRAM[] = "DATAGRAM"; const char SAM_VALUE_RAW[] = "RAW"; const char SAM_VALUE_TRUE[] = "true"; const char SAM_VALUE_FALSE[] = "false"; - const char SAM_VALUE_HOST[] = "HOST"; - const char SAM_VALUE_PORT[] = "PORT"; enum SAMSocketType { @@ -84,6 +85,7 @@ namespace client eSAMSocketTypeSession, eSAMSocketTypeStream, eSAMSocketTypeAcceptor, + eSAMSocketTypeForward, eSAMSocketTypeTerminated }; @@ -121,6 +123,7 @@ namespace client void I2PReceive (); void HandleI2PReceive (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleI2PAccept (std::shared_ptr stream); + void HandleI2PForward (std::shared_ptr stream, boost::asio::ip::tcp::endpoint ep); void HandleWriteI2PData (const boost::system::error_code& ecode, size_t sz); void HandleI2PDatagramReceive (const i2p::data::IdentityEx& from, uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); void HandleI2PRawDatagramReceive (uint16_t fromPort, uint16_t toPort, const uint8_t * buf, size_t len); @@ -128,6 +131,7 @@ namespace client void ProcessSessionCreate (char * buf, size_t len); void ProcessStreamConnect (char * buf, size_t len, size_t rem); void ProcessStreamAccept (char * buf, size_t len); + void ProcessStreamForward (char * buf, size_t len); void ProcessDestGenerate (char * buf, size_t len); void ProcessNamingLookup (char * buf, size_t len); void SendI2PError(const std::string & msg); @@ -205,6 +209,7 @@ namespace client /** send raw data to remote endpoint from our UDP Socket */ void SendTo(const uint8_t * buf, size_t len, std::shared_ptr remote); + void AddSocket(std::shared_ptr socket); void RemoveSocket(const std::shared_ptr & socket); bool ResolveSignatureType (const std::string& name, i2p::data::SigningKeyType& type) const; From e41bbcb2bb12ae8a981c04f3aeec787fb53bbd92 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 Oct 2020 11:19:37 -0400 Subject: [PATCH 06/75] handle SILENT for STREAM FORWARD --- libi2pd_client/SAM.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 2bdbf1ee..2e436637 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -608,6 +608,8 @@ namespace client m_SocketType = eSAMSocketTypeForward; m_ID = id; m_IsAccepting = true; + std::string& silent = params[SAM_PARAM_SILENT]; + if (silent == SAM_VALUE_TRUE) m_IsSilent = true; session->localDestination->AcceptStreams (std::bind (&SAMSocket::HandleI2PForward, shared_from_this (), std::placeholders::_1, ep)); SendMessageReply (SAM_STREAM_STATUS_OK, strlen(SAM_STREAM_STATUS_OK), false); @@ -982,7 +984,17 @@ namespace client s->m_Owner.AddSocket (newSocket); newSocket->Receive (); newSocket->m_Stream = stream; - newSocket->I2PReceive (); + newSocket->m_ID = s->m_ID; + if (!s->m_IsSilent) + { + // get remote peer address + auto dest = stream->GetRemoteIdentity()->ToBase64 (); + memcpy (newSocket->m_StreamBuffer, dest.c_str (), dest.length ()); + newSocket->m_StreamBuffer[dest.length ()] = '\n'; + newSocket->HandleI2PReceive (boost::system::error_code (),dest.length () + 1); // we send identity like it has been received from stream + } + else + newSocket->I2PReceive (); } else stream->AsyncClose (); From cc0367b079f958a9ab4e796ac3a2cccf39a0730a Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 26 Oct 2020 16:06:19 -0400 Subject: [PATCH 07/75] always send STREAM STATUS reply to STREAM FORWARD --- daemon/HTTPServer.cpp | 1 + libi2pd_client/SAM.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 3b9f6eaa..59c530f9 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -838,6 +838,7 @@ namespace http { case i2p::client::eSAMSocketTypeSession : s << "session"; break; case i2p::client::eSAMSocketTypeStream : s << "stream"; break; case i2p::client::eSAMSocketTypeAcceptor : s << "acceptor"; break; + case i2p::client::eSAMSocketTypeForward : s << "forward"; break; default: s << "unknown"; break; } s << " [" << it->GetSocket ().remote_endpoint() << "]"; diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 2e436637..6624c6f9 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -199,7 +199,7 @@ namespace client { LogPrint (eLogDebug, "SAMSocket::SendMessageReply, close=",close?"true":"false", " reason: ", msg); - if (!m_IsSilent) + if (!m_IsSilent || m_SocketType == eSAMSocketTypeForward) boost::asio::async_write (m_Socket, boost::asio::buffer (msg, len), boost::asio::transfer_all (), std::bind(&SAMSocket::HandleMessageReplySent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, close)); From 56f3bdd74677b3c87fe738e95653557e41da2168 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 27 Oct 2020 11:52:02 +0300 Subject: [PATCH 08/75] [win32] handle WinAPI errors in SSU Windows can throw WinAPI errors which are not handled by boost asio Signed-off-by: R4SAS --- libi2pd/SSU.cpp | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index 07c95a7a..d29f5cd7 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -13,6 +13,10 @@ #include "NetDb.hpp" #include "SSU.h" +#ifdef _WIN32 +#include +#endif + namespace i2p { namespace transport @@ -247,11 +251,17 @@ namespace transport void SSUServer::HandleReceivedFrom (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet) { - if (!ecode || - ecode == boost::asio::error::connection_refused || - ecode == boost::asio::error::connection_reset || - ecode == boost::asio::error::network_unreachable || - ecode == boost::asio::error::host_unreachable) + if (!ecode + || ecode == boost::asio::error::connection_refused + || ecode == boost::asio::error::connection_reset + || ecode == boost::asio::error::network_unreachable + || ecode == boost::asio::error::host_unreachable +#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO + || ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_ + || ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_ + || ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_ +#endif + ) // just try continue reading when received ICMP response otherwise socket can crash, // but better to find out which host were sent it and mark that router as unreachable { @@ -300,11 +310,17 @@ namespace transport void SSUServer::HandleReceivedFromV6 (const boost::system::error_code& ecode, std::size_t bytes_transferred, SSUPacket * packet) { - if (!ecode || - ecode == boost::asio::error::connection_refused || - ecode == boost::asio::error::connection_reset || - ecode == boost::asio::error::network_unreachable || - ecode == boost::asio::error::host_unreachable) + if (!ecode + || ecode == boost::asio::error::connection_refused + || ecode == boost::asio::error::connection_reset + || ecode == boost::asio::error::network_unreachable + || ecode == boost::asio::error::host_unreachable +#ifdef _WIN32 // windows can throw WinAPI error, which is not handled by ASIO + || ecode.value() == boost::winapi::ERROR_CONNECTION_REFUSED_ + || ecode.value() == boost::winapi::ERROR_NETWORK_UNREACHABLE_ + || ecode.value() == boost::winapi::ERROR_HOST_UNREACHABLE_ +#endif + ) // just try continue reading when received ICMP response otherwise socket can crash, // but better to find out which host were sent it and mark that router as unreachable { From c400372a79dcc93b75121f6fc5ba5e938a6cc185 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 27 Oct 2020 08:32:38 -0400 Subject: [PATCH 09/75] create new ratchets session if previous was not replied --- libi2pd/ECIESX25519AEADRatchetSession.h | 1 + libi2pd/Garlic.h | 1 + libi2pd/Streaming.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index af0b5de5..1c377b28 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -169,6 +169,7 @@ namespace garlic bool IsInactive (uint64_t ts) const { return ts > m_LastActivityTimestamp + ECIESX25519_INACTIVITY_TIMEOUT && CanBeRestarted (ts); } bool IsRatchets () const { return true; }; + bool IsReadyToSend () const { return m_State != eSessionStateNewSessionSent; }; uint64_t GetLastActivityTimestamp () const { return m_LastActivityTimestamp; }; private: diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index f1e363df..3c5d5de6 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -114,6 +114,7 @@ namespace garlic virtual bool CleanupUnconfirmedTags () { return false; }; // for I2CP, override in ElGamalAESSession virtual bool MessageConfirmed (uint32_t msgID); virtual bool IsRatchets () const { return false; }; + virtual bool IsReadyToSend () const { return true; }; virtual uint64_t GetLastActivityTimestamp () const { return 0; }; // non-zero for rathets only void SetLeaseSetUpdated () diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index ab08f41f..21c6d6ce 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -756,7 +756,7 @@ namespace stream return; } } - if (!m_RoutingSession || !m_RoutingSession->GetOwner ()) // expired and detached + if (!m_RoutingSession || !m_RoutingSession->GetOwner () || !m_RoutingSession->IsReadyToSend ()) // expired and detached or new session sent m_RoutingSession = m_LocalDestination.GetOwner ()->GetRoutingSession (m_RemoteLeaseSet, true); if (!m_CurrentOutboundTunnel && m_RoutingSession) // first message to send { From c63818f355dae64727e82cb01c37a3f4a6fdf09a Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 27 Oct 2020 12:27:08 -0400 Subject: [PATCH 10/75] 2.34.0 --- ChangeLog | 29 +++++++++++++++++++ Win32/installer.iss | 2 +- android/build.gradle | 4 +-- appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 5 +++- contrib/rpm/i2pd.spec | 5 +++- debian/changelog | 6 ++++ libi2pd/version.h | 2 +- qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml | 1 + 9 files changed, 49 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index beef7a5a..dbce5fb2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,35 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.34.0] - 2020-10-27 +### Added +- Ping responses for streaming +- STREAM FORWARD for SAM +- Tunnels through ECIES-x25519 routers +- Single thread for I2CP +- Shared transient destination between proxies +- Database lookups from ECIES destinations with ratchets response +- Handle WebDAV HTTP methods +- Don't try to connect or build tunnels if offline +- Validate IP when trying connect to remote peer +- Handle ICMP responses and WinAPI errors for SSU +### Changed +- Removed NTCP +- Dropped gcc 4.7 support +- Encyption type 0,4 by default for client tunnels +- Stripped out some HTTP header for HTTP server response +- HTTP 1.1 addressbook requests +- Set LeaseSet type to 3 for ratchets if not specified +- Handle SSU v4 and v6 messages in one thread +- Eliminate DH keys thread +### Fixed +- Random crashes on I2CP session disconnect +- Stream through racthets hangs if first SYN was not acked +- Check "Last-Modified" instead "If-Modified-Since" for addressbook reponse +- Trim behind ECIESx25519 tags +- Few bugs with Android main activity +- QT visual and layout issues + ## [2.33.0] - 2020-08-24 ### Added - Shared transient addresses diff --git a/Win32/installer.iss b/Win32/installer.iss index fbbeba53..cc40c409 100644 --- a/Win32/installer.iss +++ b/Win32/installer.iss @@ -1,5 +1,5 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.33.0" +#define I2Pd_ver "2.34.0" #define I2Pd_Publisher "PurpleI2P" [Setup] diff --git a/android/build.gradle b/android/build.gradle index 7d25e28b..225b5d21 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -32,8 +32,8 @@ android { applicationId "org.purplei2p.i2pd" targetSdkVersion 29 minSdkVersion 14 - versionCode 2330 - versionName "2.33.0" + versionCode 2340 + versionName "2.34.0" setProperty("archivesBaseName", archivesBaseName + "-" + versionName) ndk { abiFilters 'armeabi-v7a' diff --git a/appveyor.yml b/appveyor.yml index 3cf51c2b..a8e7d30d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.33.0.{build} +version: 2.34.0.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 00bea0b0..b1f28de1 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.33.0 +Version: 2.34.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -124,6 +124,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Oct 27 2020 orignal - 2.34.0 +- update to 2.34.0 + * Mon Aug 24 2020 orignal - 2.33.0 - update to 2.33.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 22287f24..150be6a4 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.33.0 +Version: 2.34.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -122,6 +122,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Tue Oct 27 2020 orignal - 2.34.0 +- update to 2.34.0 + * Mon Aug 24 2020 orignal - 2.33.0 - update to 2.33.0 diff --git a/debian/changelog b/debian/changelog index bac3f3b3..b79f6cd6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.34.0-1) unstable; urgency=medium + + * updated to version 2.34.0 + + -- orignal Tue, 27 Oct 2020 16:00:00 +0000 + i2pd (2.33.0-1) unstable; urgency=medium * updated to version 2.33.0/0.9.47 diff --git a/libi2pd/version.h b/libi2pd/version.h index db30eee8..26ced1c3 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -16,7 +16,7 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 33 +#define I2PD_VERSION_MINOR 34 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) diff --git a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml index d3fa2e9e..97a759c2 100644 --- a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml +++ b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml @@ -35,6 +35,7 @@ + From 979282a0d4784ab1003e7ed333ccbf2295110af2 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 28 Oct 2020 03:11:14 +0800 Subject: [PATCH 11/75] qt .pro now uses libi2pd.a and libi2pclient.a instead of sources --- qt/i2pd_qt/i2pd_qt.pro | 146 ++++------------------------------------- 1 file changed, 13 insertions(+), 133 deletions(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 534d5f5a..80968fcb 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -17,68 +17,6 @@ CONFIG(debug, debug|release) { } SOURCES += DaemonQT.cpp mainwindow.cpp \ - ../../libi2pd/api.cpp \ - ../../libi2pd/Base.cpp \ - ../../libi2pd/Blinding.cpp \ - ../../libi2pd/BloomFilter.cpp \ - ../../libi2pd/ChaCha20.cpp \ - ../../libi2pd/Config.cpp \ - ../../libi2pd/CPU.cpp \ - ../../libi2pd/Crypto.cpp \ - ../../libi2pd/CryptoKey.cpp \ - ../../libi2pd/Datagram.cpp \ - ../../libi2pd/Destination.cpp \ - ../../libi2pd/Ed25519.cpp \ - ../../libi2pd/Family.cpp \ - ../../libi2pd/FS.cpp \ - ../../libi2pd/Garlic.cpp \ - ../../libi2pd/Gost.cpp \ - ../../libi2pd/Gzip.cpp \ - ../../libi2pd/HTTP.cpp \ - ../../libi2pd/I2NPProtocol.cpp \ - ../../libi2pd/I2PEndian.cpp \ - ../../libi2pd/Identity.cpp \ - ../../libi2pd/LeaseSet.cpp \ - ../../libi2pd/Log.cpp \ - ../../libi2pd/NetDb.cpp \ - ../../libi2pd/NetDbRequests.cpp \ - ../../libi2pd/NTCP2.cpp \ - ../../libi2pd/Poly1305.cpp \ - ../../libi2pd/Profiling.cpp \ - ../../libi2pd/Reseed.cpp \ - ../../libi2pd/RouterContext.cpp \ - ../../libi2pd/RouterInfo.cpp \ - ../../libi2pd/Signature.cpp \ - ../../libi2pd/SSU.cpp \ - ../../libi2pd/SSUData.cpp \ - ../../libi2pd/SSUSession.cpp \ - ../../libi2pd/Streaming.cpp \ - ../../libi2pd/Timestamp.cpp \ - ../../libi2pd/TransitTunnel.cpp \ - ../../libi2pd/Transports.cpp \ - ../../libi2pd/Tunnel.cpp \ - ../../libi2pd/TunnelEndpoint.cpp \ - ../../libi2pd/TunnelGateway.cpp \ - ../../libi2pd/TunnelPool.cpp \ - ../../libi2pd/TunnelConfig.cpp \ - ../../libi2pd/util.cpp \ - ../../libi2pd/Elligator.cpp \ - ../../libi2pd/ECIESX25519AEADRatchetSession.cpp \ - ../../libi2pd_client/AddressBook.cpp \ - ../../libi2pd_client/BOB.cpp \ - ../../libi2pd_client/ClientContext.cpp \ - ../../libi2pd_client/HTTPProxy.cpp \ - ../../libi2pd_client/I2CP.cpp \ - ../../libi2pd_client/I2PService.cpp \ - ../../libi2pd_client/I2PTunnel.cpp \ - ../../libi2pd_client/MatchedDestination.cpp \ - ../../libi2pd_client/SAM.cpp \ - ../../libi2pd_client/SOCKS.cpp \ - ../../daemon/Daemon.cpp \ - ../../daemon/HTTPServer.cpp \ - ../../daemon/I2PControl.cpp \ - ../../daemon/i2pd.cpp \ - ../../daemon/UPnP.cpp \ ClientTunnelPane.cpp \ MainWindowItems.cpp \ ServerTunnelPane.cpp \ @@ -93,77 +31,14 @@ SOURCES += DaemonQT.cpp mainwindow.cpp \ DelayedSaveManager.cpp \ Saver.cpp \ DelayedSaveManagerImpl.cpp \ - SaverImpl.cpp + SaverImpl.cpp \ + ../../daemon/Daemon.cpp \ + ../../daemon/HTTPServer.cpp \ + ../../daemon/I2PControl.cpp \ + ../../daemon/i2pd.cpp \ + ../../daemon/UPnP.cpp HEADERS += DaemonQT.h mainwindow.h \ - ../../libi2pd/api.h \ - ../../libi2pd/Base.h \ - ../../libi2pd/Blinding.h \ - ../../libi2pd/BloomFilter.h \ - ../../libi2pd/ChaCha20.h \ - ../../libi2pd/Config.h \ - ../../libi2pd/CPU.h \ - ../../libi2pd/Crypto.h \ - ../../libi2pd/CryptoKey.h \ - ../../libi2pd/Datagram.h \ - ../../libi2pd/Destination.h \ - ../../libi2pd/Ed25519.h \ - ../../libi2pd/Family.h \ - ../../libi2pd/FS.h \ - ../../libi2pd/Garlic.h \ - ../../libi2pd/Gost.h \ - ../../libi2pd/Gzip.h \ - ../../libi2pd/HTTP.h \ - ../../libi2pd/I2NPProtocol.h \ - ../../libi2pd/I2PEndian.h \ - ../../libi2pd/Identity.h \ - ../../libi2pd/LeaseSet.h \ - ../../libi2pd/LittleBigEndian.h \ - ../../libi2pd/Log.h \ - ../../libi2pd/NetDb.hpp \ - ../../libi2pd/NetDbRequests.h \ - ../../libi2pd/NTCP2.h \ - ../../libi2pd/Poly1305.h \ - ../../libi2pd/Profiling.h \ - ../../libi2pd/Queue.h \ - ../../libi2pd/Reseed.h \ - ../../libi2pd/RouterContext.h \ - ../../libi2pd/RouterInfo.h \ - ../../libi2pd/Signature.h \ - ../../libi2pd/Siphash.h \ - ../../libi2pd/SSU.h \ - ../../libi2pd/SSUData.h \ - ../../libi2pd/SSUSession.h \ - ../../libi2pd/Streaming.h \ - ../../libi2pd/Tag.h \ - ../../libi2pd/Timestamp.h \ - ../../libi2pd/TransitTunnel.h \ - ../../libi2pd/Transports.h \ - ../../libi2pd/TransportSession.h \ - ../../libi2pd/Tunnel.h \ - ../../libi2pd/TunnelBase.h \ - ../../libi2pd/TunnelConfig.h \ - ../../libi2pd/TunnelEndpoint.h \ - ../../libi2pd/TunnelGateway.h \ - ../../libi2pd/TunnelPool.h \ - ../../libi2pd/util.h \ - ../../libi2pd/version.h \ - ../../libi2pd/Elligator.h \ - ../../libi2pd/ECIESX25519AEADRatchetSession.h \ - ../../libi2pd_client/AddressBook.h \ - ../../libi2pd_client/BOB.h \ - ../../libi2pd_client/ClientContext.h \ - ../../libi2pd_client/HTTPProxy.h \ - ../../libi2pd_client/I2CP.h \ - ../../libi2pd_client/I2PService.h \ - ../../libi2pd_client/I2PTunnel.h \ - ../../libi2pd_client/MatchedDestination.h \ - ../../libi2pd_client/SAM.h \ - ../../libi2pd_client/SOCKS.h \ - ../../daemon/Daemon.h \ - ../../daemon/HTTPServer.h \ - ../../daemon/I2PControl.h \ - ../../daemon/UPnP.h \ ClientTunnelPane.h \ MainWindowItems.h \ ServerTunnelPane.h \ @@ -180,7 +55,12 @@ HEADERS += DaemonQT.h mainwindow.h \ DelayedSaveManager.h \ Saver.h \ DelayedSaveManagerImpl.h \ - SaverImpl.h + SaverImpl.h \ + ../../daemon/Daemon.h \ + ../../daemon/HTTPServer.h \ + ../../daemon/I2PControl.h \ + ../../daemon/UPnP.h + INCLUDEPATH += ../../libi2pd INCLUDEPATH += ../../libi2pd_client @@ -193,7 +73,7 @@ FORMS += mainwindow.ui \ routercommandswidget.ui \ generalsettingswidget.ui -LIBS += -lz +LIBS += ../../libi2pd.a ../../libi2pdclient.a -lz macx { message("using mac os x target") From 2b4a91cc806f7826a8b6b24c852f916eb1de100d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 27 Oct 2020 19:34:38 +0000 Subject: [PATCH 12/75] [actions] Rename worker and jobs --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ba6acbf8..5e5152e0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,10 @@ -name: Build on Ubuntu with make +name: Build on Ubuntu on: [push, pull_request] jobs: build: - name: Building with USE_UPNP=${{ matrix.with_upnp }} flag + name: With USE_UPNP=${{ matrix.with_upnp }} runs-on: ubuntu-16.04 strategy: fail-fast: true From 0c29aeb9bead9a8f4039ecf4206bcb2d30975733 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 27 Oct 2020 19:40:22 +0000 Subject: [PATCH 13/75] [actions] add qt gui builder --- .github/workflows/build-qt.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/workflows/build-qt.yml diff --git a/.github/workflows/build-qt.yml b/.github/workflows/build-qt.yml new file mode 100644 index 00000000..6b247f1b --- /dev/null +++ b/.github/workflows/build-qt.yml @@ -0,0 +1,20 @@ +name: Build on Ubuntu + +on: [push, pull_request] + +jobs: + build: + name: With QT GUI + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@v2 + - name: install packages + run: | + sudo add-apt-repository ppa:mhier/libboost-latest + sudo apt-get update + sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev + - name: build application + run: | + cd qt/i2pd_qt + qmake + make USE_AVX=no USE_AESNI=no USE_UPNP=yes -j3 From a47aa8c282be0b23133922cbcf7c89034ce181bf Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 27 Oct 2020 19:55:48 +0000 Subject: [PATCH 14/75] [actions] build i2pd library before building gui --- .github/workflows/build-qt.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-qt.yml b/.github/workflows/build-qt.yml index 6b247f1b..6211c4c7 100644 --- a/.github/workflows/build-qt.yml +++ b/.github/workflows/build-qt.yml @@ -15,6 +15,7 @@ jobs: sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev - name: build application run: | + make -j3 USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no mk_obj_dir libi2pd.a libi2pdclient.a cd qt/i2pd_qt qmake - make USE_AVX=no USE_AESNI=no USE_UPNP=yes -j3 + make -j3 From e444519889b75d570d025e5dfcd0a15a60ca1eba Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 27 Oct 2020 16:46:39 -0400 Subject: [PATCH 15/75] excluded appcompat --- android/build.gradle | 2 -- android/src/org/purplei2p/i2pd/WebConsoleActivity.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 225b5d21..2c6c782d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,8 +21,6 @@ repositories { dependencies { implementation 'androidx.core:core:1.0.2' - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' } android { diff --git a/android/src/org/purplei2p/i2pd/WebConsoleActivity.java b/android/src/org/purplei2p/i2pd/WebConsoleActivity.java index 24e6baeb..0fcf37fe 100644 --- a/android/src/org/purplei2p/i2pd/WebConsoleActivity.java +++ b/android/src/org/purplei2p/i2pd/WebConsoleActivity.java @@ -1,7 +1,5 @@ package org.purplei2p.i2pd; -import androidx.appcompat.app.AppCompatActivity; - import android.app.Activity; import android.os.Bundle; import android.view.MenuItem; From 33f2ddb6960288f7c48d2b8d0fa8632051746817 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 28 Oct 2020 20:07:28 +0300 Subject: [PATCH 16/75] [QT] fix build with prebuild i2pd libs Signed-off-by: R4SAS --- .github/workflows/build-qt.yml | 1 - qt/i2pd_qt/i2pd_qt.pro | 24 ++++++++++++++++++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-qt.yml b/.github/workflows/build-qt.yml index 6211c4c7..d4fde2b9 100644 --- a/.github/workflows/build-qt.yml +++ b/.github/workflows/build-qt.yml @@ -15,7 +15,6 @@ jobs: sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev - name: build application run: | - make -j3 USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no mk_obj_dir libi2pd.a libi2pdclient.a cd qt/i2pd_qt qmake make -j3 diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 80968fcb..1064e953 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -7,8 +7,6 @@ TEMPLATE = app QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized CONFIG += strict_c++ c++11 -DEFINES += USE_UPNP - CONFIG(debug, debug|release) { message(Debug build) DEFINES += DEBUG_WITH_DEFAULT_LOGGING @@ -75,6 +73,22 @@ FORMS += mainwindow.ui \ LIBS += ../../libi2pd.a ../../libi2pdclient.a -lz +libi2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" USE_UPNP=yes DEBUG=no mk_obj_dir libi2pd.a +libi2pd.target = $$PWD/../../libi2pd.a +libi2pd.depends = FORCE + +libi2pdclient.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" USE_UPNP=yes DEBUG=no mk_obj_dir libi2pdclient.a +libi2pdclient.target = $$PWD/../../libi2pdclient.a +libi2pdclient.depends = FORCE + +cleani2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) clean +cleani2pd.depends = clean + +PRE_TARGETDEPS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a +QMAKE_EXTRA_TARGETS += cleani2pd libi2pd libi2pdclient +CLEAN_DEPS += cleani2pd + + macx { message("using mac os x target") BREWROOT=/usr/local @@ -110,10 +124,12 @@ windows { QMAKE_CXXFLAGS_RELEASE = -Os QMAKE_LFLAGS = -Wl,-Bstatic -static-libgcc -static-libstdc++ -mwindows - #linker's -s means "strip" + # linker's -s means "strip" QMAKE_LFLAGS_RELEASE += -s - LIBS = -lminiupnpc \ + LIBS = \ + $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a \ + -lminiupnpc \ -lboost_system$$BOOST_SUFFIX \ -lboost_date_time$$BOOST_SUFFIX \ -lboost_filesystem$$BOOST_SUFFIX \ From bf0496299413a69fd364db54b79ec0b2388976e9 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 28 Oct 2020 20:47:16 +0300 Subject: [PATCH 17/75] [QT] change i2pd make command Signed-off-by: R4SAS --- qt/i2pd_qt/i2pd_qt.pro | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 1064e953..54818f71 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -71,13 +71,13 @@ FORMS += mainwindow.ui \ routercommandswidget.ui \ generalsettingswidget.ui -LIBS += ../../libi2pd.a ../../libi2pdclient.a -lz +LIBS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -lz -libi2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" USE_UPNP=yes DEBUG=no mk_obj_dir libi2pd.a +libi2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api libi2pd.target = $$PWD/../../libi2pd.a libi2pd.depends = FORCE -libi2pdclient.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) OPT=\"$$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_RELEASE\" USE_UPNP=yes DEBUG=no mk_obj_dir libi2pdclient.a +libi2pdclient.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api_client libi2pdclient.target = $$PWD/../../libi2pdclient.a libi2pdclient.depends = FORCE From bdbd060229cf3d0808b83148ed89e7939d70499d Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 28 Oct 2020 21:02:41 +0300 Subject: [PATCH 18/75] [QT] create obj dirs before building i2pd Signed-off-by: R4SAS --- qt/i2pd_qt/i2pd_qt.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 54818f71..34b8ebfc 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -73,11 +73,11 @@ FORMS += mainwindow.ui \ LIBS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -lz -libi2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api +libi2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api libi2pd.target = $$PWD/../../libi2pd.a libi2pd.depends = FORCE -libi2pdclient.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api_client +libi2pdclient.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api_client libi2pdclient.target = $$PWD/../../libi2pdclient.a libi2pdclient.depends = FORCE From d02a0c9b3a1b9f2cbee8bf364382443cfa081443 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Wed, 28 Oct 2020 21:18:02 +0300 Subject: [PATCH 19/75] [QT] don't build i2pd with aesni/avx for compatability with arm64 Signed-off-by: R4SAS --- qt/i2pd_qt/i2pd_qt.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index 34b8ebfc..dba69143 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -73,11 +73,11 @@ FORMS += mainwindow.ui \ LIBS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -lz -libi2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api +libi2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no api libi2pd.target = $$PWD/../../libi2pd.a libi2pd.depends = FORCE -libi2pdclient.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes DEBUG=no api_client +libi2pdclient.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no api_client libi2pdclient.target = $$PWD/../../libi2pdclient.a libi2pdclient.depends = FORCE From 5d256e1d800a2f7cd9f92f3fb3e27522ad2afe0d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Oct 2020 15:35:39 -0400 Subject: [PATCH 20/75] don't allow STREAM CONNECT and STREAM ACCEPT in command session --- libi2pd_client/SAM.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libi2pd_client/SAM.cpp b/libi2pd_client/SAM.cpp index 6624c6f9..d758f31e 100644 --- a/libi2pd_client/SAM.cpp +++ b/libi2pd_client/SAM.cpp @@ -472,6 +472,11 @@ namespace client void SAMSocket::ProcessStreamConnect (char * buf, size_t len, size_t rem) { LogPrint (eLogDebug, "SAM: stream connect: ", buf); + if ( m_SocketType != eSAMSocketTypeUnknown) + { + SendI2PError ("Socket already in use"); + return; + } std::map params; ExtractParams (buf, params); std::string& id = params[SAM_PARAM_ID]; @@ -547,6 +552,11 @@ namespace client void SAMSocket::ProcessStreamAccept (char * buf, size_t len) { LogPrint (eLogDebug, "SAM: stream accept: ", buf); + if ( m_SocketType != eSAMSocketTypeUnknown) + { + SendI2PError ("Socket already in use"); + return; + } std::map params; ExtractParams (buf, params); std::string& id = params[SAM_PARAM_ID]; From 812d312a9e4c1807f768bdcb97bbccb154bef207 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 29 Oct 2020 00:38:47 +0300 Subject: [PATCH 21/75] [RPM] fix build on fedora >= 33 Signed-off-by: R4SAS --- contrib/rpm/i2pd-git.spec | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index b1f28de1..58c87cfb 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -56,14 +56,23 @@ cd build %endif %endif -%if 0%{?mageia} > 7 -pushd build -make %{?_smp_mflags} -popd -%else -make %{?_smp_mflags} +%if 0%{?fedora} >= 33 +pushd %{_arch}-redhat-linux-gnu %endif +%if 0%{?mageia} > 7 +pushd build +%endif + +make %{?_smp_mflags} + +%if 0%{?fedora} >= 33 +popd +%endif + +%if 0%{?mageia} > 7 +popd +%endif %install pushd build From 530eba1b911dcc682c05194d67c7a425267feb18 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 29 Oct 2020 00:51:01 +0300 Subject: [PATCH 22/75] [RPM] fix build on fedora >= 33 Signed-off-by: R4SAS --- contrib/rpm/i2pd-git.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 58c87cfb..1fd8ce8d 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -57,7 +57,7 @@ cd build %endif %if 0%{?fedora} >= 33 -pushd %{_arch}-redhat-linux-gnu +pushd %{_target_platform} %endif %if 0%{?mageia} > 7 From b2f0278180c2e53b7a877c9993d37beaac4bc8d0 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 29 Oct 2020 01:03:36 +0300 Subject: [PATCH 23/75] [RPM] fix build on fedora >= 33 Signed-off-by: R4SAS --- contrib/rpm/i2pd-git.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 1fd8ce8d..59d5f5ab 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -81,6 +81,10 @@ pushd build pushd build %endif +%if 0%{?fedora} >= 33 +pushd %{_target_platform} +%endif + chrpath -d i2pd %{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd %{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd From aaf6c1ea8b7fce01f10be087f5c4dc3680167649 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Thu, 29 Oct 2020 01:17:07 +0300 Subject: [PATCH 24/75] [RPM] fix build on fedora >= 33 Signed-off-by: R4SAS --- contrib/rpm/i2pd-git.spec | 8 ++++---- contrib/rpm/i2pd.spec | 25 +++++++++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index 59d5f5ab..a320d6aa 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -77,14 +77,14 @@ popd %install pushd build -%if 0%{?mageia} -pushd build -%endif - %if 0%{?fedora} >= 33 pushd %{_target_platform} %endif +%if 0%{?mageia} +pushd build +%endif + chrpath -d i2pd %{__install} -D -m 755 i2pd %{buildroot}%{_sbindir}/i2pd %{__install} -d -m 755 %{buildroot}%{_datadir}/i2pd diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 150be6a4..3f5ef260 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -54,18 +54,31 @@ cd build %endif %endif -%if 0%{?mageia} > 7 -pushd build -make %{?_smp_mflags} -popd -%else -make %{?_smp_mflags} +%if 0%{?fedora} >= 33 +pushd %{_target_platform} %endif +%if 0%{?mageia} > 7 +pushd build +%endif + +make %{?_smp_mflags} + +%if 0%{?fedora} >= 33 +popd +%endif + +%if 0%{?mageia} > 7 +popd +%endif %install pushd build +%if 0%{?fedora} >= 33 +pushd %{_target_platform} +%endif + %if 0%{?mageia} pushd build %endif From 9f2a2e44a323ba94c7782e3d0e0c4a93c63dba6f Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 28 Oct 2020 21:53:11 -0400 Subject: [PATCH 25/75] common MixHash and MixKey --- libi2pd/Crypto.cpp | 18 ++++++++++++++++-- libi2pd/Crypto.h | 10 ++++++++++ libi2pd/NTCP2.cpp | 15 --------------- libi2pd/NTCP2.h | 6 ++---- libi2pd/Tunnel.cpp | 2 +- libi2pd/TunnelConfig.cpp | 22 +++++----------------- libi2pd/TunnelConfig.h | 5 ++--- 7 files changed, 36 insertions(+), 42 deletions(-) diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index 2f10e91d..ea2cd675 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -1323,6 +1323,21 @@ namespace crypto #endif } + void NoiseSymmetricState::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 NoiseSymmetricState::MixKey (const uint8_t * sharedSecret) + { + HKDF (m_CK, sharedSecret, 32, "", m_CK); + // new ck is m_CK[0:31], key is m_CK[32:63] + } + // init and terminate /* std::vector > m_OpenSSLMutexes; @@ -1336,8 +1351,7 @@ namespace crypto m_OpenSSLMutexes[type]->unlock (); } }*/ - - + void InitCrypto (bool precomputation) { i2p::cpu::Detect (); diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index ab84e56a..205be44d 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -311,6 +311,16 @@ namespace crypto void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32 +// Noise + + struct NoiseSymmetricState + { + uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/; + + void MixHash (const uint8_t * buf, size_t len); + void MixKey (const uint8_t * sharedSecret); + }; + // init and terminate void InitCrypto (bool precomputation); void TerminateCrypto (); diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index cdf660b7..7a88e4d8 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -39,21 +39,6 @@ namespace transport delete[] m_SessionConfirmedBuffer; } - void NTCP2Establisher::MixKey (const uint8_t * inputKeyMaterial) - { - i2p::crypto::HKDF (m_CK, inputKeyMaterial, 32, "", m_CK); - // ck is m_CK[0:31], k is m_CK[32:63] - } - - 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) { static const uint8_t protocolNameHash[] = diff --git a/libi2pd/NTCP2.h b/libi2pd/NTCP2.h index df72fed0..351f17b5 100644 --- a/libi2pd/NTCP2.h +++ b/libi2pd/NTCP2.h @@ -74,7 +74,7 @@ namespace transport // RouterInfo flags const uint8_t NTCP2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; - struct NTCP2Establisher + struct NTCP2Establisher: private i2p::crypto::NoiseSymmetricState { NTCP2Establisher (); ~NTCP2Establisher (); @@ -94,8 +94,6 @@ namespace transport void KDF3Alice (); // for SessionConfirmed part 2 void KDF3Bob (); - 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 KeyDerivationFunction2 (const uint8_t * sessionRequest, size_t sessionRequestLen, const uint8_t * epub); // for SessionCreate void CreateEphemeralKey (); @@ -112,7 +110,7 @@ namespace transport std::shared_ptr m_EphemeralKeys; uint8_t m_RemoteEphemeralPublicKey[32]; // x25519 - uint8_t m_RemoteStaticKey[32], m_IV[16], m_H[32] /*h*/, m_CK[64] /* [ck, k]*/; + uint8_t m_RemoteStaticKey[32], m_IV[16]; i2p::data::IdentHash m_RemoteIdentHash; uint16_t m3p2Len; diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index bfe466e3..a74c8c91 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -124,7 +124,7 @@ namespace tunnel uint8_t nonce[12]; memset (nonce, 0, 12); if (!i2p::crypto::AEADChaCha20Poly1305 (record, TUNNEL_BUILD_RECORD_SIZE - 16, - hop->h, 32, hop->ck, nonce, record, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt + hop->m_H, 32, hop->m_CK, nonce, record, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt { LogPrint (eLogWarning, "Tunnel: Response AEAD decryption failed"); return false; diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index 5c2cbd53..61e878d4 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.cpp @@ -10,7 +10,6 @@ #include #include #include -#include "Crypto.h" #include "Log.h" #include "Transports.h" #include "Timestamp.h" @@ -129,8 +128,8 @@ namespace tunnel const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx) { static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars - memcpy (ck, protocolName, 32); // ck = h = protocol_name || 0 - SHA256 (ck, 32, h); // h = SHA256(h); + memcpy (m_CK, protocolName, 32); // ck = h = protocol_name || 0 + SHA256 (m_CK, 32, m_H); // h = SHA256(h); uint8_t hepk[32]; encryptor->Encrypt (nullptr, hepk, nullptr, false); MixHash (hepk, 32); // h = SHA256(h || hepk) @@ -140,27 +139,16 @@ namespace tunnel encrypted += 32; uint8_t sharedSecret[32]; ephemeralKeys->Agree (hepk, sharedSecret); // x25519(sesk, hepk) - uint8_t keydata[64]; - i2p::crypto::HKDF (ck, sharedSecret, 32, "", keydata); - memcpy (ck, keydata, 32); + MixKey (sharedSecret); uint8_t nonce[12]; memset (nonce, 0, 12); - if (!i2p::crypto::AEADChaCha20Poly1305 (plainText, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, h, 32, - keydata + 32, nonce, encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16, true)) // encrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (plainText, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, m_H, 32, + m_CK + 32, nonce, encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16, true)) // encrypt { LogPrint (eLogWarning, "Tunnel: Plaintext AEAD encryption failed"); return; } MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext) } - - void TunnelHopConfig::MixHash (const uint8_t * buf, size_t len) - { - SHA256_CTX ctx; - SHA256_Init (&ctx); - SHA256_Update (&ctx, h, 32); - SHA256_Update (&ctx, buf, len); - SHA256_Final (h, &ctx); - } } } \ No newline at end of file diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index 0e757071..261394b4 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.h @@ -12,12 +12,13 @@ #include #include "Identity.h" #include "RouterContext.h" +#include "Crypto.h" namespace i2p { namespace tunnel { - struct TunnelHopConfig + struct TunnelHopConfig: public i2p::crypto::NoiseSymmetricState { std::shared_ptr ident; i2p::data::IdentHash nextIdent; @@ -30,7 +31,6 @@ namespace tunnel TunnelHopConfig * next, * prev; int recordIndex; // record # in tunnel build message - uint8_t ck[32], h[32]; // for ECIES TunnelHopConfig (std::shared_ptr r); @@ -43,7 +43,6 @@ namespace tunnel void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx); void EncryptECIES (std::shared_ptr& encryptor, const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx); - void MixHash (const uint8_t * buf, size_t len); }; class TunnelConfig From b12fa97a38ca9c9fc15800e2106e483687fee33a Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 29 Oct 2020 18:41:21 -0400 Subject: [PATCH 26/75] 32 bytes private key for ECIESx25519 --- libi2pd/Identity.cpp | 20 ++++++++++++++------ libi2pd/Identity.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 490b8692..c6e5a884 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -476,7 +476,7 @@ namespace data size_t PrivateKeys::GetFullLen () const { - size_t ret = m_Public->GetFullLen () + 256 + m_Public->GetSigningPrivateKeyLen (); + size_t ret = m_Public->GetFullLen () + GetPrivateKeyLen () + m_Public->GetSigningPrivateKeyLen (); if (IsOfflineSignature ()) ret += m_OfflineSignature.size () + m_TransientSigningPrivateKeyLen; return ret; @@ -486,9 +486,10 @@ namespace data { m_Public = std::make_shared(); size_t ret = m_Public->FromBuffer (buf, len); - if (!ret || ret + 256 > len) return 0; // overflow - memcpy (m_PrivateKey, buf + ret, 256); // private key always 256 - ret += 256; + auto cryptoKeyLen = GetPrivateKeyLen (); + if (!ret || ret + cryptoKeyLen > len) return 0; // overflow + memcpy (m_PrivateKey, buf + ret, cryptoKeyLen); + ret += cryptoKeyLen; size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); if(signingPrivateKeySize + ret > len || signingPrivateKeySize > 128) return 0; // overflow memcpy (m_SigningPrivateKey, buf + ret, signingPrivateKeySize); @@ -540,8 +541,9 @@ namespace data size_t PrivateKeys::ToBuffer (uint8_t * buf, size_t len) const { size_t ret = m_Public->ToBuffer (buf, len); - memcpy (buf + ret, m_PrivateKey, 256); // private key always 256 - ret += 256; + auto cryptoKeyLen = GetPrivateKeyLen (); + memcpy (buf + ret, m_PrivateKey, cryptoKeyLen); + ret += cryptoKeyLen; size_t signingPrivateKeySize = m_Public->GetSigningPrivateKeyLen (); if(ret + signingPrivateKeySize > len) return 0; // overflow if (IsOfflineSignature ()) @@ -657,6 +659,12 @@ namespace data return IsOfflineSignature () ? m_TransientSignatureLen : m_Public->GetSignatureLen (); } + size_t PrivateKeys::GetPrivateKeyLen () const + { + // private key length always 256, but type 4 + return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) ? 32 : 256; + } + uint8_t * PrivateKeys::GetPadding() { if(m_Public->GetSigningKeyType () == SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519) diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index 534b8f4c..a36e7209 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -183,6 +183,7 @@ namespace data void CreateSigner () const; void CreateSigner (SigningKeyType keyType) const; + size_t GetPrivateKeyLen () const; private: From 3907c17cf5529034a349a0519fe84baa083a6d77 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 2 Nov 2020 18:49:07 -0500 Subject: [PATCH 27/75] handle TunnelBuildMessage for ECIES router --- libi2pd/I2NPProtocol.cpp | 53 +++++++++++++++++++++++++++++++-------- libi2pd/I2NPProtocol.h | 1 + libi2pd/RouterContext.cpp | 35 ++++++++++++++++++++++++-- libi2pd/RouterContext.h | 8 ++++-- libi2pd/TunnelConfig.cpp | 11 +++++--- libi2pd/TunnelConfig.h | 2 ++ 6 files changed, 93 insertions(+), 17 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 36e7a763..7778b9e4 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -363,37 +363,70 @@ namespace i2p BN_CTX * ctx = BN_CTX_new (); i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); BN_CTX_free (ctx); + uint8_t retCode = 0; + bool isECIES = i2p::context.IsECIES (); // replace record to reply if (i2p::context.AcceptsTunnels () && i2p::tunnel::tunnels.GetTransitTunnels ().size () <= g_MaxNumTransitTunnels && !i2p::transport::transports.IsBandwidthExceeded () && !i2p::transport::transports.IsTransitBandwidthExceeded ()) { - auto transitTunnel = i2p::tunnel::CreateTransitTunnel ( + auto transitTunnel = isECIES ? + i2p::tunnel::CreateTransitTunnel ( + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), + clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + clearText + ECIES_BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, + clearText + ECIES_BUILD_REQUEST_RECORD_IV_KEY_OFFSET, + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80, + clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) : + i2p::tunnel::CreateTransitTunnel ( bufbe32toh (clearText + BUILD_REQUEST_RECORD_RECEIVE_TUNNEL_OFFSET), clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), clearText + BUILD_REQUEST_RECORD_LAYER_KEY_OFFSET, clearText + BUILD_REQUEST_RECORD_IV_KEY_OFFSET, clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x80, - clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET ] & 0x40); + clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40); i2p::tunnel::tunnels.AddTransitTunnel (transitTunnel); - record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 0; } else - record[BUILD_RESPONSE_RECORD_RET_OFFSET] = 30; // always reject with bandwidth reason (30) + retCode = 30; // always reject with bandwidth reason (30) - //TODO: fill filler - SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret - record + BUILD_RESPONSE_RECORD_HASH_OFFSET); + if (isECIES) + { + memset (record + ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET, 0, 2); // no options + record[ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; + } + else + { + record[BUILD_RESPONSE_RECORD_RET_OFFSET] = retCode; + SHA256 (record + BUILD_RESPONSE_RECORD_PADDING_OFFSET, BUILD_RESPONSE_RECORD_PADDING_SIZE + 1, // + 1 byte of ret + record + BUILD_RESPONSE_RECORD_HASH_OFFSET); + } // encrypt reply i2p::crypto::CBCEncryption encryption; for (int j = 0; j < num; j++) { - encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); - encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE; - encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); + if (isECIES && j == i) + { + uint8_t nonce[12]; + memset (nonce, 0, 12); + auto noiseState = std::move (i2p::context.GetCurrentNoiseState ()); + if (!noiseState || !i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, + noiseState->m_H, 32, noiseState->m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + { + LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed"); + return false; + } + } + else + { + encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); + encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); + encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); + } } return true; } diff --git a/libi2pd/I2NPProtocol.h b/libi2pd/I2NPProtocol.h index 03f0f439..b8fbb303 100644 --- a/libi2pd/I2NPProtocol.h +++ b/libi2pd/I2NPProtocol.h @@ -98,6 +98,7 @@ namespace i2p const size_t ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE = 464; // ECIES BuildResponseRecord + const size_t ECIES_BUILD_RESPONSE_RECORD_OPTIONS_OFFSET = 0; const size_t ECIES_BUILD_RESPONSE_RECORD_RET_OFFSET = 511; enum I2NPMessageType diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 69e69d7c..da9b42fc 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -19,6 +19,7 @@ #include "version.h" #include "Log.h" #include "Family.h" +#include "TunnelConfig.h" #include "RouterContext.h" namespace i2p @@ -41,6 +42,13 @@ namespace i2p CreateNewRouter (); m_Decryptor = m_Keys.CreateDecryptor (nullptr); UpdateRouterInfo (); + if (IsECIES ()) + { + auto initState = new i2p::crypto::NoiseSymmetricState (); + i2p::tunnel::InitBuildRequestRecordNoiseState (*initState); + initState->MixHash (GetIdentity ()->GetEncryptionPublicKey (), 32); // h = SHA256(h || hepk) + m_InitialNoiseState.reset (initState); + } } void RouterContext::CreateNewRouter () @@ -673,9 +681,32 @@ namespace i2p return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, true) : false; } - bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const + bool RouterContext::DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) { - return m_Decryptor ? m_Decryptor->Decrypt (encrypted, data, ctx, false) : false; + if (!m_Decryptor) return false; + if (IsECIES ()) + { + if (!m_InitialNoiseState) return false; + // m_InitialNoiseState is h = SHA256(h || hepk) + m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); + m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) + uint8_t sharedSecret[32]; + m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false); + m_CurrentNoiseState->MixKey (sharedSecret); + encrypted += 32; + uint8_t nonce[12]; + memset (nonce, 0, 12); + if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, TUNNEL_BUILD_RECORD_SIZE - 16, + m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK, nonce, data, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt + { + LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); + return false; + } + m_CurrentNoiseState->MixHash (encrypted, TUNNEL_BUILD_RECORD_SIZE); // h = SHA256(h || ciphertext) + return true; + } + else + return m_Decryptor->Decrypt (encrypted, data, ctx, false); } i2p::crypto::X25519Keys& RouterContext::GetStaticKeys () diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 37e1791d..402d3816 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -84,7 +84,7 @@ namespace i2p void SetError (RouterError error) { m_Status = eRouterStatusError; m_Error = error; }; int GetNetID () const { return m_NetID; }; void SetNetID (int netID) { m_NetID = netID; }; - bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx) const; + bool DecryptTunnelBuildRecord (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx); void UpdatePort (int port); // called from Daemon void UpdateAddress (const boost::asio::ip::address& host); // called from SSU or Daemon @@ -109,7 +109,9 @@ namespace i2p bool SupportsV4 () const { return m_RouterInfo.IsV4 (); }; void SetSupportsV6 (bool supportsV6); void SetSupportsV4 (bool supportsV4); - + bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; }; + std::unique_ptr& GetCurrentNoiseState () { return m_CurrentNoiseState; }; + void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove void UpdateStats (); void UpdateTimestamp (uint64_t ts); // in seconds, called from NetDb before publishing @@ -160,6 +162,8 @@ namespace i2p std::mutex m_GarlicMutex; std::unique_ptr m_NTCP2Keys; std::unique_ptr m_StaticKeys; + // for ECIESx25519 + std::unique_ptr m_InitialNoiseState, m_CurrentNoiseState; }; extern RouterContext context; diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index 61e878d4..c0ebb766 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.cpp @@ -127,9 +127,7 @@ namespace tunnel void TunnelHopConfig::EncryptECIES (std::shared_ptr& encryptor, const uint8_t * plainText, uint8_t * encrypted, BN_CTX * ctx) { - static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars - memcpy (m_CK, protocolName, 32); // ck = h = protocol_name || 0 - SHA256 (m_CK, 32, m_H); // h = SHA256(h); + InitBuildRequestRecordNoiseState (*this); uint8_t hepk[32]; encryptor->Encrypt (nullptr, hepk, nullptr, false); MixHash (hepk, 32); // h = SHA256(h || hepk) @@ -150,5 +148,12 @@ namespace tunnel } MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext) } + + void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state) + { + static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars + memcpy (state.m_CK, protocolName, 32); // ck = h = protocol_name || 0 + SHA256 (state.m_CK, 32, state.m_H); // h = SHA256(h); + } } } \ No newline at end of file diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index 261394b4..518c1aad 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.h @@ -45,6 +45,8 @@ namespace tunnel const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx); }; + void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state); + class TunnelConfig { public: From d820b8036edfb6045eebd9223658b30b03570868 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Nov 2020 09:20:14 -0500 Subject: [PATCH 28/75] correct transient signature length --- libi2pd/Streaming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 21c6d6ce..80e8aecf 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -325,7 +325,7 @@ namespace stream if (flags & PACKET_FLAG_SIGNATURE_INCLUDED) { uint8_t signature[256]; - auto signatureLen = m_RemoteIdentity->GetSignatureLen (); + auto signatureLen = m_TransientVerifier ? m_TransientVerifier->GetSignatureLen () : m_RemoteIdentity->GetSignatureLen (); if(signatureLen <= sizeof(signature)) { memcpy (signature, optionData, signatureLen); From 4e7aafeec13338e92c5293e848b4a207cdca9bce Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Nov 2020 15:23:13 -0500 Subject: [PATCH 29/75] send transit tunnel reply for ECIES router --- libi2pd/I2NPProtocol.cpp | 46 +++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 7778b9e4..4dbb4e18 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -463,22 +463,44 @@ namespace i2p } else { - uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; - if (HandleBuildRequestRecords (num, buf + 1, clearText)) + if (i2p::context.IsECIES ()) { - if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel + uint8_t clearText[TUNNEL_BUILD_RECORD_SIZE]; + if (HandleBuildRequestRecords (num, buf + 1, clearText)) { - // so we send it to reply tunnel - transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), - eI2NPVariableTunnelBuildReply, buf, len, - bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel + { + // so we send it to reply tunnel + transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateTunnelGatewayMsg (bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + eI2NPVariableTunnelBuildReply, buf, len, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + } + else + transports.SendMessage (clearText + ECIES_BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, + bufbe32toh (clearText + ECIES_BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); } - else - transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, - CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, - bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); } + else + { + uint8_t clearText[BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; + if (HandleBuildRequestRecords (num, buf + 1, clearText)) + { + if (clearText[BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel + { + // so we send it to reply tunnel + transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateTunnelGatewayMsg (bufbe32toh (clearText + BUILD_REQUEST_RECORD_NEXT_TUNNEL_OFFSET), + eI2NPVariableTunnelBuildReply, buf, len, + bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + } + else + transports.SendMessage (clearText + BUILD_REQUEST_RECORD_NEXT_IDENT_OFFSET, + CreateI2NPMessage (eI2NPVariableTunnelBuild, buf, len, + bufbe32toh (clearText + BUILD_REQUEST_RECORD_SEND_MSG_ID_OFFSET))); + } + } } } From f94d03465a25a04937b2d6a05da0fa3857cefcf3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Nov 2020 15:38:25 -0500 Subject: [PATCH 30/75] don't create transit tunnel if decyrption failed --- libi2pd/I2NPProtocol.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 4dbb4e18..3cc254e6 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -361,8 +361,9 @@ namespace i2p { LogPrint (eLogDebug, "I2NP: Build request record ", i, " is ours"); BN_CTX * ctx = BN_CTX_new (); - i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); + bool success = i2p::context.DecryptTunnelBuildRecord (record + BUILD_REQUEST_RECORD_ENCRYPTED_OFFSET, clearText, ctx); BN_CTX_free (ctx); + if(!success) return false; uint8_t retCode = 0; bool isECIES = i2p::context.IsECIES (); // replace record to reply From b8064b9b4b6a4534d7e4089d57376b32c55cb144 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Nov 2020 15:42:53 -0500 Subject: [PATCH 31/75] copy noise state --- libi2pd/RouterContext.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index da9b42fc..8b5f5b77 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -687,8 +687,10 @@ namespace i2p if (IsECIES ()) { if (!m_InitialNoiseState) return false; + m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState ()); // m_InitialNoiseState is h = SHA256(h || hepk) - m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); + memcpy (m_CurrentNoiseState->m_CK, m_InitialNoiseState->m_CK, 64); + memcpy (m_CurrentNoiseState->m_H, m_InitialNoiseState->m_H, 32); m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) uint8_t sharedSecret[32]; m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false); From 942b2b05e70b7882ca735aa038ed17ca85ed55ba Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Nov 2020 15:53:47 -0500 Subject: [PATCH 32/75] correct key for AEAD decryption --- libi2pd/RouterContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 8b5f5b77..4d60e193 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -699,7 +699,7 @@ namespace i2p uint8_t nonce[12]; memset (nonce, 0, 12); if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, TUNNEL_BUILD_RECORD_SIZE - 16, - m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK, nonce, data, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt + m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK + 32, nonce, data, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt { LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); return false; From bd04f92087ea151f60d59637f6099d884c157ea3 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 3 Nov 2020 18:41:27 -0500 Subject: [PATCH 33/75] correct public key for ECIES address --- libi2pd/Identity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index c6e5a884..7784cc90 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -51,7 +51,7 @@ namespace data if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) { memcpy (m_StandardIdentity.publicKey, publicKey, 32); - RAND_bytes (m_StandardIdentity.publicKey, 224); + RAND_bytes (m_StandardIdentity.publicKey + 32, 224); } else memcpy (m_StandardIdentity.publicKey, publicKey, 256); From d5f3d6111e7d80552a3a65b100e512d4e487770c Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Nov 2020 11:52:33 -0500 Subject: [PATCH 34/75] correct tunnel build record size to decrept --- libi2pd/RouterContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 4d60e193..7525eceb 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -698,8 +698,8 @@ namespace i2p encrypted += 32; uint8_t nonce[12]; memset (nonce, 0, 12); - if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, TUNNEL_BUILD_RECORD_SIZE - 16, - m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK + 32, nonce, data, TUNNEL_BUILD_RECORD_SIZE - 16, false)) // decrypt + if (!i2p::crypto::AEADChaCha20Poly1305 (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, + m_CurrentNoiseState->m_H, 32, m_CurrentNoiseState->m_CK + 32, nonce, data, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE, false)) // decrypt { LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); return false; From 21501cbf819a4bf20a82e3c902c8bedd9a6208c1 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Nov 2020 13:31:28 -0500 Subject: [PATCH 35/75] correct MixHash after decryption --- libi2pd/RouterContext.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 7525eceb..4a142291 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -687,10 +687,8 @@ namespace i2p if (IsECIES ()) { if (!m_InitialNoiseState) return false; - m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState ()); // m_InitialNoiseState is h = SHA256(h || hepk) - memcpy (m_CurrentNoiseState->m_CK, m_InitialNoiseState->m_CK, 64); - memcpy (m_CurrentNoiseState->m_H, m_InitialNoiseState->m_H, 32); + m_CurrentNoiseState.reset (new i2p::crypto::NoiseSymmetricState (*m_InitialNoiseState)); m_CurrentNoiseState->MixHash (encrypted, 32); // h = SHA256(h || sepk) uint8_t sharedSecret[32]; m_Decryptor->Decrypt (encrypted, sharedSecret, ctx, false); @@ -704,7 +702,7 @@ namespace i2p LogPrint (eLogWarning, "Router: Tunnel record AEAD decryption failed"); return false; } - m_CurrentNoiseState->MixHash (encrypted, TUNNEL_BUILD_RECORD_SIZE); // h = SHA256(h || ciphertext) + m_CurrentNoiseState->MixHash (encrypted, ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 16); // h = SHA256(h || ciphertext) return true; } else From 1740715c001ff4e25ad7ffdc8f076b00ef4cab4e Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 4 Nov 2020 21:04:28 -0500 Subject: [PATCH 36/75] correct reply key and IV for ECIES record --- libi2pd/I2NPProtocol.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 3cc254e6..283c5641 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -410,20 +410,29 @@ namespace i2p for (int j = 0; j < num; j++) { uint8_t * reply = records + j*TUNNEL_BUILD_RECORD_SIZE; - if (isECIES && j == i) - { - uint8_t nonce[12]; - memset (nonce, 0, 12); - auto noiseState = std::move (i2p::context.GetCurrentNoiseState ()); - if (!noiseState || !i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, - noiseState->m_H, 32, noiseState->m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + if (isECIES) + { + if (j == i) { - LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed"); - return false; + uint8_t nonce[12]; + memset (nonce, 0, 12); + auto noiseState = std::move (i2p::context.GetCurrentNoiseState ()); + if (!noiseState || !i2p::crypto::AEADChaCha20Poly1305 (reply, TUNNEL_BUILD_RECORD_SIZE - 16, + noiseState->m_H, 32, noiseState->m_CK, nonce, reply, TUNNEL_BUILD_RECORD_SIZE, true)) // encrypt + { + LogPrint (eLogWarning, "I2NP: Reply AEAD encryption failed"); + return false; + } + } + else + { + encryption.SetKey (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); + encryption.SetIV (clearText + ECIES_BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); + encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); } } else - { + { encryption.SetKey (clearText + BUILD_REQUEST_RECORD_REPLY_KEY_OFFSET); encryption.SetIV (clearText + BUILD_REQUEST_RECORD_REPLY_IV_OFFSET); encryption.Encrypt(reply, TUNNEL_BUILD_RECORD_SIZE, reply); @@ -466,7 +475,7 @@ namespace i2p { if (i2p::context.IsECIES ()) { - uint8_t clearText[TUNNEL_BUILD_RECORD_SIZE]; + uint8_t clearText[ECIES_BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE]; if (HandleBuildRequestRecords (num, buf + 1, clearText)) { if (clearText[ECIES_BUILD_REQUEST_RECORD_FLAG_OFFSET] & 0x40) // we are endpoint of outboud tunnel From 6362a7bba55fd405d2ddd7a896970ddabb9f446d Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Nov 2020 15:27:37 -0500 Subject: [PATCH 37/75] decrypt garlic on ECIES router --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 34 ++++++++++------------- libi2pd/RouterContext.cpp | 9 ++++++ libi2pd/RouterContext.h | 2 +- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index aef273ed..8b67960c 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -176,15 +176,6 @@ namespace garlic memcpy (m_H, hh, 32); } - void ECIESX25519AEADRatchetSession::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 ECIESX25519AEADRatchetSession::CreateNonce (uint64_t seqn, uint8_t * nonce) { memset (nonce, 0, 4); @@ -257,7 +248,7 @@ namespace garlic uint8_t sharedSecret[32]; GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, aepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + MixKey (sharedSecret); // decrypt flags/static uint8_t nonce[12], fs[32]; @@ -277,7 +268,7 @@ namespace garlic // static key, fs is apk memcpy (m_RemoteStaticKey, fs, 32); GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, apk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + MixKey (sharedSecret); } else // all zeros flags CreateNonce (1, nonce); @@ -289,10 +280,13 @@ namespace garlic LogPrint (eLogWarning, "Garlic: Payload section AEAD verification failed"); return false; } - if (isStatic) MixHash (buf, len); // h = SHA256(h || ciphertext) + m_State = eSessionStateNewSessionReceived; - GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); - + if (isStatic) + { + MixHash (buf, len); // h = SHA256(h || ciphertext) + GetOwner ()->AddECIESx25519Session (m_RemoteStaticKey, shared_from_this ()); + } HandlePayload (payload.data (), len - 16, nullptr, 0); return true; @@ -469,7 +463,7 @@ namespace garlic MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + MixKey (sharedSecret); // encrypt static key section uint8_t nonce[12]; CreateNonce (0, nonce); @@ -482,7 +476,7 @@ namespace garlic offset += 48; // KDF2 GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bpk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + MixKey (sharedSecret); // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt { @@ -520,9 +514,9 @@ namespace garlic MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || bepk) uint8_t sharedSecret[32]; m_EphemeralKeys->Agree (m_Aepk, sharedSecret); // sharedSecret = x25519(besk, aepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32) + MixKey (sharedSecret); m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // sharedSecret = x25519(besk, apk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + MixKey (sharedSecret); uint8_t nonce[12]; CreateNonce (0, nonce); // calculate hash for zero length @@ -607,9 +601,9 @@ namespace garlic { // only fist time, we assume ephemeral keys the same m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK, 32); // chainKey = HKDF(chainKey, sharedSecret, "", 32) + MixKey (sharedSecret); GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk) - i2p::crypto::HKDF (m_CK, sharedSecret, 32, "", m_CK); // [chainKey, key] = HKDF(chainKey, sharedSecret, "", 64) + MixKey (sharedSecret); } uint8_t nonce[12]; CreateNonce (0, nonce); diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 4a142291..74f8ad34 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -653,6 +653,15 @@ namespace i2p i2p::HandleI2NPMessage (CreateI2NPMessage (buf, GetI2NPMessageLength (buf, len))); } + bool RouterContext::HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) + { + auto msg = CreateI2NPMessage (typeID, payload, len); + if (!msg) return false; + i2p::HandleI2NPMessage (msg); + return true; + } + + void RouterContext::ProcessGarlicMessage (std::shared_ptr msg) { std::unique_lock l(m_GarlicMutex); diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 402d3816..139cc35e 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -135,7 +135,7 @@ namespace i2p // implements GarlicDestination void HandleI2NPMessage (const uint8_t * buf, size_t len); - bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len) { return false; }; // not implemented + bool HandleCloveI2NPMessage (I2NPMessageType typeID, const uint8_t * payload, size_t len); private: From 4ba1be2dc08a26a646e8c9946fbe9aeefc6425ec Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 5 Nov 2020 21:21:46 -0500 Subject: [PATCH 38/75] one time garlic encryption for ECIES routers --- libi2pd/Destination.cpp | 10 ++--- libi2pd/ECIESX25519AEADRatchetSession.cpp | 49 ++++++++++++++++++----- libi2pd/ECIESX25519AEADRatchetSession.h | 17 ++++---- libi2pd/Garlic.cpp | 17 ++++++-- libi2pd/Garlic.h | 4 +- 5 files changed, 66 insertions(+), 31 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index 927e98a0..bf6047b2 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -559,9 +559,7 @@ namespace client m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); - auto msg = i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound); - if (floodfill->GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) // TODO: remove when implemented - msg = WrapMessage (floodfill, msg); + auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound)); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); @@ -756,10 +754,8 @@ namespace client else AddSessionKey (replyKey, replyTag); - auto msg = CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, - request->replyTunnel, replyKey, replyTag, isECIES); - if (nextFloodfill->GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ELGAMAL) // TODO: remove when implemented - msg = WrapMessage (nextFloodfill, msg); + auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, + request->replyTunnel, replyKey, replyTag, isECIES)); request->outboundTunnel->SendTunnelDataMsg ( { i2p::tunnel::TunnelMessageBlock diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 8b67960c..bd8d2fe6 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -446,7 +446,7 @@ namespace garlic LogPrint (eLogDebug, "Garlic: new send ratchet ", m_NextSendRatchet->newKey ? "new" : "old", " key ", m_NextSendRatchet->keyID, " created"); } - bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen) + bool ECIESX25519AEADRatchetSession::NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic) { ResetKeys (); // we are Alice, bpk is m_RemoteStaticKey @@ -464,31 +464,47 @@ namespace garlic uint8_t sharedSecret[32]; m_EphemeralKeys->Agree (m_RemoteStaticKey, sharedSecret); // x25519(aesk, bpk) MixKey (sharedSecret); - // encrypt static key section + // encrypt flags/static key section uint8_t nonce[12]; CreateNonce (0, nonce); - if (!i2p::crypto::AEADChaCha20Poly1305 (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET), 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt + const uint8_t * fs; + if (isStatic) + fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); + else { - LogPrint (eLogWarning, "Garlic: Static section AEAD encryption failed "); + memset (out + offset, 0, 32); // all zeros flags section + fs = out + offset; + } + if (!i2p::crypto::AEADChaCha20Poly1305 (fs, 32, m_H, 32, m_CK + 32, nonce, out + offset, 48, true)) // encrypt + { + LogPrint (eLogWarning, "Garlic: Flags/static section AEAD encryption failed "); return false; } + MixHash (out + offset, 48); // h = SHA256(h || ciphertext) offset += 48; // KDF2 - GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bpk) - MixKey (sharedSecret); + if (isStatic) + { + GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bpk) + MixKey (sharedSecret); + } + else + CreateNonce (1, nonce); // encrypt payload if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len, m_H, 32, m_CK + 32, nonce, out + offset, len + 16, true)) // encrypt { LogPrint (eLogWarning, "Garlic: Payload section AEAD encryption failed"); return false; } - MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext) - + m_State = eSessionStateNewSessionSent; - if (GetOwner ()) - GenerateMoreReceiveTags (CreateNewSessionTagset (), ECIESX25519_NSR_NUM_GENERATED_TAGS); - + if (isStatic) + { + MixHash (out + offset, len + 16); // h = SHA256(h || ciphertext) + if (GetOwner ()) + GenerateMoreReceiveTags (CreateNewSessionTagset (), ECIESX25519_NSR_NUM_GENERATED_TAGS); + } return true; } @@ -778,6 +794,11 @@ namespace garlic return nullptr; len += 72; break; + case eSessionStateOneTime: + if (!NewOutgoingSessionMessage (payload.data (), payload.size (), buf, m->maxLen, false)) + return nullptr; + len += 96; + break; default: return nullptr; } @@ -788,6 +809,12 @@ namespace garlic return m; } + std::shared_ptr ECIESX25519AEADRatchetSession::WrapOneTimeMessage (std::shared_ptr msg) + { + m_State = eSessionStateOneTime; + return WrapSingleMessage (msg); + } + std::vector ECIESX25519AEADRatchetSession::CreatePayload (std::shared_ptr msg, bool first) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch (); diff --git a/libi2pd/ECIESX25519AEADRatchetSession.h b/libi2pd/ECIESX25519AEADRatchetSession.h index 1c377b28..755531a3 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.h +++ b/libi2pd/ECIESX25519AEADRatchetSession.h @@ -31,7 +31,7 @@ namespace garlic const int ECIESX25519_SEND_INACTIVITY_TIMEOUT = 5000; // number of milliseconds we can send empty(pyaload only) packet after const int ECIESX25519_INCOMING_TAGS_EXPIRATION_TIMEOUT = 600; // in seconds const int ECIESX25519_PREVIOUS_TAGSET_EXPIRATION_TIMEOUT = 180; // 180 - const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 4096; // number of tags we request new tagset after + const int ECIESX25519_TAGSET_MAX_NUM_TAGS = 8192; // number of tags we request new tagset after const int ECIESX25519_MIN_NUM_GENERATED_TAGS = 24; const int ECIESX25519_MAX_NUM_GENERATED_TAGS = 160; const int ECIESX25519_NSR_NUM_GENERATED_TAGS = 12; @@ -129,7 +129,9 @@ namespace garlic const uint8_t ECIESX25519_NEXT_KEY_REVERSE_KEY_FLAG = 0x02; const uint8_t ECIESX25519_NEXT_KEY_REQUEST_REVERSE_KEY_FLAG = 0x04; - class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, public std::enable_shared_from_this + class ECIESX25519AEADRatchetSession: public GarlicRoutingSession, + private i2p::crypto::NoiseSymmetricState, + public std::enable_shared_from_this { enum SessionState { @@ -137,7 +139,8 @@ namespace garlic eSessionStateNewSessionReceived, eSessionStateNewSessionSent, eSessionStateNewSessionReplySent, - eSessionStateEstablished + eSessionStateEstablished, + eSessionStateOneTime }; struct DHRatchet @@ -155,7 +158,8 @@ namespace garlic bool HandleNextMessage (uint8_t * buf, size_t len, std::shared_ptr receiveTagset, int index = 0); std::shared_ptr WrapSingleMessage (std::shared_ptr msg); - + std::shared_ptr WrapOneTimeMessage (std::shared_ptr msg); + const uint8_t * GetRemoteStaticKey () const { return m_RemoteStaticKey; } void SetRemoteStaticKey (const uint8_t * key) { memcpy (m_RemoteStaticKey, key, 32); } @@ -175,7 +179,6 @@ namespace garlic private: void ResetKeys (); - void MixHash (const uint8_t * buf, size_t len); void CreateNonce (uint64_t seqn, uint8_t * nonce); bool GenerateEphemeralKeysAndEncode (uint8_t * buf); // buf is 32 bytes std::shared_ptr CreateNewSessionTagset (); @@ -186,7 +189,7 @@ namespace garlic void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset, int index); void HandleNextKey (const uint8_t * buf, size_t len, const std::shared_ptr& receiveTagset); - bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); + bool NewOutgoingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen, bool isStatic = true); bool NewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NextNewSessionReplyMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); bool NewExistingSessionMessage (const uint8_t * payload, size_t len, uint8_t * out, size_t outLen); @@ -200,7 +203,7 @@ namespace garlic private: - uint8_t m_H[32], m_CK[64] /* [chainkey, key] */, m_RemoteStaticKey[32]; + uint8_t m_RemoteStaticKey[32]; uint8_t m_Aepk[32]; // Alice's ephemeral keys, for incoming only uint8_t m_NSREncodedKey[32], m_NSRH[32], m_NSRKey[32]; // new session reply, for incoming only std::shared_ptr m_EphemeralKeys; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index 5f76bca1..d8d034a1 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -709,11 +709,20 @@ namespace garlic } } - std::shared_ptr GarlicDestination::WrapMessage (std::shared_ptr destination, - std::shared_ptr msg, bool attachLeaseSet) + std::shared_ptr GarlicDestination::WrapMessageForRouter (std::shared_ptr router, + std::shared_ptr msg) { - auto session = GetRoutingSession (destination, attachLeaseSet); - return session->WrapSingleMessage (msg); + if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) + { + auto session = std::make_shared(this, false); + session->SetRemoteStaticKey (router->GetIdentity ()->GetEncryptionPublicKey ()); + return session->WrapOneTimeMessage (msg); + } + else + { + auto session = GetRoutingSession (router, false); + return session->WrapSingleMessage (msg); + } } std::shared_ptr GarlicDestination::GetRoutingSession ( diff --git a/libi2pd/Garlic.h b/libi2pd/Garlic.h index 3c5d5de6..8df830c7 100644 --- a/libi2pd/Garlic.h +++ b/libi2pd/Garlic.h @@ -238,8 +238,8 @@ namespace garlic std::shared_ptr GetRoutingSession (std::shared_ptr destination, bool attachLeaseSet); void CleanupExpiredTags (); void RemoveDeliveryStatusSession (uint32_t msgID); - std::shared_ptr WrapMessage (std::shared_ptr destination, - std::shared_ptr msg, bool attachLeaseSet = false); + std::shared_ptr WrapMessageForRouter (std::shared_ptr router, + std::shared_ptr msg); void AddSessionKey (const uint8_t * key, const uint8_t * tag); // one tag void AddECIESx25519Key (const uint8_t * key, const uint8_t * tag); // one tag From 07b77443ddbdacf9b49221d675d9c37e997a2c46 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 7 Nov 2020 18:28:38 -0500 Subject: [PATCH 39/75] don't handle TunnelBuild message for ECIES router --- libi2pd/I2NPProtocol.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libi2pd/I2NPProtocol.cpp b/libi2pd/I2NPProtocol.cpp index 283c5641..5ad6df78 100644 --- a/libi2pd/I2NPProtocol.cpp +++ b/libi2pd/I2NPProtocol.cpp @@ -448,7 +448,7 @@ namespace i2p { int num = buf[0]; LogPrint (eLogDebug, "I2NP: VariableTunnelBuild ", num, " records"); - if (len < num*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE + 1) + if (len < num*TUNNEL_BUILD_RECORD_SIZE + 1) { LogPrint (eLogError, "VaribleTunnelBuild message of ", num, " records is too short ", len); return; @@ -516,7 +516,12 @@ namespace i2p void HandleTunnelBuildMsg (uint8_t * buf, size_t len) { - if (len < NUM_TUNNEL_BUILD_RECORDS*BUILD_REQUEST_RECORD_CLEAR_TEXT_SIZE) + if (i2p::context.IsECIES ()) + { + LogPrint (eLogWarning, "TunnelBuild is too old for ECIES router"); + return; + } + if (len < NUM_TUNNEL_BUILD_RECORDS*TUNNEL_BUILD_RECORD_SIZE) { LogPrint (eLogError, "TunnelBuild message is too short ", len); return; From 1c7780a423659ddd7fa49d9c672992a505a9dcb8 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 9 Nov 2020 15:35:50 -0500 Subject: [PATCH 40/75] garlic clove block for router --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index bd8d2fe6..1d51e67e 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -899,7 +899,7 @@ namespace garlic } } // msg - if (msg && m_Destination) + if (msg) offset += CreateGarlicClove (msg, v.data () + offset, payloadLen - offset); // ack if (m_AckRequests.size () > 0) From 7e874eaa7ce707f45a3b2a46db74ae8d48b114a3 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 12 Nov 2020 15:15:02 -0500 Subject: [PATCH 41/75] pre-calculated h --- libi2pd/TunnelConfig.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libi2pd/TunnelConfig.cpp b/libi2pd/TunnelConfig.cpp index c0ebb766..a1b234a1 100644 --- a/libi2pd/TunnelConfig.cpp +++ b/libi2pd/TunnelConfig.cpp @@ -152,8 +152,13 @@ namespace tunnel void InitBuildRequestRecordNoiseState (i2p::crypto::NoiseSymmetricState& state) { static const char protocolName[] = "Noise_N_25519_ChaChaPoly_SHA256"; // 31 chars + static const uint8_t hh[32] = + { + 0x69, 0x4d, 0x52, 0x44, 0x5a, 0x27, 0xd9, 0xad, 0xfa, 0xd2, 0x9c, 0x76, 0x32, 0x39, 0x5d, 0xc1, + 0xe4, 0x35, 0x4c, 0x69, 0xb4, 0xf9, 0x2e, 0xac, 0x8a, 0x1e, 0xe4, 0x6a, 0x9e, 0xd2, 0x15, 0x54 + }; // SHA256 (protocol_name || 0) memcpy (state.m_CK, protocolName, 32); // ck = h = protocol_name || 0 - SHA256 (state.m_CK, 32, state.m_H); // h = SHA256(h); + memcpy (state.m_H, hh, 32); // h = SHA256(h) } } } \ No newline at end of file From 62cd9fffa39bc296268b6134cd903d2705023835 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sun, 15 Nov 2020 01:31:20 +0300 Subject: [PATCH 42/75] Automate AES-NI and AVX detection on runtime, make it default on x86-based systems (#1578) Rework CPU extensions detection code and build with AES-NI and AVX support by default --- .github/workflows/build-osx.yml | 20 +++ .github/workflows/build-qt.yml | 20 --- .github/workflows/build.yml | 18 ++- .gitignore | 3 +- Makefile | 7 +- Makefile.homebrew | 7 +- Makefile.linux | 21 +-- Makefile.mingw | 17 +-- Makefile.osx | 8 +- build/CMakeLists.txt | 16 +- build/build_mingw.cmd | 29 ++-- .../installer.iss => build/win_installer.iss | 13 +- contrib/i2pd.conf | 9 ++ daemon/Daemon.cpp | 5 +- debian/compat | 2 +- .../{02-fix-1210.patch => 01-fix-1210.patch} | 0 debian/patches/01-tune-build-opts.patch | 15 -- debian/patches/series | 3 +- libi2pd/CPU.cpp | 33 ++-- libi2pd/CPU.h | 2 +- libi2pd/Config.cpp | 18 ++- libi2pd/Crypto.cpp | 143 +++++++++--------- libi2pd/Crypto.h | 13 +- libi2pd/Identity.cpp | 2 +- libi2pd/api.cpp | 5 +- qt/i2pd_qt/i2pd_qt.pro | 16 +- 26 files changed, 208 insertions(+), 237 deletions(-) create mode 100644 .github/workflows/build-osx.yml delete mode 100644 .github/workflows/build-qt.yml rename Win32/installer.iss => build/win_installer.iss (75%) rename debian/patches/{02-fix-1210.patch => 01-fix-1210.patch} (100%) delete mode 100644 debian/patches/01-tune-build-opts.patch diff --git a/.github/workflows/build-osx.yml b/.github/workflows/build-osx.yml new file mode 100644 index 00000000..50672d26 --- /dev/null +++ b/.github/workflows/build-osx.yml @@ -0,0 +1,20 @@ +name: Build on OSX + +on: [push, pull_request] + +jobs: + build: + name: With USE_UPNP=${{ matrix.with_upnp }} + runs-on: macOS-latest + strategy: + fail-fast: true + matrix: + with_upnp: ['yes', 'no'] + steps: + - uses: actions/checkout@v2 + - name: install packages + run: | + brew update + brew install boost miniupnpc openssl@1.1 + - name: build application + run: make HOMEBREW=1 USE_UPNP=${{ matrix.with_upnp }} PREFIX=$GITHUB_WORKSPACE/output -j3 diff --git a/.github/workflows/build-qt.yml b/.github/workflows/build-qt.yml deleted file mode 100644 index d4fde2b9..00000000 --- a/.github/workflows/build-qt.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: Build on Ubuntu - -on: [push, pull_request] - -jobs: - build: - name: With QT GUI - runs-on: ubuntu-16.04 - steps: - - uses: actions/checkout@v2 - - name: install packages - run: | - sudo add-apt-repository ppa:mhier/libboost-latest - sudo apt-get update - sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev - - name: build application - run: | - cd qt/i2pd_qt - qmake - make -j3 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5e5152e0..bb995219 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,4 +18,20 @@ jobs: sudo apt-get update sudo apt-get install build-essential libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev - name: build application - run: make USE_AVX=no USE_AESNI=no USE_UPNP=${{ matrix.with_upnp }} -j3 + run: make USE_UPNP=${{ matrix.with_upnp }} -j3 + + build_qt: + name: With QT GUI + runs-on: ubuntu-16.04 + steps: + - uses: actions/checkout@v2 + - name: install packages + run: | + sudo add-apt-repository ppa:mhier/libboost-latest + sudo apt-get update + sudo apt-get install build-essential qt5-default libqt5gui5 libboost1.74-dev libminiupnpc-dev libssl-dev zlib1g-dev + - name: build application + run: | + cd qt/i2pd_qt + qmake + make -j3 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3319fa10..2506fd93 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,12 @@ router.info router.keys i2p -libi2pd.so netDb /i2pd /libi2pd.a /libi2pdclient.a +/libi2pd.so +/libi2pdclient.so *.exe diff --git a/Makefile b/Makefile index 35d76b82..c359d7c7 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,6 @@ DAEMON_SRC_DIR := daemon include filelist.mk USE_AESNI := yes -USE_AVX := yes USE_STATIC := no USE_MESHNET := no USE_UPNP := no @@ -77,7 +76,7 @@ deps: mk_obj_dir @sed -i -e '/\.o:/ s/^/obj\//' $(DEPS) obj/%.o: %.cpp - $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) $(CPU_FLAGS) -c -o $@ $< + $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -c -o $@ $< # '-' is 'ignore if missing' on first run -include $(DEPS) @@ -88,11 +87,11 @@ $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) ifneq ($(USE_STATIC),yes) - $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ + $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) endif $(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) - $(CXX) $(LDFLAGS) $(LDLIBS) -shared -o $@ $^ + $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB) $(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) $(AR) -r $@ $^ diff --git a/Makefile.homebrew b/Makefile.homebrew index 64301c02..c1992296 100644 --- a/Makefile.homebrew +++ b/Makefile.homebrew @@ -35,10 +35,7 @@ endif # Seems like all recent Mac's have AES-NI, after firmware upgrade 2.2 # Found no good way to detect it from command line. TODO: Might be some osx sysinfo magic ifeq ($(USE_AESNI),yes) - CXXFLAGS += -maes -endif -ifeq ($(USE_AVX),1) - CXXFLAGS += -mavx + CXXFLAGS += -D__AES__ -maes endif install: all @@ -51,4 +48,4 @@ install: all @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 \ No newline at end of file + @ln -sf ${PREFIX}/etc/i2pd/tunnels.conf ${PREFIX}/var/lib/i2pd/tunnels.conf diff --git a/Makefile.linux b/Makefile.linux index 3ef4793c..6a7590c1 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -1,5 +1,5 @@ # set defaults instead redefine -CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-misleading-indentation -Wno-psabi +CXXFLAGS ?= ${CXX_DEBUG} -Wall -Wextra -Wno-unused-parameter -pedantic -Wno-psabi LDFLAGS ?= ${LD_DEBUG} ## NOTE: The NEEDED_CXXFLAGS are here so that custom CXXFLAGS can be specified at build time @@ -49,7 +49,7 @@ endif # UPNP Support (miniupnpc 1.5 and higher) ifeq ($(USE_UPNP),yes) - CXXFLAGS += -DUSE_UPNP + NEEDED_CXXFLAGS += -DUSE_UPNP ifeq ($(USE_STATIC),yes) LDLIBS += $(LIBDIR)/libminiupnpc.a else @@ -58,20 +58,7 @@ endif endif ifeq ($(USE_AESNI),yes) -#check if AES-NI is supported by CPU -ifneq ($(shell $(GREP) -c aes /proc/cpuinfo),0) - machine := $(shell uname -m) - ifeq ($(machine), aarch64) - CXXFLAGS += -DARM64AES - else - CPU_FLAGS += -maes - endif -endif -endif - -ifeq ($(USE_AVX),yes) -#check if AVX supported by CPU -ifneq ($(shell $(GREP) -c avx /proc/cpuinfo),0) - CPU_FLAGS += -mavx +ifeq (, $(findstring arm, $(SYS))$(findstring aarch64, $(SYS))) # no arm and aarch64 in dumpmachine + NEEDED_CXXFLAGS += -D__AES__ -maes endif endif diff --git a/Makefile.mingw b/Makefile.mingw index 2782b715..764606b6 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,7 +1,7 @@ USE_WIN32_APP=yes CXX = g++ WINDRES = windres -CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN +CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -fPIC -msse INCFLAGS = -Idaemon -I. LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ @@ -42,25 +42,18 @@ LDLIBS += \ -lpthread ifeq ($(USE_WIN32_APP), yes) - CXXFLAGS += -DWIN32_APP + NEEDED_CXXFLAGS += -DWIN32_APP LDFLAGS += -mwindows DAEMON_RC += Win32/Resource.rc DAEMON_OBJS += $(patsubst %.rc,obj/%.o,$(DAEMON_RC)) endif ifeq ($(USE_WINXP_FLAGS), yes) - CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 + NEEDED_CXXFLAGS += -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 endif -# don't change following line to ifeq ($(USE_AESNI),yes) !!! -ifeq ($(USE_AESNI),1) - CPU_FLAGS += -maes -else - CPU_FLAGS += -msse -endif - -ifeq ($(USE_AVX),1) - CPU_FLAGS += -mavx +ifeq ($(USE_AESNI),yes) + NEEDED_CXXFLAGS += -D__AES__ -maes endif ifeq ($(USE_ASLR),yes) diff --git a/Makefile.osx b/Makefile.osx index c6af4fc2..2e52585e 100644 --- a/Makefile.osx +++ b/Makefile.osx @@ -22,12 +22,8 @@ ifeq ($(USE_UPNP),yes) endif endif -ifeq ($(USE_AESNI),1) - CXXFLAGS += -maes +ifeq ($(USE_AESNI),yes) + CXXFLAGS += -D__AES__ -maes else CXXFLAGS += -msse endif - -ifeq ($(USE_AVX),1) - CXXFLAGS += -mavx -endif diff --git a/build/CMakeLists.txt b/build/CMakeLists.txt index 827e20d3..6f9fbae6 100644 --- a/build/CMakeLists.txt +++ b/build/CMakeLists.txt @@ -11,9 +11,8 @@ if(WIN32 OR MSVC OR MSYS OR MINGW) message(SEND_ERROR "cmake build for windows is not supported. Please use MSYS2 with makefiles in project root.") endif() -# configurale options -option(WITH_AESNI "Use AES-NI instructions set" OFF) -option(WITH_AVX "Use AVX instructions" OFF) +# configurable options +option(WITH_AESNI "Use AES-NI instructions set" ON) option(WITH_HARDENING "Use hardening compiler flags" OFF) option(WITH_LIBRARY "Build library" ON) option(WITH_BINARY "Build binary" ON) @@ -189,13 +188,11 @@ if(UNIX) endif() endif() -if(WITH_AESNI) +# Note: AES-NI and AVX is available on x86-based CPU's. +# Here also ARM64 implementation, but currently we don't support it. +if(WITH_AESNI AND (ARCHITECTURE MATCHES "x86_64" OR ARCHITECTURE MATCHES "i386")) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes") - add_definitions(-DAESNI) -endif() - -if(WITH_AVX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mavx") + add_definitions(-D__AES__) endif() if(WITH_ADDRSANITIZER) @@ -309,7 +306,6 @@ message(STATUS "Architecture : ${ARCHITECTURE}") message(STATUS "Install prefix: : ${CMAKE_INSTALL_PREFIX}") message(STATUS "Options:") message(STATUS " AESNI : ${WITH_AESNI}") -message(STATUS " AVX : ${WITH_AVX}") message(STATUS " HARDENING : ${WITH_HARDENING}") message(STATUS " LIBRARY : ${WITH_LIBRARY}") message(STATUS " BINARY : ${WITH_BINARY}") diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index ec861bb2..37a1d454 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -30,10 +30,10 @@ REM we must work in root of repo cd .. REM deleting old log files -del /S build_*.log >> nul +del /S build_*.log >> nul 2>&1 echo Receiving latest commit and cleaning up... -%xSH% "git pull && make clean" > build/build_git.log 2>&1 +%xSH% "git checkout contrib/* && git pull && make clean" > build/build.log 2>&1 echo. REM set to variable current commit hash @@ -43,16 +43,17 @@ FOR /F "usebackq" %%a IN (`%xSH% 'git describe --tags'`) DO ( %xSH% "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul +REM converting configuration files to DOS format (usable in default notepad) +%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/*" > build/build.log 2>&1 + REM starting building set MSYSTEM=MINGW32 set bitness=32 call :BUILDING -echo. set MSYSTEM=MINGW64 set bitness=64 call :BUILDING -echo. REM building for WinXP set "WD=C:\msys64-xp\usr\bin\" @@ -62,7 +63,10 @@ set "xSH=%WD%bash -lc" call :BUILDING_XP echo. -del README.txt >> nul +REM compile installer +C:\PROGRA~2\INNOSE~1\ISCC.exe build\win_installer.iss + +del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul echo Build complete... pause @@ -70,20 +74,13 @@ exit /b 0 :BUILDING %xSH% "make clean" >> nul -echo Building i2pd %tag% for win%bitness%: -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 %FILELIST% && make clean" > build/build_win%bitness%_avx_aesni_%tag%.log 2>&1 -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 %FILELIST% && make clean" > build/build_win%bitness%_avx_%tag%.log 2>&1 -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 %FILELIST% && make clean" > build/build_win%bitness%_aesni_%tag%.log 2>&1 -echo Build without extensions... -%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 +echo Building i2pd %tag% for win%bitness% +%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1 goto EOF :BUILDING_XP %xSH% "make clean" >> nul -echo Building i2pd %tag% for winxp... -%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build/build_winxp_%tag%.log 2>&1 +echo Building i2pd %tag% for winxp +%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build/build_winxp_%tag%.log 2>&1 :EOF \ No newline at end of file diff --git a/Win32/installer.iss b/build/win_installer.iss similarity index 75% rename from Win32/installer.iss rename to build/win_installer.iss index cc40c409..007cd643 100644 --- a/Win32/installer.iss +++ b/build/win_installer.iss @@ -1,6 +1,7 @@ #define I2Pd_AppName "i2pd" -#define I2Pd_ver "2.34.0" #define I2Pd_Publisher "PurpleI2P" +; Get application version from compiled binary +#define I2Pd_ver GetFileVersionString(AddBackslash(SourcePath) + "..\i2pd_x64.exe") [Setup] AppName={#I2Pd_AppName} @@ -10,9 +11,9 @@ DefaultDirName={pf}\I2Pd DefaultGroupName=I2Pd UninstallDisplayIcon={app}\I2Pd.exe OutputDir=. -LicenseFile=../LICENSE +LicenseFile=..\LICENSE OutputBaseFilename=setup_{#I2Pd_AppName}_v{#I2Pd_ver} -SetupIconFile=mask.ico +SetupIconFile=..\Win32\mask.ico InternalCompressLevel=ultra64 Compression=lzma/ultra64 SolidCompression=true @@ -23,10 +24,12 @@ AppID={{621A23E0-3CF4-4BD6-97BC-4835EA5206A2} AppPublisherURL=http://i2pd.website/ AppSupportURL=https://github.com/PurpleI2P/i2pd/issues AppUpdatesURL=https://github.com/PurpleI2P/i2pd/releases +CloseApplications=yes [Files] -Source: ..\i2pd_x86.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64 -Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64 +Source: ..\i2pd_x32.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: not IsWin64; MinVersion: 6.0 +Source: ..\i2pd_x64.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64; MinVersion: 6.0 +Source: ..\i2pd_xp.exe; DestDir: {app}; DestName: i2pd.exe; Flags: ignoreversion; Check: IsWin64; OnlyBelowVersion: 6.0 Source: ..\README.md; DestDir: {app}; DestName: Readme.txt; Flags: onlyifdoesntexist Source: ..\contrib\i2pd.conf; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist Source: ..\contrib\subscriptions.txt; DestDir: {userappdata}\i2pd; Flags: onlyifdoesntexist diff --git a/contrib/i2pd.conf b/contrib/i2pd.conf index 2174abe8..5ef39bc9 100644 --- a/contrib/i2pd.conf +++ b/contrib/i2pd.conf @@ -229,3 +229,12 @@ verify = true [persist] ## Save peer profiles on disk (default: true) # profiles = true + +[cpuext] +## Use CPU AES-NI instructions set when work with cryptography when available (default: true) +# aesni = true +## Use CPU AVX instructions set when work with cryptography when available (default: true) +# avx = true +## Force usage of CPU instructions set, even if they not found +## DO NOT TOUCH that option if you really don't know what are you doing! +# force = false \ No newline at end of file diff --git a/daemon/Daemon.cpp b/daemon/Daemon.cpp index 0317704a..839495a5 100644 --- a/daemon/Daemon.cpp +++ b/daemon/Daemon.cpp @@ -128,7 +128,10 @@ namespace i2p LogPrint(eLogDebug, "FS: data directory: ", datadir); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); - i2p::crypto::InitCrypto (precomputation); + bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); + bool avx; i2p::config::GetOption("cpuext.avx", avx); + bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); + i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt); int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); diff --git a/debian/compat b/debian/compat index f11c82a4..9a037142 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -9 \ No newline at end of file +10 \ No newline at end of file diff --git a/debian/patches/02-fix-1210.patch b/debian/patches/01-fix-1210.patch similarity index 100% rename from debian/patches/02-fix-1210.patch rename to debian/patches/01-fix-1210.patch diff --git a/debian/patches/01-tune-build-opts.patch b/debian/patches/01-tune-build-opts.patch deleted file mode 100644 index e06a8621..00000000 --- a/debian/patches/01-tune-build-opts.patch +++ /dev/null @@ -1,15 +0,0 @@ -Index: i2pd/Makefile -=================================================================== ---- i2pd.orig/Makefile -+++ i2pd/Makefile -@@ -13,8 +13,8 @@ DAEMON_SRC_DIR := daemon - - include filelist.mk - --USE_AESNI := yes --USE_AVX := yes -+USE_AESNI := no -+USE_AVX := no - USE_STATIC := no - USE_MESHNET := no - USE_UPNP := no diff --git a/debian/patches/series b/debian/patches/series index 002802b5..07f821c8 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ -01-tune-build-opts.patch -02-fix-1210.patch +01-fix-1210.patch diff --git a/libi2pd/CPU.cpp b/libi2pd/CPU.cpp index e7eff473..0bd830e3 100644 --- a/libi2pd/CPU.cpp +++ b/libi2pd/CPU.cpp @@ -27,37 +27,24 @@ namespace cpu bool aesni = false; bool avx = false; - void Detect() + void Detect(bool AesSwitch, bool AvxSwitch, bool force) { -#if defined(__AES__) || defined(__AVX__) - #if defined(__x86_64__) || defined(__i386__) int info[4]; __cpuid(0, info[0], info[1], info[2], info[3]); if (info[0] >= 0x00000001) { __cpuid(0x00000001, info[0], info[1], info[2], info[3]); -#ifdef __AES__ - aesni = info[2] & bit_AES; // AESNI -#endif // __AES__ -#ifdef __AVX__ - avx = info[2] & bit_AVX; // AVX -#endif // __AVX__ + if ((info[2] & bit_AES && AesSwitch) || (AesSwitch && force)) { + aesni = true; + } + if ((info[2] & bit_AVX && AvxSwitch) || (AvxSwitch && force)) { + avx = true; + } } -#endif // defined(__x86_64__) || defined(__i386__) +#endif // defined(__x86_64__) || defined(__i386__) -#ifdef __AES__ - if(aesni) - { - LogPrint(eLogInfo, "AESNI enabled"); - } -#endif // __AES__ -#ifdef __AVX__ - if(avx) - { - LogPrint(eLogInfo, "AVX enabled"); - } -#endif // __AVX__ -#endif // defined(__AES__) || defined(__AVX__) + LogPrint(eLogInfo, "AESNI ", (aesni ? "enabled" : "disabled")); + LogPrint(eLogInfo, "AVX ", (avx ? "enabled" : "disabled")); } } } diff --git a/libi2pd/CPU.h b/libi2pd/CPU.h index 9677b293..f021bccb 100644 --- a/libi2pd/CPU.h +++ b/libi2pd/CPU.h @@ -16,7 +16,7 @@ namespace cpu extern bool aesni; extern bool avx; - void Detect(); + void Detect(bool AesSwitch, bool AvxSwitch, bool force); } } diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index fc479532..d99fdde1 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -47,11 +47,11 @@ namespace config { ("ifname", value()->default_value(""), "Network interface to bind to") ("ifname4", value()->default_value(""), "Network interface to bind to for ipv4") ("ifname6", value()->default_value(""), "Network interface to bind to for ipv6") - ("nat", value()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") + ("nat", bool_switch()->default_value(true), "Should we assume we are behind NAT? (default: enabled)") ("port", value()->default_value(0), "Port to listen for incoming connections (default: auto)") - ("ipv4", value()->default_value(true), "Enable communication through ipv4 (default: enabled)") + ("ipv4", bool_switch()->default_value(true), "Enable communication through ipv4 (default: enabled)") ("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)") - ("reservedrange", value()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)") + ("reservedrange", bool_switch()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)") ("netid", value()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2") ("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)") ("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)") @@ -59,8 +59,8 @@ namespace config { ("floodfill", bool_switch()->default_value(false), "Router will be floodfill (default: disabled)") ("bandwidth", value()->default_value(""), "Bandwidth limit: integer in KBps or letters: L (32), O (256), P (2048), X (>9000)") ("share", value()->default_value(100), "Limit of transit traffic from max bandwidth in percents. (default: 100)") - ("ntcp", value()->default_value(false), "Ignored. Always false") - ("ssu", value()->default_value(true), "Enable SSU transport (default: enabled)") + ("ntcp", bool_switch()->default_value(false), "Ignored. Always false") + ("ssu", bool_switch()->default_value(true), "Enable SSU transport (default: enabled)") ("ntcpproxy", value()->default_value(""), "Ignored") #ifdef _WIN32 ("svcctl", value()->default_value(""), "Windows service management ('install' or 'remove')") @@ -266,6 +266,13 @@ namespace config { ("persist.addressbook", value()->default_value(true), "Persist full addresses (default: true)") ; + options_description cpuext("CPU encryption extensions options"); + cpuext.add_options() + ("cpuext.aesni", bool_switch()->default_value(true), "Use auto detection for AESNI CPU extensions. If false, AESNI will be not used") + ("cpuext.avx", bool_switch()->default_value(true), "Use auto detection for AVX CPU extensions. If false, AVX will be not used") + ("cpuext.force", bool_switch()->default_value(false), "Force usage of CPU extensions. Useful when cpuinfo is not available on virtual machines") + ; + m_OptionsDesc .add(general) .add(limits) @@ -286,6 +293,7 @@ namespace config { .add(ntcp2) .add(nettime) .add(persist) + .add(cpuext) ; } diff --git a/libi2pd/Crypto.cpp b/libi2pd/Crypto.cpp index ea2cd675..523828ce 100644 --- a/libi2pd/Crypto.cpp +++ b/libi2pd/Crypto.cpp @@ -119,7 +119,7 @@ namespace crypto ~CryptoConstants () { - BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae); + BN_free (elgp); BN_free (elgg); BN_free (dsap); BN_free (dsaq); BN_free (dsag); BN_free (rsae); } }; @@ -522,7 +522,7 @@ namespace crypto bn2buf (y, encrypted + len, len); RAND_bytes (encrypted + 2*len, 256 - 2*len); } - // ecryption key and iv + // encryption key and iv EC_POINT_mul (curve, p, nullptr, key, k, ctx); EC_POINT_get_affine_coordinates_GFp (curve, p, x, y, nullptr); uint8_t keyBuf[64], iv[64], shared[32]; @@ -638,7 +638,7 @@ namespace crypto { uint64_t buf[256]; uint64_t hash[12]; // 96 bytes -#ifdef __AVX__ +#if defined(__x86_64__) || defined(__i386__) if(i2p::cpu::avx) { __asm__ @@ -657,7 +657,7 @@ namespace crypto : : [key]"m"(*(const uint8_t *)key), [ipad]"m"(*ipads), [opad]"m"(*opads), [buf]"r"(buf), [hash]"r"(hash) - : "memory", "%xmm0" // TODO: change to %ymm0 later + : "memory", "%xmm0" // TODO: change to %ymm0 later ); } else @@ -688,7 +688,7 @@ namespace crypto // concatenate with msg memcpy (buf + 8, msg, len); // calculate first hash - MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes + MD5((uint8_t *)buf, len + 64, (uint8_t *)(hash + 8)); // 16 bytes // calculate digest MD5((uint8_t *)hash, 96, digest); @@ -696,35 +696,28 @@ namespace crypto // AES #ifdef __AES__ - #ifdef ARM64AES - void init_aesenc(void){ - // TODO: Implementation - } - - #endif - #define KeyExpansion256(round0,round1) \ - "pshufd $0xff, %%xmm2, %%xmm2 \n" \ - "movaps %%xmm1, %%xmm4 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pshufd $0xff, %%xmm2, %%xmm2 \n" \ + "movaps %%xmm1, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm1 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm1 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm1 \n" \ "pxor %%xmm2, %%xmm1 \n" \ - "movaps %%xmm1, "#round0"(%[sched]) \n" \ + "movaps %%xmm1, "#round0"(%[sched]) \n" \ "aeskeygenassist $0, %%xmm1, %%xmm4 \n" \ - "pshufd $0xaa, %%xmm4, %%xmm2 \n" \ - "movaps %%xmm3, %%xmm4 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pshufd $0xaa, %%xmm4, %%xmm2 \n" \ + "movaps %%xmm3, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm3 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm3 \n" \ - "pslldq $4, %%xmm4 \n" \ + "pslldq $4, %%xmm4 \n" \ "pxor %%xmm4, %%xmm3 \n" \ "pxor %%xmm2, %%xmm3 \n" \ - "movaps %%xmm3, "#round1"(%[sched]) \n" + "movaps %%xmm3, "#round1"(%[sched]) \n" #endif #ifdef __AES__ @@ -750,16 +743,16 @@ namespace crypto KeyExpansion256(192,208) "aeskeygenassist $64, %%xmm3, %%xmm2 \n" // key expansion final - "pshufd $0xff, %%xmm2, %%xmm2 \n" - "movaps %%xmm1, %%xmm4 \n" - "pslldq $4, %%xmm4 \n" + "pshufd $0xff, %%xmm2, %%xmm2 \n" + "movaps %%xmm1, %%xmm4 \n" + "pslldq $4, %%xmm4 \n" "pxor %%xmm4, %%xmm1 \n" - "pslldq $4, %%xmm4 \n" + "pslldq $4, %%xmm4 \n" "pxor %%xmm4, %%xmm1 \n" - "pslldq $4, %%xmm4 \n" + "pslldq $4, %%xmm4 \n" "pxor %%xmm4, %%xmm1 \n" "pxor %%xmm2, %%xmm1 \n" - "movups %%xmm1, 224(%[sched]) \n" + "movups %%xmm1, 224(%[sched]) \n" : // output : [key]"r"((const uint8_t *)key), [sched]"r"(GetKeySchedule ()) // input : "%xmm1", "%xmm2", "%xmm3", "%xmm4", "memory" // clogged @@ -794,9 +787,9 @@ namespace crypto { __asm__ ( - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" EncryptAES256(sched) - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); } @@ -833,9 +826,9 @@ namespace crypto { __asm__ ( - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" DecryptAES256(sched) - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" : : [sched]"r"(GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "memory" ); } @@ -848,7 +841,7 @@ namespace crypto #ifdef __AES__ #define CallAESIMC(offset) \ - "movaps "#offset"(%[shed]), %%xmm0 \n" \ + "movaps "#offset"(%[shed]), %%xmm0 \n" \ "aesimc %%xmm0, %%xmm0 \n" \ "movaps %%xmm0, "#offset"(%[shed]) \n" #endif @@ -873,7 +866,7 @@ namespace crypto if(i2p::cpu::aesni) { ExpandKey (key); // expand encryption key first - // then invert it using aesimc + // then invert it using aesimc __asm__ ( CallAESIMC(16) @@ -906,18 +899,18 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" + "movups (%[iv]), %%xmm1 \n" "1: \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n" EncryptAES256(sched) - "movaps %%xmm0, %%xmm1 \n" - "movups %%xmm0, (%[out]) \n" + "movaps %%xmm0, %%xmm1 \n" + "movups %%xmm0, (%[out]) \n" "add $16, %[in] \n" "add $16, %[out] \n" "dec %[num] \n" "jnz 1b \n" - "movups %%xmm1, (%[iv]) \n" + "movups %%xmm1, (%[iv]) \n" : : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) @@ -951,12 +944,12 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[iv]), %%xmm1 \n" + "movups (%[in]), %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n" EncryptAES256(sched) - "movups %%xmm0, (%[out]) \n" - "movups %%xmm0, (%[iv]) \n" + "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[iv]) \n" : : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out) @@ -975,19 +968,19 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" + "movups (%[iv]), %%xmm1 \n" "1: \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "movaps %%xmm0, %%xmm2 \n" DecryptAES256(sched) "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" "movaps %%xmm2, %%xmm1 \n" "add $16, %[in] \n" "add $16, %[out] \n" "dec %[num] \n" "jnz 1b \n" - "movups %%xmm1, (%[iv]) \n" + "movups %%xmm1, (%[iv]) \n" : : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) @@ -1021,12 +1014,12 @@ namespace crypto { __asm__ ( - "movups (%[iv]), %%xmm1 \n" - "movups (%[in]), %%xmm0 \n" - "movups %%xmm0, (%[iv]) \n" + "movups (%[iv]), %%xmm1 \n" + "movups (%[in]), %%xmm0 \n" + "movups %%xmm0, (%[iv]) \n" DecryptAES256(sched) "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" : : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out) @@ -1046,7 +1039,7 @@ namespace crypto __asm__ ( // encrypt IV - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" EncryptAES256(sched_iv) "movaps %%xmm0, %%xmm1 \n" // double IV encryption @@ -1056,11 +1049,11 @@ namespace crypto "1: \n" "add $16, %[in] \n" "add $16, %[out] \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "pxor %%xmm1, %%xmm0 \n" EncryptAES256(sched_l) - "movaps %%xmm0, %%xmm1 \n" - "movups %%xmm0, (%[out]) \n" + "movaps %%xmm0, %%xmm1 \n" + "movups %%xmm0, (%[out]) \n" "dec %[num] \n" "jnz 1b \n" : @@ -1097,11 +1090,11 @@ namespace crypto "1: \n" "add $16, %[in] \n" "add $16, %[out] \n" - "movups (%[in]), %%xmm0 \n" + "movups (%[in]), %%xmm0 \n" "movaps %%xmm0, %%xmm2 \n" DecryptAES256(sched_l) "pxor %%xmm1, %%xmm0 \n" - "movups %%xmm0, (%[out]) \n" + "movups %%xmm0, (%[out]) \n" "movaps %%xmm2, %%xmm1 \n" "dec %[num] \n" "jnz 1b \n" @@ -1324,23 +1317,23 @@ namespace crypto } void NoiseSymmetricState::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); - } + { + SHA256_CTX ctx; + SHA256_Init (&ctx); + SHA256_Update (&ctx, m_H, 32); + SHA256_Update (&ctx, buf, len); + SHA256_Final (m_H, &ctx); + } - void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret) - { - HKDF (m_CK, sharedSecret, 32, "", m_CK); + void NoiseSymmetricState::MixKey (const uint8_t * sharedSecret) + { + HKDF (m_CK, sharedSecret, 32, "", m_CK); // new ck is m_CK[0:31], key is m_CK[32:63] - } - + } + // init and terminate -/* std::vector > m_OpenSSLMutexes; +/* std::vector > m_OpenSSLMutexes; static void OpensslLockingCallback(int mode, int type, const char * file, int line) { if (type > 0 && (size_t)type < m_OpenSSLMutexes.size ()) @@ -1351,10 +1344,10 @@ namespace crypto m_OpenSSLMutexes[type]->unlock (); } }*/ - - void InitCrypto (bool precomputation) + + void InitCrypto (bool precomputation, bool aesni, bool avx, bool force) { - i2p::cpu::Detect (); + i2p::cpu::Detect (aesni, avx, force); #if LEGACY_OPENSSL SSL_library_init (); #endif diff --git a/libi2pd/Crypto.h b/libi2pd/Crypto.h index 205be44d..da7a4bf4 100644 --- a/libi2pd/Crypto.h +++ b/libi2pd/Crypto.h @@ -169,9 +169,6 @@ namespace crypto #ifdef __AES__ - #ifdef ARM64AES - void init_aesenc(void) __attribute__((constructor)); - #endif class ECBCryptoAESNI { public: @@ -316,13 +313,13 @@ namespace crypto struct NoiseSymmetricState { uint8_t m_H[32] /*h*/, m_CK[64] /*[ck, k]*/; - + void MixHash (const uint8_t * buf, size_t len); - void MixKey (const uint8_t * sharedSecret); - }; - + void MixKey (const uint8_t * sharedSecret); + }; + // init and terminate - void InitCrypto (bool precomputation); + void InitCrypto (bool precomputation, bool aesni, bool avx, bool force); void TerminateCrypto (); } } diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 7784cc90..88523492 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -828,7 +828,7 @@ namespace data XORMetric operator^(const IdentHash& key1, const IdentHash& key2) { XORMetric m; -#ifdef __AVX__ +#if defined(__x86_64__) || defined(__i386__) if(i2p::cpu::avx) { __asm__ diff --git a/libi2pd/api.cpp b/libi2pd/api.cpp index 569fbd8c..faeee84d 100644 --- a/libi2pd/api.cpp +++ b/libi2pd/api.cpp @@ -37,7 +37,10 @@ namespace api i2p::fs::Init(); bool precomputation; i2p::config::GetOption("precomputation.elgamal", precomputation); - i2p::crypto::InitCrypto (precomputation); + bool aesni; i2p::config::GetOption("cpuext.aesni", aesni); + bool avx; i2p::config::GetOption("cpuext.avx", avx); + bool forceCpuExt; i2p::config::GetOption("cpuext.force", forceCpuExt); + i2p::crypto::InitCrypto (precomputation, aesni, avx, forceCpuExt); int netID; i2p::config::GetOption("netid", netID); i2p::context.SetNetID (netID); diff --git a/qt/i2pd_qt/i2pd_qt.pro b/qt/i2pd_qt/i2pd_qt.pro index dba69143..eed4cd7b 100644 --- a/qt/i2pd_qt/i2pd_qt.pro +++ b/qt/i2pd_qt/i2pd_qt.pro @@ -4,14 +4,16 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = i2pd_qt TEMPLATE = app -QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized +QMAKE_CXXFLAGS *= -Wno-unused-parameter -Wno-maybe-uninitialized -Wno-deprecated-copy CONFIG += strict_c++ c++11 CONFIG(debug, debug|release) { message(Debug build) DEFINES += DEBUG_WITH_DEFAULT_LOGGING + I2PDMAKE += DEBUG=yes } else { message(Release build) + I2PDMAKE += DEBUG=no } SOURCES += DaemonQT.cpp mainwindow.cpp \ @@ -73,19 +75,19 @@ FORMS += mainwindow.ui \ LIBS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -lz -libi2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no api +libi2pd.commands = @echo Building i2pd libraries libi2pd.target = $$PWD/../../libi2pd.a -libi2pd.depends = FORCE +libi2pd.depends = i2pd FORCE -libi2pdclient.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_AVX=no USE_AESNI=no USE_UPNP=yes DEBUG=no api_client -libi2pdclient.target = $$PWD/../../libi2pdclient.a -libi2pdclient.depends = FORCE +i2pd.commands = cd $$PWD/../../ && mkdir -p obj/libi2pd_client && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) USE_UPNP=yes $$I2PDMAKE api_client +i2pd.target += $$PWD/../../libi2pdclient.a +i2pd.depends = FORCE cleani2pd.commands = cd $$PWD/../../ && CC=$$QMAKE_CC CXX=$$QMAKE_CXX $(MAKE) clean cleani2pd.depends = clean PRE_TARGETDEPS += $$PWD/../../libi2pd.a $$PWD/../../libi2pdclient.a -QMAKE_EXTRA_TARGETS += cleani2pd libi2pd libi2pdclient +QMAKE_EXTRA_TARGETS += cleani2pd i2pd libi2pd CLEAN_DEPS += cleani2pd From 8b3a7486c74b27199a08dc500e2a19dfe16e53a0 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 14 Nov 2020 18:28:50 -0500 Subject: [PATCH 43/75] rename CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET to CRYPTO_KEY_TYPE_ECIES_X25519_AEAD --- libi2pd/Destination.cpp | 14 +++++++------- libi2pd/ECIESX25519AEADRatchetSession.cpp | 12 ++++++------ libi2pd/Garlic.cpp | 11 ++++++----- libi2pd/Identity.cpp | 14 +++++++------- libi2pd/Identity.h | 2 +- libi2pd/RouterContext.h | 2 +- libi2pd/TunnelConfig.h | 2 +- libi2pd_client/I2CP.cpp | 8 ++++---- 8 files changed, 33 insertions(+), 32 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index bf6047b2..d51fc63d 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -744,7 +744,7 @@ namespace client request->excluded.insert (nextFloodfill->GetIdentHash ()); request->requestTimeoutTimer.cancel (); - bool isECIES = SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) && + bool isECIES = SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) && nextFloodfill->GetVersion () >= MAKE_VERSION_NUMBER(0, 9, 46); // >= 0.9.46; uint8_t replyKey[32], replyTag[32]; RAND_bytes (replyKey, 32); // random session key @@ -842,8 +842,8 @@ namespace client i2p::data::CryptoKeyType LeaseSetDestination::GetPreferredCryptoType () const { - if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) - return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; + if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) + return i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; return i2p::data::CRYPTO_KEY_TYPE_ELGAMAL; } @@ -898,7 +898,7 @@ namespace client else encryptionKey->GenerateKeys (); encryptionKey->CreateDecryptor (); - if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) + if (it == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) { m_ECIESx25519EncryptionKey.reset (encryptionKey); if (GetLeaseSetType () == i2p::data::NETDB_STORE_TYPE_LEASESET) @@ -1215,7 +1215,7 @@ namespace client bool ClientDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const { - if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) + if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) if (m_ECIESx25519EncryptionKey && m_ECIESx25519EncryptionKey->decryptor) return m_ECIESx25519EncryptionKey->decryptor->Decrypt (encrypted, data, ctx, true); if (m_StandardEncryptionKey && m_StandardEncryptionKey->decryptor) @@ -1227,12 +1227,12 @@ namespace client bool ClientDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { - return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET ? (bool)m_ECIESx25519EncryptionKey : (bool)m_StandardEncryptionKey; + return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519EncryptionKey : (bool)m_StandardEncryptionKey; } const uint8_t * ClientDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { - if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) + if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey->pub : nullptr; return m_StandardEncryptionKey ? m_StandardEncryptionKey->pub : nullptr; } diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 1d51e67e..3dfe4ca5 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -236,7 +236,7 @@ namespace garlic if (!GetOwner ()) return false; // we are Bob // KDF1 - MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET), 32); // h = SHA256(h || bpk) + MixHash (GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD), 32); // h = SHA256(h || bpk) if (!i2p::crypto::GetElligator ()->Decode (buf, m_Aepk)) { @@ -247,7 +247,7 @@ namespace garlic MixHash (m_Aepk, 32); // h = SHA256(h || aepk) uint8_t sharedSecret[32]; - GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, aepk) + GetOwner ()->Decrypt (m_Aepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, aepk) MixKey (sharedSecret); // decrypt flags/static @@ -267,7 +267,7 @@ namespace garlic { // static key, fs is apk memcpy (m_RemoteStaticKey, fs, 32); - GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519(bsk, apk) + GetOwner ()->Decrypt (fs, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519(bsk, apk) MixKey (sharedSecret); } else // all zeros flags @@ -469,7 +469,7 @@ namespace garlic CreateNonce (0, nonce); const uint8_t * fs; if (isStatic) - fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); + fs = GetOwner ()->GetEncryptionPublicKey (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); else { memset (out + offset, 0, 32); // all zeros flags section @@ -486,7 +486,7 @@ namespace garlic // KDF2 if (isStatic) { - GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bpk) + GetOwner ()->Decrypt (m_RemoteStaticKey, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bpk) MixKey (sharedSecret); } else @@ -618,7 +618,7 @@ namespace garlic // only fist time, we assume ephemeral keys the same m_EphemeralKeys->Agree (bepk, sharedSecret); // sharedSecret = x25519(aesk, bepk) MixKey (sharedSecret); - GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET); // x25519 (ask, bepk) + GetOwner ()->Decrypt (bepk, sharedSecret, nullptr, i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); // x25519 (ask, bepk) MixKey (sharedSecret); } uint8_t nonce[12]; diff --git a/libi2pd/Garlic.cpp b/libi2pd/Garlic.cpp index d8d034a1..2fe97156 100644 --- a/libi2pd/Garlic.cpp +++ b/libi2pd/Garlic.cpp @@ -506,7 +506,7 @@ namespace garlic else { bool found = false; - if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) + if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) { // try ECIESx25519 tag uint64_t tag; @@ -536,7 +536,7 @@ namespace garlic decryption->Decrypt(buf + 514, length - 514, buf + 514); HandleAESBlock (buf + 514, length - 514, decryption, msg->from); } - else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) + else if (SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) { // otherwise ECIESx25519 auto session = std::make_shared (this, false); // incoming @@ -712,7 +712,7 @@ namespace garlic std::shared_ptr GarlicDestination::WrapMessageForRouter (std::shared_ptr router, std::shared_ptr msg) { - if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) + if (router->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) { auto session = std::make_shared(this, false); session->SetRemoteStaticKey (router->GetIdentity ()->GetEncryptionPublicKey ()); @@ -728,8 +728,8 @@ namespace garlic std::shared_ptr GarlicDestination::GetRoutingSession ( std::shared_ptr destination, bool attachLeaseSet) { - if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && - SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET)) + if (destination->GetEncryptionType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && + SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) { ECIESX25519AEADRatchetSessionPtr session; uint8_t staticKey[32]; @@ -771,6 +771,7 @@ namespace garlic } return session; } + return nullptr; } void GarlicDestination::CleanupExpiredTags () diff --git a/libi2pd/Identity.cpp b/libi2pd/Identity.cpp index 88523492..89f6cda0 100644 --- a/libi2pd/Identity.cpp +++ b/libi2pd/Identity.cpp @@ -48,7 +48,7 @@ namespace data IdentityEx::IdentityEx(const uint8_t * publicKey, const uint8_t * signingKey, SigningKeyType type, CryptoKeyType cryptoType) { - if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) + if (cryptoType == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) { memcpy (m_StandardIdentity.publicKey, publicKey, 32); RAND_bytes (m_StandardIdentity.publicKey + 32, 224); @@ -426,7 +426,7 @@ namespace data case CRYPTO_KEY_TYPE_ELGAMAL: return std::make_shared(key); break; - case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET: + case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: return std::make_shared(key); break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: @@ -662,7 +662,7 @@ namespace data size_t PrivateKeys::GetPrivateKeyLen () const { // private key length always 256, but type 4 - return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) ? 32 : 256; + return (m_Public->GetCryptoKeyType () == CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) ? 32 : 256; } uint8_t * PrivateKeys::GetPadding() @@ -687,6 +687,9 @@ namespace data case CRYPTO_KEY_TYPE_ELGAMAL: return std::make_shared(key); break; + case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: + return std::make_shared(key); + break; case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC: case CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST: return std::make_shared(key); @@ -694,9 +697,6 @@ namespace data case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: return std::make_shared(key); break; - case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET: - return std::make_shared(key); - break; default: LogPrint (eLogError, "Identity: Unknown crypto key type ", (int)cryptoType); }; @@ -776,7 +776,7 @@ namespace data case CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC: i2p::crypto::CreateECIESGOSTR3410RandomKeys (priv, pub); break; - case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET: + case CRYPTO_KEY_TYPE_ECIES_X25519_AEAD: i2p::crypto::CreateECIESX25519AEADRatchetRandomKeys (priv, pub); break; default: diff --git a/libi2pd/Identity.h b/libi2pd/Identity.h index a36e7209..e9cf63ed 100644 --- a/libi2pd/Identity.h +++ b/libi2pd/Identity.h @@ -64,7 +64,7 @@ namespace data const uint16_t CRYPTO_KEY_TYPE_ELGAMAL = 0; const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC = 1; - const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET = 4; + const uint16_t CRYPTO_KEY_TYPE_ECIES_X25519_AEAD = 4; const uint16_t CRYPTO_KEY_TYPE_ECIES_P256_SHA256_AES256CBC_TEST = 65280; // TODO: remove later const uint16_t CRYPTO_KEY_TYPE_ECIES_GOSTR3410_CRYPTO_PRO_A_SHA256_AES256CBC = 65281; // TODO: use GOST R 34.11 instead SHA256 and GOST 28147-89 instead AES diff --git a/libi2pd/RouterContext.h b/libi2pd/RouterContext.h index 139cc35e..8c13b842 100644 --- a/libi2pd/RouterContext.h +++ b/libi2pd/RouterContext.h @@ -109,7 +109,7 @@ namespace i2p bool SupportsV4 () const { return m_RouterInfo.IsV4 (); }; void SetSupportsV6 (bool supportsV6); void SetSupportsV4 (bool supportsV4); - bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; }; + bool IsECIES () const { return GetIdentity ()->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; }; std::unique_ptr& GetCurrentNoiseState () { return m_CurrentNoiseState; }; void UpdateNTCP2V6Address (const boost::asio::ip::address& host); // called from Daemon. TODO: remove diff --git a/libi2pd/TunnelConfig.h b/libi2pd/TunnelConfig.h index 518c1aad..9aed0d25 100644 --- a/libi2pd/TunnelConfig.h +++ b/libi2pd/TunnelConfig.h @@ -39,7 +39,7 @@ namespace tunnel void SetNext (TunnelHopConfig * n); void SetPrev (TunnelHopConfig * p); - bool IsECIES () const { return ident->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET; }; + bool IsECIES () const { return ident->GetCryptoKeyType () == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD; }; void CreateBuildRequestRecord (uint8_t * record, uint32_t replyMsgID, BN_CTX * ctx); void EncryptECIES (std::shared_ptr& encryptor, const uint8_t * clearText, uint8_t * encrypted, BN_CTX * ctx); diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index d5436936..2b9df0fa 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -46,7 +46,7 @@ namespace client bool I2CPDestination::Decrypt (const uint8_t * encrypted, uint8_t * data, BN_CTX * ctx, i2p::data::CryptoKeyType preferredCrypto) const { - if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && m_ECIESx25519Decryptor) + if (preferredCrypto == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor) return m_ECIESx25519Decryptor->Decrypt (encrypted, data, ctx, true); if (m_Decryptor) return m_Decryptor->Decrypt (encrypted, data, ctx, true); @@ -57,14 +57,14 @@ namespace client const uint8_t * I2CPDestination::GetEncryptionPublicKey (i2p::data::CryptoKeyType keyType) const { - if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET && m_ECIESx25519Decryptor) + if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_ECIESx25519Decryptor) return m_ECIESx25519Decryptor->GetPubicKey (); return nullptr; } bool I2CPDestination::SupportsEncryptionType (i2p::data::CryptoKeyType keyType) const { - return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType; + return keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? (bool)m_ECIESx25519Decryptor : m_EncryptionKeyType == keyType; } @@ -621,7 +621,7 @@ namespace client uint16_t keyType = bufbe16toh (buf + offset); offset += 2; // encryption type uint16_t keyLen = bufbe16toh (buf + offset); offset += 2; // private key length if (offset + keyLen > len) return; - if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD_RATCHET) + if (keyType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) m_Destination->SetECIESx25519EncryptionPrivateKey (buf + offset); else { From 1f6be38145911ef72901eb7bdc4cee881bd33ea1 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Nov 2020 13:06:02 -0500 Subject: [PATCH 44/75] wait for publish confirmation or publish to another floodfill --- libi2pd/NetDb.cpp | 45 ++++++++++++++++++++++++++++----------- libi2pd/NetDb.hpp | 9 +++++++- libi2pd/RouterContext.cpp | 9 ++++++-- 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 318db953..0768b838 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -111,6 +111,9 @@ namespace data case eI2NPDatabaseLookup: HandleDatabaseLookupMsg (msg); break; + case eI2NPDeliveryStatus: + HandleDeliveryStatusMsg (msg); + break; case eI2NPDummyMsg: // plain RouterInfo from NTCP2 with flags for now HandleNTCP2RouterInfoMsg (msg); @@ -148,10 +151,12 @@ namespace data lastDestinationCleanup = ts; } - if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL) // update timestamp and publish + if (!m_HiddenMode && i2p::transport::transports.IsOnline () && + ((m_PublishReplyToken && ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) || + ts - lastPublish >= NETDB_PUBLISH_INTERVAL)) // update timestamp and publish { i2p::context.UpdateTimestamp (ts); - if (!m_HiddenMode) Publish (); + Publish (); lastPublish = ts; } if (ts - lastExploratory >= 30) // exploratory every 30 seconds @@ -992,6 +997,16 @@ namespace data } } + void NetDb::HandleDeliveryStatusMsg (std::shared_ptr msg) + { + if (m_PublishReplyToken == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) + { + LogPrint (eLogInfo, "NetDb: Publishing confirmed. reply token=", m_PublishReplyToken); + m_PublishExcluded.clear (); + m_PublishReplyToken = 0; + } + } + void NetDb::Explore (int numDestinations) { // new requests @@ -1045,18 +1060,22 @@ namespace data void NetDb::Publish () { i2p::context.UpdateStats (); // for floodfill - std::set excluded; // TODO: fill up later - for (int i = 0; i < 2; i++) + + if (m_PublishExcluded.size () > NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS) { - auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded); - if (floodfill) - { - uint32_t replyToken; - RAND_bytes ((uint8_t *)&replyToken, 4); - LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken); - transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); - excluded.insert (floodfill->GetIdentHash ()); - } + LogPrint (eLogError, "NetDb: Couldn't publish our RouterInfo to ", NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS, " closest routers. Try again"); + m_PublishExcluded.clear (); + } + + auto floodfill = GetClosestFloodfill (i2p::context.GetIdentHash (), m_PublishExcluded); + if (floodfill) + { + uint32_t replyToken; + RAND_bytes ((uint8_t *)&replyToken, 4); + LogPrint (eLogInfo, "NetDb: Publishing our RouterInfo to ", i2p::data::GetIdentHashAbbreviation(floodfill->GetIdentHash ()), ". reply token=", replyToken); + m_PublishExcluded.insert (floodfill->GetIdentHash ()); + m_PublishReplyToken = replyToken; + transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg (i2p::context.GetSharedRouterInfo (), replyToken)); } } diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index f9a57ccd..afd1f562 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -41,6 +41,8 @@ namespace data const int NETDB_MIN_EXPIRATION_TIMEOUT = 90 * 60; // 1.5 hours const int NETDB_MAX_EXPIRATION_TIMEOUT = 27 * 60 * 60; // 27 hours const int NETDB_PUBLISH_INTERVAL = 60 * 40; + const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds + const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36 /** function for visiting a leaseset stored in a floodfill */ @@ -77,6 +79,7 @@ namespace data void HandleDatabaseSearchReplyMsg (std::shared_ptr msg); void HandleDatabaseLookupMsg (std::shared_ptr msg); void HandleNTCP2RouterInfoMsg (std::shared_ptr m); + void HandleDeliveryStatusMsg (std::shared_ptr msg); std::shared_ptr GetRandomRouter () const; std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith) const; @@ -115,6 +118,8 @@ namespace data void ClearRouterInfos () { m_RouterInfos.clear (); }; + uint32_t GetPublishReplyToken () const { return m_PublishReplyToken; }; + private: void Load (); @@ -162,9 +167,11 @@ namespace data /** router info we are bootstrapping from or nullptr if we are not currently doing that*/ std::shared_ptr m_FloodfillBootstrap; - /** true if in hidden mode */ bool m_HiddenMode; + + std::set m_PublishExcluded; + uint32_t m_PublishReplyToken = 0; }; extern NetDb netdb; diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 74f8ad34..375e0b9a 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -670,8 +670,13 @@ namespace i2p void RouterContext::ProcessDeliveryStatusMessage (std::shared_ptr msg) { - std::unique_lock l(m_GarlicMutex); - i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); + if (i2p::data::netdb.GetPublishReplyToken () == bufbe32toh (msg->GetPayload () + DELIVERY_STATUS_MSGID_OFFSET)) + i2p::data::netdb.PostI2NPMsg (msg); + else + { + std::unique_lock l(m_GarlicMutex); + i2p::garlic::GarlicDestination::ProcessDeliveryStatusMessage (msg); + } } void RouterContext::CleanupDestination () From af20b13c7a54a852a16024111714d17585aecdee Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Nov 2020 17:02:01 -0500 Subject: [PATCH 45/75] create paired inbound tunnels if no inbound tunnels yet --- libi2pd/TunnelPool.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index d0fd401f..909248ba 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -118,7 +118,6 @@ namespace tunnel std::unique_lock l(m_OutboundTunnelsMutex); m_OutboundTunnels.insert (createdTunnel); } - //CreatePairedInboundTunnel (createdTunnel); } void TunnelPool::TunnelExpired (std::shared_ptr expiredTunnel) @@ -235,6 +234,15 @@ namespace tunnel for (const auto& it : m_InboundTunnels) if (it->IsEstablished ()) num++; } + if (!num && !m_OutboundTunnels.empty ()) + { + for (auto it: m_OutboundTunnels) + { + CreatePairedInboundTunnel (it); + num++; + if (num >= m_NumInboundTunnels) break; + } + } for (int i = num; i < m_NumInboundTunnels; i++) CreateInboundTunnel (); From 44ca315c7559f44190853b9aa3da88979e89fe2b Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Nov 2020 19:38:34 -0500 Subject: [PATCH 46/75] don't build tunnels for all pools at the time --- libi2pd/Tunnel.cpp | 28 ++++++++++++++++------------ libi2pd/Tunnel.h | 4 ++-- libi2pd/TunnelPool.cpp | 15 +++++++++++++-- libi2pd/TunnelPool.h | 4 ++++ 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/libi2pd/Tunnel.cpp b/libi2pd/Tunnel.cpp index a74c8c91..ad918787 100644 --- a/libi2pd/Tunnel.cpp +++ b/libi2pd/Tunnel.cpp @@ -474,7 +474,7 @@ namespace tunnel { std::this_thread::sleep_for (std::chrono::seconds(1)); // wait for other parts are ready - uint64_t lastTs = 0; + uint64_t lastTs = 0, lastPoolsTs = 0; while (m_IsRunning) { try @@ -535,12 +535,20 @@ namespace tunnel while (msg); } - uint64_t ts = i2p::util::GetSecondsSinceEpoch (); - if (ts - lastTs >= 15 && i2p::transport::transports.IsOnline()) // manage tunnels every 15 seconds + if (i2p::transport::transports.IsOnline()) { - ManageTunnels (); - lastTs = ts; - } + uint64_t ts = i2p::util::GetSecondsSinceEpoch (); + if (ts - lastTs >= 15) // manage tunnels every 15 seconds + { + ManageTunnels (); + lastTs = ts; + } + if (ts - lastPoolsTs >= 5) // manage pools every 5 seconds + { + ManageTunnelPools (ts); + lastPoolsTs = ts; + } + } } catch (std::exception& ex) { @@ -582,7 +590,6 @@ namespace tunnel ManageInboundTunnels (); ManageOutboundTunnels (); ManageTransitTunnels (); - ManageTunnelPools (); } void Tunnels::ManagePendingTunnels () @@ -794,16 +801,13 @@ namespace tunnel } } - void Tunnels::ManageTunnelPools () + void Tunnels::ManageTunnelPools (uint64_t ts) { std::unique_lock l(m_PoolsMutex); for (auto& pool : m_Pools) { if (pool && pool->IsActive ()) - { - pool->CreateTunnels (); - pool->TestTunnels (); - } + pool->ManageTunnels (ts); } } diff --git a/libi2pd/Tunnel.h b/libi2pd/Tunnel.h index a50bc31a..37c5cddb 100644 --- a/libi2pd/Tunnel.h +++ b/libi2pd/Tunnel.h @@ -230,7 +230,7 @@ namespace tunnel void ManagePendingTunnels (); template void ManagePendingTunnels (PendingTunnels& pendingTunnels); - void ManageTunnelPools (); + void ManageTunnelPools (uint64_t ts); std::shared_ptr CreateZeroHopsInboundTunnel (); std::shared_ptr CreateZeroHopsOutboundTunnel (); @@ -249,7 +249,7 @@ namespace tunnel std::list> m_Pools; std::shared_ptr m_ExploratoryPool; i2p::util::Queue > m_Queue; - + // some stats int m_NumSuccesiveTunnelCreations, m_NumFailedTunnelCreations; diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index 909248ba..a44fc33d 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -26,9 +26,10 @@ namespace tunnel { TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, int numOutboundTunnels): m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), - m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), m_IsActive (true), - m_CustomPeerSelector(nullptr) + m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), + m_IsActive (true), m_CustomPeerSelector(nullptr) { + m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + rand () % TUNNEL_POOL_MANAGE_INTERVAL; } TunnelPool::~TunnelPool () @@ -321,6 +322,16 @@ namespace tunnel } } + void TunnelPool::ManageTunnels (uint64_t ts) + { + if (ts > m_NextManageTime) + { + CreateTunnels (); + TestTunnels (); + m_NextManageTime = ts + TUNNEL_POOL_MANAGE_INTERVAL + (rand () % TUNNEL_POOL_MANAGE_INTERVAL)/2; + } + } + void TunnelPool::ProcessGarlicMessage (std::shared_ptr msg) { if (m_LocalDestination) diff --git a/libi2pd/TunnelPool.h b/libi2pd/TunnelPool.h index 04ff4ae7..d1024d04 100644 --- a/libi2pd/TunnelPool.h +++ b/libi2pd/TunnelPool.h @@ -27,6 +27,8 @@ namespace i2p { namespace tunnel { + const int TUNNEL_POOL_MANAGE_INTERVAL = 10; // in seconds + class Tunnel; class InboundTunnel; class OutboundTunnel; @@ -69,6 +71,7 @@ namespace tunnel std::shared_ptr GetNextInboundTunnel (std::shared_ptr excluded = nullptr) const; std::shared_ptr GetNewOutboundTunnel (std::shared_ptr old) const; void TestTunnels (); + void ManageTunnels (uint64_t ts); void ProcessGarlicMessage (std::shared_ptr msg); void ProcessDeliveryStatus (std::shared_ptr msg); @@ -123,6 +126,7 @@ namespace tunnel mutable std::mutex m_TestsMutex; std::map, std::shared_ptr > > m_Tests; bool m_IsActive; + uint64_t m_NextManageTime; // in seconds std::mutex m_CustomPeerSelectorMutex; ITunnelPeerSelector * m_CustomPeerSelector; From 1ae98b7fe1604a7b8ba6023fb48ff5da049fb258 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 16 Nov 2020 03:38:04 +0300 Subject: [PATCH 47/75] [webconsole] graceful timer for windows --- Win32/Win32App.cpp | 15 ++++++--------- Win32/Win32App.h | 2 ++ daemon/HTTPServer.cpp | 13 +++++++++++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Win32/Win32App.cpp b/Win32/Win32App.cpp index df345b11..1785ffd6 100644 --- a/Win32/Win32App.cpp +++ b/Win32/Win32App.cpp @@ -43,10 +43,7 @@ namespace i2p { namespace win32 { - static DWORD GracefulShutdownEndtime = 0; - - typedef DWORD (* IPN)(); - IPN GetTickCountLocal = (IPN)GetProcAddress (GetModuleHandle ("KERNEL32.dll"), "GetTickCount"); + DWORD g_GracefulShutdownEndtime = 0; static void ShowPopupMenu (HWND hWnd, POINT *curpos, int wDefaultItem) { @@ -167,9 +164,9 @@ namespace win32 s << "; "; s << "Success Rate: " << i2p::tunnel::tunnels.GetTunnelCreationSuccessRate() << "%\n"; s << "Uptime: "; ShowUptime(s, i2p::context.GetUptime ()); - if (GracefulShutdownEndtime != 0) + if (g_GracefulShutdownEndtime != 0) { - DWORD GracefulTimeLeft = (GracefulShutdownEndtime - GetTickCountLocal()) / 1000; + DWORD GracefulTimeLeft = (g_GracefulShutdownEndtime - GetTickCount()) / 1000; s << "Graceful shutdown, time left: "; ShowUptime(s, GracefulTimeLeft); } else @@ -247,7 +244,7 @@ namespace win32 i2p::context.SetAcceptsTunnels (false); SetTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER, 10*60*1000, nullptr); // 10 minutes SetTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER, 1000, nullptr); // check tunnels every second - GracefulShutdownEndtime = GetTickCountLocal() + 10*60*1000; + g_GracefulShutdownEndtime = GetTickCount() + 10*60*1000; i2p::util::DaemonWin32::Instance ().isGraceful = true; return 0; } @@ -256,7 +253,7 @@ namespace win32 i2p::context.SetAcceptsTunnels (true); KillTimer (hWnd, IDT_GRACEFUL_SHUTDOWN_TIMER); KillTimer (hWnd, IDT_GRACEFUL_TUNNELCHECK_TIMER); - GracefulShutdownEndtime = 0; + g_GracefulShutdownEndtime = 0; i2p::util::DaemonWin32::Instance ().isGraceful = false; return 0; } @@ -343,7 +340,7 @@ namespace win32 { case IDT_GRACEFUL_SHUTDOWN_TIMER: { - GracefulShutdownEndtime = 0; + g_GracefulShutdownEndtime = 0; PostMessage (hWnd, WM_CLOSE, 0, 0); // exit return 0; } diff --git a/Win32/Win32App.h b/Win32/Win32App.h index d242f7d3..ebe49efd 100644 --- a/Win32/Win32App.h +++ b/Win32/Win32App.h @@ -15,6 +15,8 @@ namespace i2p { namespace win32 { + extern DWORD g_GracefulShutdownEndtime; + bool StartWin32App (); void StopWin32App (); int RunWin32App (); diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 59c530f9..ad549a00 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -270,8 +270,17 @@ namespace http { } s << "
\r\n"; #if ((!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) || defined(ANDROID_BINARY)) - if (auto remains = Daemon.gracefulShutdownInterval) - s << "Stopping in: " << remains << " seconds
\r\n"; + if (auto remains = Daemon.gracefulShutdownInterval) { + s << "Stopping in: "; + ShowUptime(s, remains); + s << "
\r\n"; +#elif defined(WIN32_APP) + if (i2p::win32::g_GracefulShutdownEndtime != 0) { + uint16_t remains = (i2p::win32::g_GracefulShutdownEndtime - GetTickCount()) / 1000; + s << "Stopping in: "; + ShowUptime(s, remains); + s << "
\r\n"; + } #endif auto family = i2p::context.GetFamily (); if (family.length () > 0) From 2bd6daeb8de30d6445961ba02f2975acc678bc61 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 16 Nov 2020 03:38:52 +0300 Subject: [PATCH 48/75] disable aes/avx for winxp by default --- libi2pd/CPU.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libi2pd/CPU.cpp b/libi2pd/CPU.cpp index 0bd830e3..0804e2ac 100644 --- a/libi2pd/CPU.cpp +++ b/libi2pd/CPU.cpp @@ -34,10 +34,18 @@ namespace cpu __cpuid(0, info[0], info[1], info[2], info[3]); if (info[0] >= 0x00000001) { __cpuid(0x00000001, info[0], info[1], info[2], info[3]); +#if defined (_WIN32) && (WINVER == 0x0501) // WinXP + if (AesSwitch && force) { // only if forced +#else if ((info[2] & bit_AES && AesSwitch) || (AesSwitch && force)) { +#endif aesni = true; } +#if defined (_WIN32) && (WINVER == 0x0501) // WinXP + if (AvxSwitch && force) { // only if forced +#else if ((info[2] & bit_AVX && AvxSwitch) || (AvxSwitch && force)) { +#endif avx = true; } } From 4a44b18b97c65211faec7cc6742a4592a5662db8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Nov 2020 19:56:16 -0500 Subject: [PATCH 49/75] fixed typo --- daemon/HTTPServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index ad549a00..3c9ddde6 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -274,6 +274,7 @@ namespace http { s << "Stopping in: "; ShowUptime(s, remains); s << "
\r\n"; + } #elif defined(WIN32_APP) if (i2p::win32::g_GracefulShutdownEndtime != 0) { uint16_t remains = (i2p::win32::g_GracefulShutdownEndtime - GetTickCount()) / 1000; From b4369470cb88c43c87e657537c4e42add3d9fd4a Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Nov 2020 20:05:27 -0500 Subject: [PATCH 50/75] publish updated RouterInfo --- libi2pd/NetDb.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 0768b838..9a90e952 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -153,6 +153,7 @@ namespace data if (!m_HiddenMode && i2p::transport::transports.IsOnline () && ((m_PublishReplyToken && ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) || + i2p::context.GetLastUpdateTime () > lastPublish || ts - lastPublish >= NETDB_PUBLISH_INTERVAL)) // update timestamp and publish { i2p::context.UpdateTimestamp (ts); From c69c4ae8a019d3d220a522797d0987877bd9da9e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 15 Nov 2020 21:46:49 -0500 Subject: [PATCH 51/75] don't publish too fast --- libi2pd/NetDb.cpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 9a90e952..4399fb15 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -151,14 +151,22 @@ namespace data lastDestinationCleanup = ts; } - if (!m_HiddenMode && i2p::transport::transports.IsOnline () && - ((m_PublishReplyToken && ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) || - i2p::context.GetLastUpdateTime () > lastPublish || - ts - lastPublish >= NETDB_PUBLISH_INTERVAL)) // update timestamp and publish + // publish + if (!m_HiddenMode && i2p::transport::transports.IsOnline ()) { - i2p::context.UpdateTimestamp (ts); - Publish (); - lastPublish = ts; + bool publish = false; + if (m_PublishReplyToken) + { + if (ts - lastPublish >= NETDB_PUBLISH_CONFIRMATION_TIMEOUT) publish = true; + } + else if (i2p::context.GetLastUpdateTime () > lastPublish || + ts - lastPublish >= NETDB_PUBLISH_INTERVAL) publish = true; + if (publish) // update timestamp and publish + { + i2p::context.UpdateTimestamp (ts); + Publish (); + lastPublish = ts; + } } if (ts - lastExploratory >= 30) // exploratory every 30 seconds { From 3b630fe546d76e2c19e7540d3406888c7413e15b Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 16 Nov 2020 10:04:38 -0500 Subject: [PATCH 52/75] fixed race condition --- libi2pd/TunnelPool.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index a44fc33d..a898d69e 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -292,6 +292,8 @@ namespace tunnel } // new tests + std::unique_lock l1(m_OutboundTunnelsMutex); + std::unique_lock l2(m_InboundTunnelsMutex); auto it1 = m_OutboundTunnels.begin (); auto it2 = m_InboundTunnels.begin (); while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) From 3925540517d31d62d1ad89158e2a075c9d539463 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 16 Nov 2020 12:56:22 -0500 Subject: [PATCH 53/75] don't update expired tunnels --- libi2pd/TunnelPool.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/libi2pd/TunnelPool.cpp b/libi2pd/TunnelPool.cpp index a898d69e..87413c3f 100644 --- a/libi2pd/TunnelPool.cpp +++ b/libi2pd/TunnelPool.cpp @@ -292,8 +292,6 @@ namespace tunnel } // new tests - std::unique_lock l1(m_OutboundTunnelsMutex); - std::unique_lock l2(m_InboundTunnelsMutex); auto it1 = m_OutboundTunnels.begin (); auto it2 = m_InboundTunnels.begin (); while (it1 != m_OutboundTunnels.end () && it2 != m_InboundTunnels.end ()) @@ -363,17 +361,24 @@ namespace tunnel } if (found) { - // restore from test failed state if any - if (test.first->GetState () == eTunnelStateTestFailed) - test.first->SetState (eTunnelStateEstablished); - if (test.second->GetState () == eTunnelStateTestFailed) - test.second->SetState (eTunnelStateEstablished); uint64_t dlt = i2p::util::GetMillisecondsSinceEpoch () - timestamp; LogPrint (eLogDebug, "Tunnels: test of ", msgID, " successful. ", dlt, " milliseconds"); - // update latency uint64_t latency = dlt / 2; - test.first->AddLatencySample(latency); - test.second->AddLatencySample(latency); + // restore from test failed state if any + if (test.first) + { + if (test.first->GetState () == eTunnelStateTestFailed) + test.first->SetState (eTunnelStateEstablished); + // update latency + test.first->AddLatencySample(latency); + } + if (test.second) + { + if (test.second->GetState () == eTunnelStateTestFailed) + test.second->SetState (eTunnelStateEstablished); + // update latency + test.second->AddLatencySample(latency); + } } else { From 0a3af12ee984c0964994dbacd9fd170c08f3c75e Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 17 Nov 2020 17:59:40 +0300 Subject: [PATCH 54/75] [make] track changes in includes Signed-off-by: R4SAS --- Makefile | 26 +++++++++++++------------- Makefile.mingw | 4 ++-- Win32/DaemonWin32.cpp | 4 ++-- build/build_mingw.cmd | 14 +++++++------- build/win_installer.iss | 3 ++- daemon/HTTPServer.cpp | 5 +++-- 6 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Makefile b/Makefile index c359d7c7..7bb3ceda 100644 --- a/Makefile +++ b/Makefile @@ -4,13 +4,12 @@ ARLIB := libi2pd.a SHLIB_CLIENT := libi2pdclient.so ARLIB_CLIENT := libi2pdclient.a I2PD := i2pd -GREP := grep -DEPS := obj/make.dep LIB_SRC_DIR := libi2pd LIB_CLIENT_SRC_DIR := libi2pd_client DAEMON_SRC_DIR := daemon +# import source files lists include filelist.mk USE_AESNI := yes @@ -50,7 +49,12 @@ ifeq ($(USE_MESHNET),yes) NEEDED_CXXFLAGS += -DMESHNET endif -NEEDED_CXXFLAGS += -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) +NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) + +LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) +LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) +DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) +DEPS := $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d) all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD) @@ -71,32 +75,29 @@ api_client: mk_obj_dir $(SHLIB) $(ARLIB) $(SHLIB_CLIENT) $(ARLIB_CLIENT) ## -std=c++11. If you want to remove this variable please do so in a way that allows setting ## custom FLAGS to work at build-time. -deps: mk_obj_dir - $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) -MM *.cpp > $(DEPS) - @sed -i -e '/\.o:/ s/^/obj\//' $(DEPS) - obj/%.o: %.cpp $(CXX) $(CXXFLAGS) $(NEEDED_CXXFLAGS) $(INCFLAGS) -c -o $@ $< # '-' is 'ignore if missing' on first run -include $(DEPS) -DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) $(CXX) -o $@ $^ $(LDFLAGS) $(LDLIBS) -$(SHLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) +$(SHLIB): $(LIB_OBJS) ifneq ($(USE_STATIC),yes) $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) endif -$(SHLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) +$(SHLIB_CLIENT): $(LIB_CLIENT_OBJS) +ifneq ($(USE_STATIC),yes) $(CXX) $(LDFLAGS) -shared -o $@ $^ $(LDLIBS) $(SHLIB) +endif -$(ARLIB): $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) +$(ARLIB): $(LIB_OBJS) $(AR) -r $@ $^ -$(ARLIB_CLIENT): $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) +$(ARLIB_CLIENT): $(LIB_CLIENT_OBJS) $(AR) -r $@ $^ clean: @@ -122,7 +123,6 @@ doxygen: .PHONY: all .PHONY: clean -.PHONY: deps .PHONY: doxygen .PHONY: dist .PHONY: last-dist diff --git a/Makefile.mingw b/Makefile.mingw index 764606b6..4cd2c292 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,8 +1,8 @@ USE_WIN32_APP=yes CXX = g++ WINDRES = windres -CXXFLAGS := ${CXX_DEBUG} -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -fPIC -msse -INCFLAGS = -Idaemon -I. +CXXFLAGS := $(CXX_DEBUG) -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -fPIC -msse +INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32 LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ # detect proper flag for c++11 support by compilers diff --git a/Win32/DaemonWin32.cpp b/Win32/DaemonWin32.cpp index 1214ff68..30f4f92e 100644 --- a/Win32/DaemonWin32.cpp +++ b/Win32/DaemonWin32.cpp @@ -14,10 +14,10 @@ #include "Log.h" #ifdef _WIN32 -#include "Win32/Win32Service.h" +#include "Win32Service.h" #ifdef WIN32_APP #include -#include "Win32/Win32App.h" +#include "Win32App.h" #endif namespace i2p diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index 37a1d454..e791039e 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -23,8 +23,8 @@ 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. -set /a threads=%NUMBER_OF_PROCESSORS%-1 +REM detecting number of processors +set /a threads=%NUMBER_OF_PROCESSORS% REM we must work in root of repo cd .. @@ -33,7 +33,7 @@ REM deleting old log files del /S build_*.log >> nul 2>&1 echo Receiving latest commit and cleaning up... -%xSH% "git checkout contrib/* && git pull && make clean" > build/build.log 2>&1 +%xSH% "git checkout contrib/* && git pull && make clean" > build\build.log 2>&1 echo. REM set to variable current commit hash @@ -44,7 +44,7 @@ FOR /F "usebackq" %%a IN (`%xSH% 'git describe --tags'`) DO ( %xSH% "echo To use configs and certificates, move all files and certificates folder from contrib directory here. > README.txt" >> nul REM converting configuration files to DOS format (usable in default notepad) -%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/*" > build/build.log 2>&1 +%xSH% "unix2dos contrib/i2pd.conf contrib/tunnels.conf contrib/tunnels.d/*" >> build\build.log 2>&1 REM starting building set MSYSTEM=MINGW32 @@ -64,7 +64,7 @@ call :BUILDING_XP echo. REM compile installer -C:\PROGRA~2\INNOSE~1\ISCC.exe build\win_installer.iss +C:\PROGRA~2\INNOSE~1\ISCC.exe /dI2Pd_ver="%tag%" build\win_installer.iss >> build\build.log 2>&1 del README.txt i2pd_x32.exe i2pd_x64.exe i2pd_xp.exe >> nul @@ -75,12 +75,12 @@ exit /b 0 :BUILDING %xSH% "make clean" >> nul echo Building i2pd %tag% for win%bitness% -%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build/build_win%bitness%_%tag%.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes -j%threads% && cp i2pd.exe i2pd_x%bitness%.exe && zip -r9 build/i2pd_%tag%_win%bitness%_mingw.zip %FILELIST% && make clean" > build\build_win%bitness%_%tag%.log 2>&1 goto EOF :BUILDING_XP %xSH% "make clean" >> nul echo Building i2pd %tag% for winxp -%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build/build_winxp_%tag%.log 2>&1 +%xSH% "make DEBUG=no USE_UPNP=yes USE_WINXP_FLAGS=yes -j%threads% && cp i2pd.exe i2pd_xp.exe && zip -r9 build/i2pd_%tag%_winxp_mingw.zip %FILELIST% && make clean" > build\build_winxp_%tag%.log 2>&1 :EOF \ No newline at end of file diff --git a/build/win_installer.iss b/build/win_installer.iss index 007cd643..8a93a2c7 100644 --- a/build/win_installer.iss +++ b/build/win_installer.iss @@ -1,7 +1,8 @@ #define I2Pd_AppName "i2pd" #define I2Pd_Publisher "PurpleI2P" ; Get application version from compiled binary -#define I2Pd_ver GetFileVersionString(AddBackslash(SourcePath) + "..\i2pd_x64.exe") +; Disabled to use definition from command line +;#define I2Pd_ver GetFileVersionString(AddBackslash(SourcePath) + "..\i2pd_x64.exe") [Setup] AppName={#I2Pd_AppName} diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index 3c9ddde6..ecc5acdd 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -30,8 +30,9 @@ #include "Daemon.h" #include "util.h" #include "ECIESX25519AEADRatchetSession.h" + #ifdef WIN32_APP -#include "Win32/Win32App.h" +#include "Win32App.h" #endif // For image and info @@ -274,7 +275,7 @@ namespace http { s << "Stopping in: "; ShowUptime(s, remains); s << "
\r\n"; - } + } #elif defined(WIN32_APP) if (i2p::win32::g_GracefulShutdownEndtime != 0) { uint16_t remains = (i2p::win32::g_GracefulShutdownEndtime - GetTickCount()) / 1000; From 85d796f906b8e02f1fcc073624203caaca1ae3d0 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Tue, 17 Nov 2020 21:39:46 +0300 Subject: [PATCH 55/75] [actions] obj directories before make on windows --- .github/workflows/build-windows.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 9763f75b..c979e43f 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -26,4 +26,6 @@ jobs: install: base-devel mingw-w64-${{ matrix.arch }}-gcc mingw-w64-${{ matrix.arch }}-boost mingw-w64-${{ matrix.arch }}-openssl mingw-w64-${{ matrix.arch }}-miniupnpc update: true - name: build application - run: make USE_UPNP=yes DEBUG=no -j3 + run: | + mkdir -p obj/Win32 obj/libi2pd obj/libi2pd_client obj/daemon + make USE_UPNP=yes DEBUG=no -j3 From feaecbe177700d86ed0eb5729190a59173093bda Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Nov 2020 15:02:06 -0500 Subject: [PATCH 56/75] own local destination for each 'transient' --- libi2pd_client/ClientContext.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/ClientContext.cpp b/libi2pd_client/ClientContext.cpp index ab868916..860e8cfd 100644 --- a/libi2pd_client/ClientContext.cpp +++ b/libi2pd_client/ClientContext.cpp @@ -590,7 +590,8 @@ namespace client localDestination = CreateNewMatchedTunnelDestination(k, dest, &options); else localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options); - destinations[keys] = localDestination; + if (keys != "transient") + destinations[keys] = localDestination; } } } From d8381e94866f138160b19d58f01880040ec8fb12 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 18 Nov 2020 18:11:29 -0500 Subject: [PATCH 57/75] disable encryption to ECIES routers --- libi2pd/Destination.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libi2pd/Destination.cpp b/libi2pd/Destination.cpp index d51fc63d..44180ae5 100644 --- a/libi2pd/Destination.cpp +++ b/libi2pd/Destination.cpp @@ -559,7 +559,9 @@ namespace client m_ExcludedFloodfills.insert (floodfill->GetIdentHash ()); LogPrint (eLogDebug, "Destination: Publish LeaseSet of ", GetIdentHash ().ToBase32 ()); RAND_bytes ((uint8_t *)&m_PublishReplyToken, 4); - auto msg = WrapMessageForRouter (floodfill, i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound)); + auto msg = i2p::CreateDatabaseStoreMsg (leaseSet, m_PublishReplyToken, inbound); + if (floodfill->GetIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // TODO: remove whan implemented + msg = WrapMessageForRouter (floodfill, msg); m_PublishConfirmationTimer.expires_from_now (boost::posix_time::seconds(PUBLISH_CONFIRMATION_TIMEOUT)); m_PublishConfirmationTimer.async_wait (std::bind (&LeaseSetDestination::HandlePublishConfirmationTimer, shared_from_this (), std::placeholders::_1)); @@ -754,8 +756,9 @@ namespace client else AddSessionKey (replyKey, replyTag); - auto msg = WrapMessageForRouter (nextFloodfill, CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, - request->replyTunnel, replyKey, replyTag, isECIES)); + auto msg = CreateLeaseSetDatabaseLookupMsg (dest, request->excluded, request->replyTunnel, replyKey, replyTag, isECIES); + if (nextFloodfill->GetIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) // TODO: remove whan implemented + msg = WrapMessageForRouter (nextFloodfill, msg); request->outboundTunnel->SendTunnelDataMsg ( { i2p::tunnel::TunnelMessageBlock From 30d6bd144bf4d90d7d38ea43545cbce674e34237 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 19 Nov 2020 15:41:00 -0500 Subject: [PATCH 58/75] don't replace an adddress by one with DSA signature --- libi2pd_client/AddressBook.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libi2pd_client/AddressBook.cpp b/libi2pd_client/AddressBook.cpp index 5c1cffbb..d695b8eb 100644 --- a/libi2pd_client/AddressBook.cpp +++ b/libi2pd_client/AddressBook.cpp @@ -454,17 +454,18 @@ namespace client auto it = m_Addresses.find (name); if (it != m_Addresses.end ()) // already exists ? { - if (it->second->IsIdentHash () && it->second->identHash != ident->GetIdentHash ()) // address changed? + if (it->second->IsIdentHash () && it->second->identHash != ident->GetIdentHash () && // address changed? + ident->GetSigningKeyType () != i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) // don't replace by DSA { it->second->identHash = ident->GetIdentHash (); m_Storage->AddAddress (ident); + m_Storage->RemoveAddress (it->second->identHash); LogPrint (eLogInfo, "Addressbook: updated host: ", name); } } else { - //m_Addresses.emplace (name, std::make_shared
(ident->GetIdentHash ())); - m_Addresses[name] = std::make_shared
(ident->GetIdentHash ()); // for gcc 4.7 + m_Addresses.emplace (name, std::make_shared
(ident->GetIdentHash ())); m_Storage->AddAddress (ident); if (is_update) LogPrint (eLogInfo, "Addressbook: added new host: ", name); From 0436a65baa95ef1eae32e9d06c65669687a3b2f5 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 20 Nov 2020 20:31:50 -0500 Subject: [PATCH 59/75] upddate DSA router keys --- libi2pd/RouterContext.cpp | 53 +++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 375e0b9a..220fbc4f 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -564,31 +564,42 @@ namespace i2p bool RouterContext::Load () { - std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary); - if (!fk.is_open ()) return false; - fk.seekg (0, std::ios::end); - size_t len = fk.tellg(); - fk.seekg (0, std::ios::beg); + { + std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary); + if (!fk.is_open ()) return false; + fk.seekg (0, std::ios::end); + size_t len = fk.tellg(); + fk.seekg (0, std::ios::beg); - if (len == sizeof (i2p::data::Keys)) // old keys file format - { - i2p::data::Keys keys; - fk.read ((char *)&keys, sizeof (keys)); - m_Keys = keys; + if (len == sizeof (i2p::data::Keys)) // old keys file format + { + i2p::data::Keys keys; + fk.read ((char *)&keys, sizeof (keys)); + m_Keys = keys; + } + else // new keys file format + { + uint8_t * buf = new uint8_t[len]; + fk.read ((char *)buf, len); + m_Keys.FromBuffer (buf, len); + delete[] buf; + } } - else // new keys file format + std::shared_ptr oldIdentity; + if (m_Keys.GetPublic ()->GetSigningKeyType () == i2p::data::SIGNING_KEY_TYPE_DSA_SHA1) { - uint8_t * buf = new uint8_t[len]; - fk.read ((char *)buf, len); - m_Keys.FromBuffer (buf, len); - delete[] buf; - } + // update keys + LogPrint (eLogInfo, "Router: router keys are obsolete. Creating new"); + oldIdentity = m_Keys.GetPublic (); + m_Keys = i2p::data::PrivateKeys::CreateRandomKeys (i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); + SaveKeys (); + } // read NTCP2 keys if available std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary); if (n2k) { n2k.seekg (0, std::ios::end); - len = n2k.tellg(); + size_t len = n2k.tellg(); n2k.seekg (0, std::ios::beg); if (len == sizeof (NTCP2PrivateKeys)) { @@ -598,17 +609,15 @@ namespace i2p n2k.close (); } // read RouterInfo - m_RouterInfo.SetRouterIdentity (GetIdentity ()); + m_RouterInfo.SetRouterIdentity (oldIdentity ? oldIdentity : GetIdentity ()); i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO)); if (!routerInfo.IsUnreachable ()) // router.info looks good { m_RouterInfo.Update (routerInfo.GetBuffer (), routerInfo.GetBufferLen ()); + if (oldIdentity) + m_RouterInfo.SetRouterIdentity (GetIdentity ()); // from new keys m_RouterInfo.SetProperty ("coreVersion", I2P_VERSION); m_RouterInfo.SetProperty ("router.version", I2P_VERSION); - - // Migration to 0.9.24. TODO: remove later - m_RouterInfo.DeleteProperty ("coreVersion"); - m_RouterInfo.DeleteProperty ("stat_uptime"); } else { From f4486bc075387828c5daec6c3d4b894cbd1458b3 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 20 Nov 2020 21:48:33 -0500 Subject: [PATCH 60/75] take intro key from right address --- libi2pd/SSUSession.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libi2pd/SSUSession.cpp b/libi2pd/SSUSession.cpp index 860c2be3..b4f2fcdb 100644 --- a/libi2pd/SSUSession.cpp +++ b/libi2pd/SSUSession.cpp @@ -30,14 +30,15 @@ namespace transport if (router) { // we are client - auto address = router->GetSSUAddress (false); + auto address = IsV6 () ? router->GetSSUV6Address () : router->GetSSUAddress (true); if (address) m_IntroKey = address->ssu->key; m_Data.AdjustPacketSize (router); // mtu } else { // we are server - auto address = i2p::context.GetRouterInfo ().GetSSUAddress (false); + auto address = IsV6 () ? i2p::context.GetRouterInfo ().GetSSUV6Address () : + i2p::context.GetRouterInfo ().GetSSUAddress (true); if (address) m_IntroKey = address->ssu->key; } m_CreationTime = i2p::util::GetSecondsSinceEpoch (); From 2266c3877c01af077733e54d9ab2cf5df0a42d3a Mon Sep 17 00:00:00 2001 From: R4SAS Date: Sat, 21 Nov 2020 19:45:06 +0300 Subject: [PATCH 61/75] update reseeds Signed-off-by: R4SAS --- .../certificates/reseed/meeh_at_mail.i2p.crt | 32 ------------------- libi2pd/Config.cpp | 5 ++- 2 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 contrib/certificates/reseed/meeh_at_mail.i2p.crt diff --git a/contrib/certificates/reseed/meeh_at_mail.i2p.crt b/contrib/certificates/reseed/meeh_at_mail.i2p.crt deleted file mode 100644 index 6014c96f..00000000 --- a/contrib/certificates/reseed/meeh_at_mail.i2p.crt +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFeTCCA2GgAwIBAgIEZZozujANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY -WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt -b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNbWVlaEBtYWlsLmky -cDAeFw0xNDA2MjgyMjQ5MDlaFw0yNDA2MjcyMjQ5MDlaMG0xCzAJBgNVBAYTAlhY -MQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBBbm9ueW1v -dXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRYwFAYDVQQDDA1tZWVoQG1haWwuaTJw -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnVnmPE4uUvCky0yCnnVH -cJEDqzwDPupx0zr0YDlhZk5VOPPecx5haayJ/V6nXPc1aVVWn+CHfedcF2aBgN4K -5aBueS/l6l5WHcv02DofAqlTmyAws3oQeR1qoTuW24cKRtLR7h5bxv63f6bgp6e+ -RihFNez6UxErnRPuJOJEO2Im6EgVp6fz7tQ7R35zxAUeES2YILPySvzy2vYm/EEG -jXX7Ap2A5svVo90xCMOeUZ/55vLsjyIshN+tV87U4xwvAkUmwsmWVHm3BQpHkI6z -zMJie6epB8Bqm0GYm0EcElJH4OCxGTvDLoghpswbuUO7iy3JSfoL7ZCnoiQdK9K4 -yVVChj8lG+r7KaTowK96iZep+sZefjOt5VFGuW2Fi/WBv3ldiLlJAo/ZfrUM4+vG -fyNBXbl6bX87uTCGOT1p3dazo+zJMsAZ+Y93DlM/mDEWFa1kKNrs74syzaWEqF4L -KQE6VoYn80OOzafSigTVQgSwUtQtB0XGhMzJhyxU2XHWe1LFIy7Pta0B+lDiZj7c -I8nXxYjsDfEu/Elj/Ra9N6bH0awmgB5JDa+Tbir+oEM5SyDfpSaCGuatdGxjweGI -kVmFU0SqCZV/8TXbIu6MUVzTZMZVT94edifFSRad4fqw7eZbSXlPu++3d1/btn6h -ibM04nkv0mm+FxCKB/wdAkECAwEAAaMhMB8wHQYDVR0OBBYEFO7jIkSRkoXyJcho -9/Q0gDOINa5EMA0GCSqGSIb3DQEBDQUAA4ICAQBzfWO7+8HWOKLaYWToJ6XZbpNF -3wXv1yC4W/HRR80m4JSsq9r0d7838Nvd7vLVP6MY6MaVb/JnV76FdQ5WQ6ticD0Y -o3zmpqqbKVSspN0lrkig4surT88AjfVQz/vEIzKNQEbpzc3hC2LCiE2u+cK/ix4j -b9RohnaPvwLnew5RNQRpcmk+XejaNITISr2yQIwXL7TEYy8HdGCfzFSSFhKe9vkb -GsWS5ASrUzRoprswmlgRe8gEHI+d51Z7mWgna0/5mBz9bH/3QXtpxlLWm3bVV+kt -pZjQDTHE0GqG2YsD1Gmp4LU/JFhCojMTtiPCXmr9KFtpiVlx06DuKm5PC8Ak+5w+ -m/DQYYfv9z+AA5Y430bjnzwg67bhqVyyek4wcDQinFswv3h4bIB7CJujDcEqXXza -lhG1ufPPCUTMrVjh7AShohZraqlSlyQPY9vEppLwD4W1d+MqDHM7ljOH7gQYaUPi -wE30AdXEOxLZcT3aRKxkKf2esNofSuUC/+NXQvPjpuI4UJKO3eegi+M9dbnKoNWs -MPPLPpycecWPheFYM5K6Ao63cjlUY2wYwCfDTFgjA5q8i/Rp7i6Z6fLE3YWJ4VdR -WOFB7hlluQ//jMW6M1qz6IYXmlUjcXl81VEvlOH/QBNrPvX3I3SYXYgVRnVGUudB -o3eNsanvTU+TIFBh2Q== ------END CERTIFICATE----- diff --git a/libi2pd/Config.cpp b/libi2pd/Config.cpp index d99fdde1..d16d82d3 100644 --- a/libi2pd/Config.cpp +++ b/libi2pd/Config.cpp @@ -197,13 +197,12 @@ namespace config { ("reseed.proxy", value()->default_value(""), "url for reseed proxy, supports http/socks") ("reseed.urls", value()->default_value( "https://reseed.i2p-projekt.de/," - "https://reseed.diva.exchange/," - "https://reseed.i2p2.no/," + "https://reseed.diva.exchange/," "https://reseed-fr.i2pd.xyz/," "https://reseed.memcpy.io/," "https://reseed.onion.im/," "https://i2pseed.creativecowpat.net:8443/," - "https://reseed.i2pgit.org/," + "https://reseed.i2pgit.org/," "https://i2p.novg.net/" ), "Reseed URLs, separated by comma") ; From 3dfb44de3114728b44cd84c7aba29f4d4e68af9c Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Nov 2020 14:27:08 -0500 Subject: [PATCH 62/75] exclude DSA floodfills --- libi2pd/NetDb.cpp | 4 ++-- libi2pd/RouterInfo.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index 4399fb15..e280e31b 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -240,7 +240,7 @@ namespace data std::unique_lock l(m_FloodfillsMutex); if (wasFloodfill) m_Floodfills.remove (r); - else + else if (r->IsEligibleFloodfill ()) m_Floodfills.push_back (r); } } @@ -263,7 +263,7 @@ namespace data if (inserted) { LogPrint (eLogInfo, "NetDb: RouterInfo added: ", ident.ToBase64()); - if (r->IsFloodfill () && r->IsReachable ()) // floodfill must be reachable + if (r->IsFloodfill () && r->IsEligibleFloodfill ()) { std::unique_lock l(m_FloodfillsMutex); m_Floodfills.push_back (r); diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index 282c34f9..a4b2fd22 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -184,7 +184,9 @@ namespace data bool IsHidden () const { return m_Caps & eHidden; }; bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; - + // floodfill must be reachable and not DSA + bool IsEligibleFloodfill () const { return IsReachable () && GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1; }; + uint8_t GetCaps () const { return m_Caps; }; void SetCaps (uint8_t caps); void SetCaps (const char * caps); From c875ff923a4a77311728aa7fdb9df72dcf47ca67 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 21 Nov 2020 18:44:40 -0500 Subject: [PATCH 63/75] random intro key --- libi2pd/RouterContext.cpp | 6 +++--- libi2pd/RouterInfo.cpp | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 220fbc4f..cdab624c 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -89,7 +89,7 @@ namespace i2p host = i2p::util::net::GetInterfaceAddress(ifname4, false).to_string(); if (ssu) - routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); + routerInfo.AddSSUAddress (host.c_str(), port, nullptr); } if (ipv6) { @@ -103,7 +103,7 @@ namespace i2p host = i2p::util::net::GetInterfaceAddress(ifname6, true).to_string(); if (ssu) - routerInfo.AddSSUAddress (host.c_str(), port, routerInfo.GetIdentHash ()); + routerInfo.AddSSUAddress (host.c_str(), port, nullptr); } routerInfo.SetCaps (i2p::data::RouterInfo::eReachable | @@ -486,7 +486,7 @@ namespace i2p if (ssu) { std::string host = "::1"; // TODO: read host - m_RouterInfo.AddSSUAddress (host.c_str (), port, GetIdentHash ()); + m_RouterInfo.AddSSUAddress (host.c_str (), port, nullptr); } } // NTCP2 diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 12f81a42..3fc512f6 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -719,7 +719,10 @@ namespace data addr->date = 0; addr->ssu.reset (new SSUExt ()); addr->ssu->mtu = mtu; - memcpy (addr->ssu->key, key, 32); + if (key) + memcpy (addr->ssu->key, key, 32); + else + RAND_bytes (addr->ssu->key, 32); for (const auto& it: *m_Addresses) // don't insert same address twice if (*it == *addr) return; m_SupportedTransports |= addr->host.is_v6 () ? eSSUV6 : eSSUV4; From 771480e368af28ed6218e76f586e5700eacd3c40 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Nov 2020 17:36:00 -0500 Subject: [PATCH 64/75] send queue for incoming I2CP messages --- libi2pd_client/I2CP.cpp | 85 ++++++++++++++++++++++++++++++++++------- libi2pd_client/I2CP.h | 11 +++++- 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 2b9df0fa..05d61474 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -227,12 +227,17 @@ namespace client I2CPSession::I2CPSession (I2CPServer& owner, std::shared_ptr socket): m_Owner (owner), m_Socket (socket), m_SessionID (0xFFFF), - m_MessageID (0), m_IsSendAccepted (true) + m_MessageID (0), m_IsSendAccepted (true), m_IsSending (false) { } I2CPSession::~I2CPSession () { + if (m_SendQueue) + { + for (auto& it: *m_SendQueue) + delete[] boost::asio::buffer_cast(it); + } } void I2CPSession::Start () @@ -358,25 +363,64 @@ namespace client if (socket) { auto l = len + I2CP_HEADER_SIZE; - uint8_t * buf = new uint8_t[l]; + uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len); buf[I2CP_HEADER_TYPE_OFFSET] = type; memcpy (buf + I2CP_HEADER_SIZE, payload, len); - boost::asio::async_write (*socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (), - std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, buf)); + if (m_IsSending) + { + if (!m_SendQueue) + m_SendQueue = std::make_shared (); + if (m_SendQueue->size () > I2CP_MAX_SEND_QUEUE_SIZE) + { + LogPrint (eLogError, "I2CP: Queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); + return; + } + m_SendQueue->push_back ({buf, l}); + } + else + { + m_IsSending = true; + boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), boost::asio::transfer_all (), + std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + } } else LogPrint (eLogError, "I2CP: Can't write to the socket"); } - void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf) + void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) { - delete[] buf; - if (ecode && ecode != boost::asio::error::operation_aborted) - Terminate (); + if (ecode) + { + if (ecode != boost::asio::error::operation_aborted) + Terminate (); + } + else if (m_SendQueue) + { + auto socket = m_Socket; + if (socket) + { + auto queue = m_SendQueue; + m_SendQueue = nullptr; + boost::asio::async_write (*socket, *queue, boost::asio::transfer_all (), + std::bind(&I2CPSession::HandleI2CPMessageSentQueue, shared_from_this (), + std::placeholders::_1, std::placeholders::_2, queue)); + } + } + else + m_IsSending = false; } + void I2CPSession::HandleI2CPMessageSentQueue (const boost::system::error_code& ecode, std::size_t bytes_transferred, SendQueue queue) + { + for (auto& it: *queue) + delete[] boost::asio::buffer_cast(it);; + + HandleI2CPMessageSent (ecode, bytes_transferred); + } + std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len) { uint8_t l = buf[0]; @@ -810,16 +854,31 @@ namespace client if (socket) { auto l = len + 10 + I2CP_HEADER_SIZE; - uint8_t * buf = new uint8_t[l]; + uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE; htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID); htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++); htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); - boost::asio::async_write (*socket, boost::asio::buffer (buf, l), boost::asio::transfer_all (), - std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, buf)); + if (m_IsSending) + { + if (!m_SendQueue) + m_SendQueue = std::make_shared (); + if (m_SendQueue->size () > I2CP_MAX_SEND_QUEUE_SIZE) + { + LogPrint (eLogError, "I2CP: Queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); + return; + } + m_SendQueue->push_back ({buf, l}); + } + else + { + m_IsSending = true; + boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), boost::asio::transfer_all (), + std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + } } else LogPrint (eLogError, "I2CP: Can't write to the socket"); diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index c5dc80e7..51d503aa 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -25,6 +25,7 @@ namespace client const uint8_t I2CP_PROTOCOL_BYTE = 0x2A; const size_t I2CP_SESSION_BUFFER_SIZE = 4096; const size_t I2CP_MAX_MESSAGE_LENGTH = 65535; + const size_t I2CP_MAX_SEND_QUEUE_SIZE = 256; const size_t I2CP_HEADER_LENGTH_OFFSET = 0; const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4; @@ -122,6 +123,8 @@ namespace client class I2CPServer; class I2CPSession: public std::enable_shared_from_this { + typedef std::shared_ptr > SendQueue; + public: #ifdef ANDROID @@ -167,7 +170,8 @@ namespace client void HandleMessage (); void Terminate (); - void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, const uint8_t * buf); + void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); + void HandleI2CPMessageSentQueue (const boost::system::error_code& ecode, std::size_t bytes_transferred, SendQueue queue); std::string ExtractString (const uint8_t * buf, size_t len); size_t PutString (uint8_t * buf, size_t len, const std::string& str); void ExtractMapping (const uint8_t * buf, size_t len, std::map& mapping); @@ -186,6 +190,11 @@ namespace client uint16_t m_SessionID; uint32_t m_MessageID; bool m_IsSendAccepted; + + // to client + bool m_IsSending; + uint8_t m_SendBuffer[I2CP_MAX_MESSAGE_LENGTH]; + SendQueue m_SendQueue; }; typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len); From bc330ff0ea134d5d18d927609d3870192829f70f Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 23 Nov 2020 01:44:21 +0300 Subject: [PATCH 65/75] update makefiles, license year Signed-off-by: R4SAS --- LICENSE | 2 +- Makefile | 5 +++-- Makefile.linux | 16 ++++++++-------- Makefile.mingw | 11 ++++++----- Win32/Resource.rc2 | 2 +- build/build_mingw.cmd | 2 +- contrib/android_binary_pack/build-archive | 2 +- contrib/android_binary_pack/i2pd | 10 +++++----- libi2pd/FS.cpp | 6 +++--- libi2pd/Timestamp.cpp | 2 +- libi2pd/util.cpp | 12 ++++++------ qt/i2pd_qt/i2pd.rc | 2 +- 12 files changed, 37 insertions(+), 35 deletions(-) diff --git a/LICENSE b/LICENSE index 2cb10225..9a1e4527 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2013-2015, The PurpleI2P Project +Copyright (c) 2013-2020, The PurpleI2P Project All rights reserved. diff --git a/Makefile b/Makefile index 7bb3ceda..3e0b23cf 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,7 @@ NEEDED_CXXFLAGS += -MMD -MP -I$(LIB_SRC_DIR) -I$(LIB_CLIENT_SRC_DIR) LIB_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_SRC)) LIB_CLIENT_OBJS += $(patsubst %.cpp,obj/%.o,$(LIB_CLIENT_SRC)) DAEMON_OBJS += $(patsubst %.cpp,obj/%.o,$(DAEMON_SRC)) -DEPS := $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d) +DEPS += $(LIB_OBJS:.o=.d) $(LIB_CLIENT_OBJS:.o=.d) $(DAEMON_OBJS:.o=.d) all: mk_obj_dir $(ARLIB) $(ARLIB_CLIENT) $(I2PD) @@ -82,7 +82,7 @@ obj/%.o: %.cpp -include $(DEPS) $(I2PD): $(DAEMON_OBJS) $(ARLIB) $(ARLIB_CLIENT) - $(CXX) -o $@ $^ $(LDFLAGS) $(LDLIBS) + $(CXX) -o $@ $(LDFLAGS) $^ $(LDLIBS) $(SHLIB): $(LIB_OBJS) ifneq ($(USE_STATIC),yes) @@ -130,3 +130,4 @@ doxygen: .PHONY: api_client .PHONY: mk_obj_dir .PHONY: install +.PHONY: strip diff --git a/Makefile.linux b/Makefile.linux index 6a7590c1..ee6a902b 100644 --- a/Makefile.linux +++ b/Makefile.linux @@ -33,7 +33,7 @@ ifeq ($(USE_STATIC),yes) # NOTE: on glibc you will get this warning: # Using 'getaddrinfo' in statically linked applications requires at runtime # the shared libraries from the glibc version used for linking - LIBDIR := /usr/lib + LIBDIR := /usr/lib/$(SYS) LDLIBS += $(LIBDIR)/libboost_system.a LDLIBS += $(LIBDIR)/libboost_date_time.a LDLIBS += $(LIBDIR)/libboost_filesystem.a @@ -41,20 +41,20 @@ ifeq ($(USE_STATIC),yes) LDLIBS += $(LIBDIR)/libssl.a LDLIBS += $(LIBDIR)/libcrypto.a LDLIBS += $(LIBDIR)/libz.a - LDLIBS += -lpthread -static-libstdc++ -static-libgcc -lrt -ldl - USE_AESNI := no +ifeq ($(USE_UPNP),yes) + LDLIBS += $(LIBDIR)/libminiupnpc.a +endif + LDLIBS += -lpthread -ldl else LDLIBS += -lcrypto -lssl -lz -lboost_system -lboost_date_time -lboost_filesystem -lboost_program_options -lpthread +ifeq ($(USE_UPNP),yes) + LDLIBS += -lminiupnpc +endif endif # UPNP Support (miniupnpc 1.5 and higher) ifeq ($(USE_UPNP),yes) NEEDED_CXXFLAGS += -DUSE_UPNP -ifeq ($(USE_STATIC),yes) - LDLIBS += $(LIBDIR)/libminiupnpc.a -else - LDLIBS += -lminiupnpc -endif endif ifeq ($(USE_AESNI),yes) diff --git a/Makefile.mingw b/Makefile.mingw index 4cd2c292..ce1966a1 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,9 +1,11 @@ -USE_WIN32_APP=yes -CXX = g++ +# Build application with GUI (tray, main window) +USE_WIN32_APP := yes + WINDRES = windres -CXXFLAGS := $(CXX_DEBUG) -D_MT -DWIN32 -D_WINDOWS -DWIN32_LEAN_AND_MEAN -fPIC -msse + +CXXFLAGS := $(CXX_DEBUG) -D_MT -DWIN32_LEAN_AND_MEAN -fPIC -msse INCFLAGS = -I$(DAEMON_SRC_DIR) -IWin32 -LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc -static-libstdc++ +LDFLAGS := ${LD_DEBUG} -Wl,-Bstatic -static-libgcc # detect proper flag for c++11 support by compilers CXXVER := $(shell $(CXX) -dumpversion) @@ -38,7 +40,6 @@ LDLIBS += \ -liphlpapi \ -lole32 \ -luuid \ - -lstdc++ \ -lpthread ifeq ($(USE_WIN32_APP), yes) diff --git a/Win32/Resource.rc2 b/Win32/Resource.rc2 index 6a4f481d..9eecbc1f 100644 --- a/Win32/Resource.rc2 +++ b/Win32/Resource.rc2 @@ -25,7 +25,7 @@ BEGIN VALUE "FileDescription", "C++ I2P daemon" VALUE "FileVersion", I2PD_VERSION VALUE "InternalName", CODENAME - VALUE "LegalCopyright", "Copyright (C) 2013-2017, The PurpleI2P Project" + VALUE "LegalCopyright", "Copyright (C) 2013-2020, The PurpleI2P Project" VALUE "OriginalFilename", "i2pd" VALUE "ProductName", "Purple I2P" VALUE "ProductVersion", I2P_VERSION diff --git a/build/build_mingw.cmd b/build/build_mingw.cmd index e791039e..aaf25843 100644 --- a/build/build_mingw.cmd +++ b/build/build_mingw.cmd @@ -2,7 +2,7 @@ setlocal enableextensions enabledelayedexpansion title Building i2pd -REM Copyright (c) 2013-2017, The PurpleI2P Project +REM Copyright (c) 2013-2020, The PurpleI2P Project REM This file is part of Purple i2pd project and licensed under BSD3 REM See full license text in LICENSE file at top of project tree diff --git a/contrib/android_binary_pack/build-archive b/contrib/android_binary_pack/build-archive index bb56cace..c439dd7f 100755 --- a/contrib/android_binary_pack/build-archive +++ b/contrib/android_binary_pack/build-archive @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2013-2017, The PurpleI2P Project +# Copyright (c) 2013-2020, The PurpleI2P Project # # This file is part of Purple i2pd project and licensed under BSD3 # diff --git a/contrib/android_binary_pack/i2pd b/contrib/android_binary_pack/i2pd index aeaae804..c31cb4ad 100755 --- a/contrib/android_binary_pack/i2pd +++ b/contrib/android_binary_pack/i2pd @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (c) 2013-2019, The PurpleI2P Project +# Copyright (c) 2013-2020, The PurpleI2P Project # # This file is part of Purple i2pd project and licensed under BSD3 # @@ -21,13 +21,13 @@ arch=$(uname -m) screenfind=$(which screen) if [ -z $screenfind ]; then - echo "Can't find 'screen' installed. That script needs it!"; - exit 1; + echo "Can't find 'screen' installed. That script needs it!"; + exit 1; fi if [ -z i2pd-$arch ]; then - echo "Can't find i2pd binary for your archtecture."; - exit 1; + echo "Can't find i2pd binary for your archtecture."; + exit 1; fi screen -AmdS i2pd ./i2pd-$arch --datadir=$DIR diff --git a/libi2pd/FS.cpp b/libi2pd/FS.cpp index 32fc3ec0..bd1a7ad2 100644 --- a/libi2pd/FS.cpp +++ b/libi2pd/FS.cpp @@ -46,13 +46,13 @@ namespace fs { dataDir = cmdline_param; return; } -#if defined(WIN32) || defined(_WIN32) +#ifdef _WIN32 char localAppData[MAX_PATH]; // check executable directory first if(!GetModuleFileName(NULL, localAppData, MAX_PATH)) { -#if defined(WIN32_APP) +#ifdef WIN32_APP MessageBox(NULL, TEXT("Unable to get application path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK); #else fprintf(stderr, "Error: Unable to get application path!"); @@ -70,7 +70,7 @@ namespace fs { { if(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, localAppData) != S_OK) { -#if defined(WIN32_APP) +#ifdef WIN32_APP MessageBox(NULL, TEXT("Unable to get AppData path!"), TEXT("I2Pd: error"), MB_ICONERROR | MB_OK); #else fprintf(stderr, "Error: Unable to get AppData path!"); diff --git a/libi2pd/Timestamp.cpp b/libi2pd/Timestamp.cpp index 45684333..0490350e 100644 --- a/libi2pd/Timestamp.cpp +++ b/libi2pd/Timestamp.cpp @@ -19,7 +19,7 @@ #include "I2PEndian.h" #include "Timestamp.h" -#ifdef WIN32 +#ifdef _WIN32 #ifndef _WIN64 #define _USE_32BIT_TIME_T #endif diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 2cc101c7..24814ad3 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -13,7 +13,7 @@ #include "util.h" #include "Log.h" -#ifdef WIN32 +#ifdef _WIN32 #include #include #include @@ -56,7 +56,7 @@ int inet_pton_xp(int af, const char *src, void *dst) } return 0; } -#else /* !WIN32 => UNIX */ +#else /* !_WIN32 => UNIX */ #include #include #endif @@ -109,7 +109,7 @@ namespace util namespace net { -#ifdef WIN32 +#ifdef _WIN32 bool IsWindowsXPorLater() { static bool isRequested = false; @@ -333,13 +333,13 @@ namespace net return mtu; } -#endif // WIN32 +#endif // _WIN32 int GetMTU(const boost::asio::ip::address& localAddress) { int fallback = localAddress.is_v6 () ? 1280 : 620; // fallback MTU -#ifdef WIN32 +#ifdef _WIN32 return GetMTUWindows(localAddress, fallback); #else return GetMTUUnix(localAddress, fallback); @@ -349,7 +349,7 @@ namespace net const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6) { -#ifdef WIN32 +#ifdef _WIN32 LogPrint(eLogError, "NetIface: cannot get address by interface name, not implemented on WIN32"); if(ipv6) return boost::asio::ip::address::from_string("::1"); diff --git a/qt/i2pd_qt/i2pd.rc b/qt/i2pd_qt/i2pd.rc index bebdf1d6..d31e591e 100644 --- a/qt/i2pd_qt/i2pd.rc +++ b/qt/i2pd_qt/i2pd.rc @@ -17,7 +17,7 @@ BEGIN VALUE "FileDescription", "I2Pd Qt" VALUE "FileVersion", I2PD_VERSION VALUE "InternalName", "i2pd-qt" - VALUE "LegalCopyright", "Copyright (C) 2013-2018, The PurpleI2P Project" + VALUE "LegalCopyright", "Copyright (C) 2013-2020, The PurpleI2P Project" VALUE "LegalTrademarks1", "Distributed under the BSD 3-Clause software license, see the accompanying file COPYING or https://opensource.org/licenses/BSD-3-Clause." VALUE "OriginalFilename", "i2pd_qt.exe" VALUE "ProductName", "i2pd-qt" From 86e3b977e492e832933596f46753c73a85299d5e Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Nov 2020 21:41:27 -0500 Subject: [PATCH 66/75] check I2CP message size --- libi2pd_client/I2CP.cpp | 115 ++++++++++++++++++---------------------- libi2pd_client/I2CP.h | 3 +- 2 files changed, 55 insertions(+), 63 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 05d61474..a2e2d79f 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -354,40 +354,17 @@ namespace client void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len) { - if (len > I2CP_MAX_MESSAGE_LENGTH) + auto l = len + I2CP_HEADER_SIZE; + if (l > I2CP_MAX_MESSAGE_LENGTH) { - LogPrint (eLogError, "I2CP: Message to send is too long ", len); + LogPrint (eLogError, "I2CP: Message to send is too long ", l); return; } - auto socket = m_Socket; - if (socket) - { - auto l = len + I2CP_HEADER_SIZE; - uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; - htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len); - buf[I2CP_HEADER_TYPE_OFFSET] = type; - memcpy (buf + I2CP_HEADER_SIZE, payload, len); - if (m_IsSending) - { - if (!m_SendQueue) - m_SendQueue = std::make_shared (); - if (m_SendQueue->size () > I2CP_MAX_SEND_QUEUE_SIZE) - { - LogPrint (eLogError, "I2CP: Queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); - return; - } - m_SendQueue->push_back ({buf, l}); - } - else - { - m_IsSending = true; - boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), boost::asio::transfer_all (), - std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); - } - } - else - LogPrint (eLogError, "I2CP: Can't write to the socket"); + uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; + htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len); + buf[I2CP_HEADER_TYPE_OFFSET] = type; + memcpy (buf + I2CP_HEADER_SIZE, payload, len); + SendBuffer (buf, l); } void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -420,6 +397,38 @@ namespace client HandleI2CPMessageSent (ecode, bytes_transferred); } + + void I2CPSession::SendBuffer (uint8_t * buf, size_t len) + { + auto socket = m_Socket; + if (socket) + { + if (m_IsSending) + { + auto sendQueue = m_SendQueue; + if (!sendQueue) + { + sendQueue = std::make_shared (); + m_SendQueue = sendQueue; + } + else if (sendQueue->size () > I2CP_MAX_SEND_QUEUE_SIZE) + { + LogPrint (eLogError, "I2CP: Queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); + return; + } + sendQueue->push_back ({buf, len}); + } + else + { + m_IsSending = true; + boost::asio::async_write (*socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), + std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), + std::placeholders::_1, std::placeholders::_2)); + } + } + else + LogPrint (eLogError, "I2CP: Can't write to the socket"); + } std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len) { @@ -850,38 +859,20 @@ namespace client void I2CPSession::SendMessagePayloadMessage (const uint8_t * payload, size_t len) { // we don't use SendI2CPMessage to eliminate additional copy - auto socket = m_Socket; - if (socket) + auto l = len + 10 + I2CP_HEADER_SIZE; + if (l > I2CP_MAX_MESSAGE_LENGTH) { - auto l = len + 10 + I2CP_HEADER_SIZE; - uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; - htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); - buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE; - htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID); - htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++); - htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); - memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); - if (m_IsSending) - { - if (!m_SendQueue) - m_SendQueue = std::make_shared (); - if (m_SendQueue->size () > I2CP_MAX_SEND_QUEUE_SIZE) - { - LogPrint (eLogError, "I2CP: Queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); - return; - } - m_SendQueue->push_back ({buf, l}); - } - else - { - m_IsSending = true; - boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), boost::asio::transfer_all (), - std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); - } - } - else - LogPrint (eLogError, "I2CP: Can't write to the socket"); + LogPrint (eLogError, "I2CP: Message to send is too long ", l); + return; + } + uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; + htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); + buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE; + htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID); + htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++); + htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); + memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); + SendBuffer (buf, l); } I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread): diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 51d503aa..ac3acd45 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -169,7 +169,8 @@ namespace client void HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (); void Terminate (); - + void SendBuffer (uint8_t * buf, size_t len); + void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleI2CPMessageSentQueue (const boost::system::error_code& ecode, std::size_t bytes_transferred, SendQueue queue); std::string ExtractString (const uint8_t * buf, size_t len); From 9301e39af786865665b046be85eb044ba6e72b9d Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Nov 2020 12:49:18 -0500 Subject: [PATCH 67/75] minimal version for floodfill 0.9.28 --- libi2pd/NetDb.hpp | 1 + libi2pd/RouterInfo.cpp | 7 +++++++ libi2pd/RouterInfo.h | 3 +-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index afd1f562..845217e1 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -44,6 +44,7 @@ namespace data const int NETDB_PUBLISH_CONFIRMATION_TIMEOUT = 5; // in seconds const int NETDB_MAX_PUBLISH_EXCLUDED_FLOODFILLS = 15; const int NETDB_MIN_HIGHBANDWIDTH_VERSION = MAKE_VERSION_NUMBER(0, 9, 36); // 0.9.36 + const int NETDB_MIN_FLOODFILL_VERSION = MAKE_VERSION_NUMBER(0, 9, 28); // 0.9.28 /** function for visiting a leaseset stored in a floodfill */ typedef std::function)> LeaseSetVisitor; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 3fc512f6..13776b81 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -948,5 +948,12 @@ namespace data if (encryptor) encryptor->Encrypt (data, encrypted, ctx, true); } + + bool RouterInfo::IsEligibleFloodfill () const + { + // floodfill must be reachable, >= 0.9.28 and not DSA + return IsReachable () && m_Version >= NETDB_MIN_FLOODFILL_VERSION && + GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1; + } } } diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index a4b2fd22..733ea44a 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -184,8 +184,7 @@ namespace data bool IsHidden () const { return m_Caps & eHidden; }; bool IsHighBandwidth () const { return m_Caps & RouterInfo::eHighBandwidth; }; bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; - // floodfill must be reachable and not DSA - bool IsEligibleFloodfill () const { return IsReachable () && GetIdentity ()->GetSigningKeyType () != SIGNING_KEY_TYPE_DSA_SHA1; }; + bool IsEligibleFloodfill () const; uint8_t GetCaps () const { return m_Caps; }; void SetCaps (uint8_t caps); From 1c5b350c2b90d53dbed1841087e4098c30903a20 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 23 Nov 2020 18:55:48 -0500 Subject: [PATCH 68/75] TCP_QUICKACK --- libi2pd/NTCP2.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libi2pd/NTCP2.cpp b/libi2pd/NTCP2.cpp index 7a88e4d8..bb54437e 100644 --- a/libi2pd/NTCP2.cpp +++ b/libi2pd/NTCP2.cpp @@ -742,6 +742,10 @@ namespace transport void NTCP2Session::ReceiveLength () { if (IsTerminated ()) return; +#ifdef __linux__ + const int one = 1; + setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); +#endif boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } @@ -793,6 +797,10 @@ namespace transport void NTCP2Session::Receive () { if (IsTerminated ()) return; +#ifdef __linux__ + const int one = 1; + setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one)); +#endif boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } From c833b16544a8081d5390cb954e82a1d4b5dbffd1 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 26 Nov 2020 09:15:45 -0500 Subject: [PATCH 69/75] check if session expired before generating more tags --- libi2pd/ECIESX25519AEADRatchetSession.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libi2pd/ECIESX25519AEADRatchetSession.cpp b/libi2pd/ECIESX25519AEADRatchetSession.cpp index 3dfe4ca5..00efee48 100644 --- a/libi2pd/ECIESX25519AEADRatchetSession.cpp +++ b/libi2pd/ECIESX25519AEADRatchetSession.cpp @@ -1011,8 +1011,11 @@ namespace garlic void ECIESX25519AEADRatchetSession::GenerateMoreReceiveTags (std::shared_ptr receiveTagset, int numTags) { - for (int i = 0; i < numTags; i++) - GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset); + if (GetOwner ()) + { + for (int i = 0; i < numTags; i++) + GetOwner ()->AddECIESx25519SessionNextTag (receiveTagset); + } } bool ECIESX25519AEADRatchetSession::CheckExpired (uint64_t ts) From ad36738f57fb8709893e27cb92dffe269d7ec337 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 27 Nov 2020 13:37:03 -0500 Subject: [PATCH 70/75] detach session from destination upon termination --- libi2pd_client/I2CP.cpp | 20 +++++++++++++++----- libi2pd_client/I2CP.h | 2 ++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index a2e2d79f..5b8c09b2 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -30,6 +30,12 @@ namespace client { } + void I2CPDestination::Stop () + { + LeaseSetDestination::Stop (); + m_Owner = nullptr; + } + void I2CPDestination::SetEncryptionPrivateKey (const uint8_t * key) { m_Decryptor = i2p::data::PrivateKeys::CreateDecryptor (m_Identity->GetCryptoKeyType (), key); @@ -72,7 +78,8 @@ namespace client { uint32_t length = bufbe32toh (buf); if (length > len - 4) length = len - 4; - m_Owner->SendMessagePayloadMessage (buf + 4, length); + if (m_Owner) + m_Owner->SendMessagePayloadMessage (buf + 4, length); } void I2CPDestination::CreateNewLeaseSet (std::vector > tunnels) @@ -84,7 +91,8 @@ namespace client leases[-1] = tunnels.size (); htobe16buf (leases - 3, m_Owner->GetSessionID ()); size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size (); - m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); + if (m_Owner) + m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); } void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len) @@ -119,7 +127,8 @@ namespace client [s, msg, remote, nonce]() { bool sent = s->SendMsg (msg, remote); - s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); + if (s->m_Owner) + s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); }); } else @@ -130,9 +139,10 @@ namespace client if (ls) { bool sent = s->SendMsg (msg, ls); - s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); + if (s->m_Owner) + s->m_Owner->SendMessageStatusMessage (nonce, sent ? eI2CPMessageStatusGuaranteedSuccess : eI2CPMessageStatusGuaranteedFailure); } - else + else if (s->m_Owner) s->m_Owner->SendMessageStatusMessage (nonce, eI2CPMessageStatusNoLeaseSet); }); } diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index ac3acd45..460b8638 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -71,6 +71,8 @@ namespace client I2CPDestination (boost::asio::io_service& service, std::shared_ptr owner, std::shared_ptr identity, bool isPublic, const std::map& params); ~I2CPDestination () {}; + + void Stop (); void SetEncryptionPrivateKey (const uint8_t * key); void SetEncryptionType (i2p::data::CryptoKeyType keyType) { m_EncryptionKeyType = keyType; }; From 242fb7db14c84e5a8ff960ab3affb8a1a0a6ae81 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 28 Nov 2020 10:09:38 -0500 Subject: [PATCH 71/75] terminate I2CP session if destroyed explicitly --- libi2pd_client/I2CP.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 5b8c09b2..9e9d17ee 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -89,10 +89,16 @@ namespace client m_LeaseSetExpirationTime = ls.GetExpirationTime (); uint8_t * leases = ls.GetLeases (); leases[-1] = tunnels.size (); - htobe16buf (leases - 3, m_Owner->GetSessionID ()); - size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size (); if (m_Owner) - m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); + { + uint16_t sessionID = m_Owner->GetSessionID (); + if (sessionID != 0xFFFF) + { + htobe16buf (leases - 3, sessionID); + size_t l = 2/*sessionID*/ + 1/*num leases*/ + i2p::data::LEASE_SIZE*tunnels.size (); + m_Owner->SendI2CPMessage (I2CP_REQUEST_VARIABLE_LEASESET_MESSAGE, leases - 3, l); + } + } } void I2CPDestination::LeaseSetCreated (const uint8_t * buf, size_t len) @@ -243,11 +249,7 @@ namespace client I2CPSession::~I2CPSession () { - if (m_SendQueue) - { - for (auto& it: *m_SendQueue) - delete[] boost::asio::buffer_cast(it); - } + Terminate (); } void I2CPSession::Start () @@ -358,8 +360,18 @@ namespace client m_Socket->close (); m_Socket = nullptr; } - m_Owner.RemoveSession (GetSessionID ()); - LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " terminated"); + if (m_SendQueue) + { + for (auto& it: *m_SendQueue) + delete[] boost::asio::buffer_cast(it); + m_SendQueue = nullptr; + } + if (m_SessionID != 0xFFFF) + { + m_Owner.RemoveSession (GetSessionID ()); + LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " terminated"); + m_SessionID = 0xFFFF; + } } void I2CPSession::SendI2CPMessage (uint8_t type, const uint8_t * payload, size_t len) @@ -555,11 +567,7 @@ namespace client { SendSessionStatusMessage (0); // destroy LogPrint (eLogDebug, "I2CP: session ", m_SessionID, " destroyed"); - if (m_Destination) - { - m_Destination->Stop (); - m_Destination = 0; - } + Terminate (); } void I2CPSession::ReconfigureSessionMessageHandler (const uint8_t * buf, size_t len) From ff971563dbdc8e18b1b894284ea5b71252d4b8e9 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 28 Nov 2020 22:25:06 -0500 Subject: [PATCH 72/75] cleanup queue after buffers deletion --- libi2pd_client/I2CP.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 9e9d17ee..82ee7841 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -364,6 +364,7 @@ namespace client { for (auto& it: *m_SendQueue) delete[] boost::asio::buffer_cast(it); + m_SendQueue->clear (); m_SendQueue = nullptr; } if (m_SessionID != 0xFFFF) @@ -415,7 +416,8 @@ namespace client void I2CPSession::HandleI2CPMessageSentQueue (const boost::system::error_code& ecode, std::size_t bytes_transferred, SendQueue queue) { for (auto& it: *queue) - delete[] boost::asio::buffer_cast(it);; + delete[] boost::asio::buffer_cast(it); + queue->clear (); HandleI2CPMessageSent (ecode, bytes_transferred); } From 746f53ba0792d786e3038bc9f466a8bc7d0e9198 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Nov 2020 14:59:34 -0500 Subject: [PATCH 73/75] use SendBufferQueue for queued messages from I2P --- libi2pd/Streaming.cpp | 12 ++++- libi2pd/Streaming.h | 6 +++ libi2pd_client/I2CP.cpp | 113 +++++++++++++++++++--------------------- libi2pd_client/I2CP.h | 11 ++-- 4 files changed, 75 insertions(+), 67 deletions(-) diff --git a/libi2pd/Streaming.cpp b/libi2pd/Streaming.cpp index 80e8aecf..05b34d9e 100644 --- a/libi2pd/Streaming.cpp +++ b/libi2pd/Streaming.cpp @@ -21,10 +21,18 @@ namespace stream { void SendBufferQueue::Add (const uint8_t * buf, size_t len, SendHandler handler) { - m_Buffers.push_back (std::make_shared(buf, len, handler)); - m_Size += len; + Add (std::make_shared(buf, len, handler)); } + void SendBufferQueue::Add (std::shared_ptr buf) + { + if (buf) + { + m_Buffers.push_back (buf); + m_Size += buf->len; + } + } + size_t SendBufferQueue::Get (uint8_t * buf, size_t len) { size_t offset = 0; diff --git a/libi2pd/Streaming.h b/libi2pd/Streaming.h index e8b8db91..ab3c4439 100644 --- a/libi2pd/Streaming.h +++ b/libi2pd/Streaming.h @@ -111,6 +111,11 @@ namespace stream buf = new uint8_t[len]; memcpy (buf, b, len); } + SendBuffer (size_t l): // creat empty buffer + len(l), offset (0) + { + buf = new uint8_t[len]; + } ~SendBuffer () { delete[] buf; @@ -129,6 +134,7 @@ namespace stream ~SendBufferQueue () { CleanUp (); }; void Add (const uint8_t * buf, size_t len, SendHandler handler); + void Add (std::shared_ptr buf); size_t Get (uint8_t * buf, size_t len); size_t GetSize () const { return m_Size; }; bool IsEmpty () const { return m_Buffers.empty (); }; diff --git a/libi2pd_client/I2CP.cpp b/libi2pd_client/I2CP.cpp index 82ee7841..cb618b5d 100644 --- a/libi2pd_client/I2CP.cpp +++ b/libi2pd_client/I2CP.cpp @@ -360,13 +360,8 @@ namespace client m_Socket->close (); m_Socket = nullptr; } - if (m_SendQueue) - { - for (auto& it: *m_SendQueue) - delete[] boost::asio::buffer_cast(it); - m_SendQueue->clear (); - m_SendQueue = nullptr; - } + if (!m_SendQueue.IsEmpty ()) + m_SendQueue.CleanUp (); if (m_SessionID != 0xFFFF) { m_Owner.RemoveSession (GetSessionID ()); @@ -383,11 +378,32 @@ namespace client LogPrint (eLogError, "I2CP: Message to send is too long ", l); return; } - uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; + auto sendBuf = m_IsSending ? std::make_shared (l) : nullptr; + uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer; htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len); buf[I2CP_HEADER_TYPE_OFFSET] = type; memcpy (buf + I2CP_HEADER_SIZE, payload, len); - SendBuffer (buf, l); + if (sendBuf) + { + if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) + m_SendQueue.Add (sendBuf); + else + { + LogPrint (eLogWarning, "I2CP: send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); + return; + } + } + else + { + auto socket = m_Socket; + if (socket) + { + m_IsSending = true; + boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), + boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent, + shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + } } void I2CPSession::HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred) @@ -397,62 +413,22 @@ namespace client if (ecode != boost::asio::error::operation_aborted) Terminate (); } - else if (m_SendQueue) + else if (!m_SendQueue.IsEmpty ()) { auto socket = m_Socket; if (socket) { - auto queue = m_SendQueue; - m_SendQueue = nullptr; - boost::asio::async_write (*socket, *queue, boost::asio::transfer_all (), - std::bind(&I2CPSession::HandleI2CPMessageSentQueue, shared_from_this (), - std::placeholders::_1, std::placeholders::_2, queue)); + auto len = m_SendQueue.Get (m_SendBuffer, I2CP_MAX_MESSAGE_LENGTH); + boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, len), + boost::asio::transfer_all (),std::bind(&I2CPSession::HandleI2CPMessageSent, + shared_from_this (), std::placeholders::_1, std::placeholders::_2)); } + else + m_IsSending = false; } else m_IsSending = false; } - - void I2CPSession::HandleI2CPMessageSentQueue (const boost::system::error_code& ecode, std::size_t bytes_transferred, SendQueue queue) - { - for (auto& it: *queue) - delete[] boost::asio::buffer_cast(it); - queue->clear (); - - HandleI2CPMessageSent (ecode, bytes_transferred); - } - - void I2CPSession::SendBuffer (uint8_t * buf, size_t len) - { - auto socket = m_Socket; - if (socket) - { - if (m_IsSending) - { - auto sendQueue = m_SendQueue; - if (!sendQueue) - { - sendQueue = std::make_shared (); - m_SendQueue = sendQueue; - } - else if (sendQueue->size () > I2CP_MAX_SEND_QUEUE_SIZE) - { - LogPrint (eLogError, "I2CP: Queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); - return; - } - sendQueue->push_back ({buf, len}); - } - else - { - m_IsSending = true; - boost::asio::async_write (*socket, boost::asio::buffer (buf, len), boost::asio::transfer_all (), - std::bind(&I2CPSession::HandleI2CPMessageSent, shared_from_this (), - std::placeholders::_1, std::placeholders::_2)); - } - } - else - LogPrint (eLogError, "I2CP: Can't write to the socket"); - } std::string I2CPSession::ExtractString (const uint8_t * buf, size_t len) { @@ -885,14 +861,35 @@ namespace client LogPrint (eLogError, "I2CP: Message to send is too long ", l); return; } - uint8_t * buf = m_IsSending ? new uint8_t[l] : m_SendBuffer; + auto sendBuf = m_IsSending ? std::make_shared (l) : nullptr; + uint8_t * buf = sendBuf ? sendBuf->buf : m_SendBuffer; htobe32buf (buf + I2CP_HEADER_LENGTH_OFFSET, len + 10); buf[I2CP_HEADER_TYPE_OFFSET] = I2CP_MESSAGE_PAYLOAD_MESSAGE; htobe16buf (buf + I2CP_HEADER_SIZE, m_SessionID); htobe32buf (buf + I2CP_HEADER_SIZE + 2, m_MessageID++); htobe32buf (buf + I2CP_HEADER_SIZE + 6, len); memcpy (buf + I2CP_HEADER_SIZE + 10, payload, len); - SendBuffer (buf, l); + if (sendBuf) + { + if (m_SendQueue.GetSize () < I2CP_MAX_SEND_QUEUE_SIZE) + m_SendQueue.Add (sendBuf); + else + { + LogPrint (eLogWarning, "I2CP: send queue size exceeds ", I2CP_MAX_SEND_QUEUE_SIZE); + return; + } + } + else + { + auto socket = m_Socket; + if (socket) + { + m_IsSending = true; + boost::asio::async_write (*socket, boost::asio::buffer (m_SendBuffer, l), + boost::asio::transfer_all (), std::bind(&I2CPSession::HandleI2CPMessageSent, + shared_from_this (), std::placeholders::_1, std::placeholders::_2)); + } + } } I2CPServer::I2CPServer (const std::string& interface, int port, bool isSingleThread): diff --git a/libi2pd_client/I2CP.h b/libi2pd_client/I2CP.h index 460b8638..32f32221 100644 --- a/libi2pd_client/I2CP.h +++ b/libi2pd_client/I2CP.h @@ -17,6 +17,7 @@ #include #include "util.h" #include "Destination.h" +#include "Streaming.h" namespace i2p { @@ -25,7 +26,7 @@ namespace client const uint8_t I2CP_PROTOCOL_BYTE = 0x2A; const size_t I2CP_SESSION_BUFFER_SIZE = 4096; const size_t I2CP_MAX_MESSAGE_LENGTH = 65535; - const size_t I2CP_MAX_SEND_QUEUE_SIZE = 256; + const size_t I2CP_MAX_SEND_QUEUE_SIZE = 1024*1024; // in bytes, 1M const size_t I2CP_HEADER_LENGTH_OFFSET = 0; const size_t I2CP_HEADER_TYPE_OFFSET = I2CP_HEADER_LENGTH_OFFSET + 4; @@ -125,8 +126,6 @@ namespace client class I2CPServer; class I2CPSession: public std::enable_shared_from_this { - typedef std::shared_ptr > SendQueue; - public: #ifdef ANDROID @@ -171,14 +170,12 @@ namespace client void HandleReceivedPayload (const boost::system::error_code& ecode, std::size_t bytes_transferred); void HandleMessage (); void Terminate (); - void SendBuffer (uint8_t * buf, size_t len); void HandleI2CPMessageSent (const boost::system::error_code& ecode, std::size_t bytes_transferred); - void HandleI2CPMessageSentQueue (const boost::system::error_code& ecode, std::size_t bytes_transferred, SendQueue queue); + std::string ExtractString (const uint8_t * buf, size_t len); size_t PutString (uint8_t * buf, size_t len, const std::string& str); void ExtractMapping (const uint8_t * buf, size_t len, std::map& mapping); - void SendSessionStatusMessage (uint8_t status); void SendHostReplyMessage (uint32_t requestID, std::shared_ptr identity); @@ -197,7 +194,7 @@ namespace client // to client bool m_IsSending; uint8_t m_SendBuffer[I2CP_MAX_MESSAGE_LENGTH]; - SendQueue m_SendQueue; + i2p::stream::SendBufferQueue m_SendQueue; }; typedef void (I2CPSession::*I2CPMessageHandler)(const uint8_t * buf, size_t len); From 58153c3579b7e0e9dd1632891b770b82d295ec19 Mon Sep 17 00:00:00 2001 From: R4SAS Date: Mon, 30 Nov 2020 04:10:13 +0300 Subject: [PATCH 74/75] [webconsole] fix content block width Signed-off-by: R4SAS --- daemon/HTTPServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daemon/HTTPServer.cpp b/daemon/HTTPServer.cpp index ecc5acdd..9f420cf0 100644 --- a/daemon/HTTPServer.cpp +++ b/daemon/HTTPServer.cpp @@ -70,7 +70,7 @@ namespace http { " .menu { float: left; } .menu a, .commands a { display: block; }\r\n" " .listitem { display: block; font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" " .tableitem { font-family: monospace; font-size: 1.2em; white-space: nowrap; }\r\n" - " .content { float: left; font-size: 1em; margin-left: 4em; max-width: 46em; overflow: auto; }\r\n" + " .content { float: left; font-size: 1em; margin-left: 4em; max-width: 45em; overflow: auto; }\r\n" " .tunnel.established { color: #56B734; } .tunnel.expiring { color: #D3AE3F; }\r\n" " .tunnel.failed { color: #D33F3F; } .tunnel.building { color: #434343; }\r\n" " caption { font-size: 1.5em; text-align: center; color: #894C84; }\r\n" From 0ab95b1b8791cfe2fab856b42b5ffbd883a15906 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Nov 2020 12:50:15 -0500 Subject: [PATCH 75/75] 2.35.0 --- ChangeLog | 22 +++++++++++++++++++ android/build.gradle | 4 ++-- appveyor.yml | 2 +- contrib/rpm/i2pd-git.spec | 5 ++++- contrib/rpm/i2pd.spec | 5 ++++- debian/changelog | 6 +++++ libi2pd/version.h | 4 ++-- qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml | 1 + 8 files changed, 42 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index dbce5fb2..bc9b28df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,28 @@ # for this file format description, # see https://github.com/olivierlacan/keep-a-changelog +## [2.35.0] - 2020-11-30 +### Added +- ECIES-x25519 routers +- Random intro keys for SSU +- Graceful shutdown timer for windows +- Send queue for I2CP messages +- Update DSA router keys to EdDSA +- TCP_QUICKACK for NTCP2 sockets on Linux +### Changed +- Exclude floodfills with DSA signatures and < 0.9.28 +- Random intervals between tunnel tests and manage for tunnel pools +- Don't replace an addressbook record by one with DSA signature +- Publish RouterInfo after update +- Create paired inbound tunnels if no inbound tunnels yet +- Reseed servers list +### Fixed +- Transient signature length, if different from identity +- Terminate I2CP session if destroyed +- RouterInfo publishing confirmation +- Check if ECIES-X25519-AEAD-Ratchet session expired before generating more tags +- Correct block size for delivery type local for ECIES-X25519-AEAD-Ratchet + ## [2.34.0] - 2020-10-27 ### Added - Ping responses for streaming diff --git a/android/build.gradle b/android/build.gradle index 2c6c782d..dbe75759 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -30,8 +30,8 @@ android { applicationId "org.purplei2p.i2pd" targetSdkVersion 29 minSdkVersion 14 - versionCode 2340 - versionName "2.34.0" + versionCode 2350 + versionName "2.35.0" setProperty("archivesBaseName", archivesBaseName + "-" + versionName) ndk { abiFilters 'armeabi-v7a' diff --git a/appveyor.yml b/appveyor.yml index a8e7d30d..cc6d130b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 2.34.0.{build} +version: 2.35.0.{build} pull_requests: do_not_increment_build_number: true branches: diff --git a/contrib/rpm/i2pd-git.spec b/contrib/rpm/i2pd-git.spec index a320d6aa..d622ced5 100644 --- a/contrib/rpm/i2pd-git.spec +++ b/contrib/rpm/i2pd-git.spec @@ -1,7 +1,7 @@ %define git_hash %(git rev-parse HEAD | cut -c -7) Name: i2pd-git -Version: 2.34.0 +Version: 2.35.0 Release: git%{git_hash}%{?dist} Summary: I2P router written in C++ Conflicts: i2pd @@ -137,6 +137,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Nov 30 2020 orignal - 2.35.0 +- update to 2.35.0 + * Tue Oct 27 2020 orignal - 2.34.0 - update to 2.34.0 diff --git a/contrib/rpm/i2pd.spec b/contrib/rpm/i2pd.spec index 3f5ef260..d147c269 100644 --- a/contrib/rpm/i2pd.spec +++ b/contrib/rpm/i2pd.spec @@ -1,5 +1,5 @@ Name: i2pd -Version: 2.34.0 +Version: 2.35.0 Release: 1%{?dist} Summary: I2P router written in C++ Conflicts: i2pd-git @@ -135,6 +135,9 @@ getent passwd i2pd >/dev/null || \ %changelog +* Mon Nov 30 2020 orignal - 2.35.0 +- update to 2.35.0 + * Tue Oct 27 2020 orignal - 2.34.0 - update to 2.34.0 diff --git a/debian/changelog b/debian/changelog index b79f6cd6..7ca75409 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +i2pd (2.35.0-1) unstable; urgency=high + + * updated to version 2.35.0/0.9.48 + + -- orignal Mon, 30 Nov 2020 16:00:00 +0000 + i2pd (2.34.0-1) unstable; urgency=medium * updated to version 2.34.0 diff --git a/libi2pd/version.h b/libi2pd/version.h index 26ced1c3..f28d88c0 100644 --- a/libi2pd/version.h +++ b/libi2pd/version.h @@ -16,7 +16,7 @@ #define MAKE_VERSION_NUMBER(a,b,c) ((a*100+b)*100+c) #define I2PD_VERSION_MAJOR 2 -#define I2PD_VERSION_MINOR 34 +#define I2PD_VERSION_MINOR 35 #define I2PD_VERSION_MICRO 0 #define I2PD_VERSION_PATCH 0 #define I2PD_VERSION MAKE_VERSION(I2PD_VERSION_MAJOR, I2PD_VERSION_MINOR, I2PD_VERSION_MICRO) @@ -30,7 +30,7 @@ #define I2P_VERSION_MAJOR 0 #define I2P_VERSION_MINOR 9 -#define I2P_VERSION_MICRO 47 +#define I2P_VERSION_MICRO 48 #define I2P_VERSION_PATCH 0 #define I2P_VERSION MAKE_VERSION(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) #define I2P_VERSION_NUMBER MAKE_VERSION_NUMBER(I2P_VERSION_MAJOR, I2P_VERSION_MINOR, I2P_VERSION_MICRO) diff --git a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml index 97a759c2..e23729a8 100644 --- a/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml +++ b/qt/i2pd_qt/data/website.i2pd.i2pd.appdata.xml @@ -35,6 +35,7 @@ +