From 426fbcbfa3811f1893a62944cba4b72eea189ec0 Mon Sep 17 00:00:00 2001
From: zzz <zzz@i2pmail.org>
Date: Sun, 18 Jul 2021 14:22:57 -0400
Subject: [PATCH] Prop 157 updates

- Fix registration of reply key/tag with SKM
- Allow OTBRM down client tunnel
- Disable tunnel hop throttles for allowLocal
- Various cleanups
---
 .../tunnel/InboundMessageDistributor.java     |  3 +-
 .../router/tunnel/TunnelCreatorConfig.java    |  3 +
 .../i2p/router/tunnel/pool/BuildHandler.java  | 19 +++---
 .../router/tunnel/pool/BuildRequestor.java    | 61 ++++++++-----------
 4 files changed, 37 insertions(+), 49 deletions(-)

diff --git a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
index e393105d23..1131f20a3e 100644
--- a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
+++ b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
@@ -318,7 +318,8 @@ class InboundMessageDistributor implements GarlicMessageReceiver.CloveReceiver {
                         _context.statManager().addRateData("tunnel.handleLoadClove", 1);
                         data = null;
                         //_context.inNetMessagePool().add(data, null, null);
-                } else if (_client != null && type != DeliveryStatusMessage.MESSAGE_TYPE) {
+                } else if (_client != null && type != DeliveryStatusMessage.MESSAGE_TYPE &&
+                           type != OutboundTunnelBuildReplyMessage.MESSAGE_TYPE) {
                             // drop it, since the data we receive shouldn't include other stuff, 
                             // as that might open an attack vector
                             _context.statManager().addRateData("tunnel.dropDangerousClientTunnelMessage", 1, 
diff --git a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java
index 47364a8563..4553f2f406 100644
--- a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java
+++ b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java
@@ -421,6 +421,9 @@ public abstract class TunnelCreatorConfig implements TunnelInfo {
                  buf.append("\nHop ").append(i);
              buf.append(": ").append(_config[i]);
         }
+        if (_garlicReplyKeys != null) {
+            buf.append("\nGarlic reply key: ").append(_garlicReplyKeys.key).append(" tag: ").append(_garlicReplyKeys.rtag);
+        }
         return buf.toString();
     }
 }
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
index 9cf128ae5e..cdf51362e8 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java
@@ -13,7 +13,6 @@ import net.i2p.data.EmptyProperties;
 import net.i2p.data.Hash;
 import net.i2p.data.router.RouterIdentity;
 import net.i2p.data.router.RouterInfo;
-import net.i2p.data.SessionKey;
 import net.i2p.data.TunnelId;
 import net.i2p.data.i2np.BuildRequestRecord;
 import net.i2p.data.i2np.BuildResponseRecord;
@@ -32,9 +31,7 @@ import net.i2p.router.Job;
 import net.i2p.router.JobImpl;
 import net.i2p.router.OutNetMessage;
 import net.i2p.router.RouterContext;
-import net.i2p.router.crypto.ratchet.RatchetSessionTag;
 import net.i2p.router.networkdb.kademlia.MessageWrapper;
-import net.i2p.router.networkdb.kademlia.MessageWrapper.OneTimeSession;
 import net.i2p.router.peermanager.TunnelHistory;
 import net.i2p.router.tunnel.HopConfig;
 import net.i2p.router.tunnel.TunnelDispatcher;
@@ -161,9 +158,10 @@ class BuildHandler implements Runnable {
         
         _processor = new BuildMessageProcessor(ctx);
         // used for previous hop, for all requests
-        _requestThrottler = new RequestThrottler(ctx);
+        boolean testMode = ctx.getBooleanProperty("i2np.allowLocal");
+        _requestThrottler = testMode ? null : new RequestThrottler(ctx);
         // used for previous and next hops, for successful builds only
-        _throttler = new ParticipatingThrottler(ctx);
+        _throttler = testMode ? null : new ParticipatingThrottler(ctx);
         _buildReplyHandler = new BuildReplyHandler(ctx);
         _buildMessageHandlerJob = new TunnelBuildMessageHandlerJob(ctx);
         _buildReplyMessageHandlerJob = new TunnelBuildReplyMessageHandlerJob(ctx);
@@ -854,7 +852,7 @@ class BuildHandler implements Runnable {
         // Check participating throttle counters for previous and next hops
         // This is at the end as it compares to a percentage of created tunnels.
         // We may need another counter above for requests.
-        if (response == 0 && !isInGW) {
+        if (response == 0 && !isInGW && _throttler != null) {
             if (from != null && _throttler.shouldThrottle(from)) {
                 if (_log.shouldLog(Log.WARN))
                     _log.warn("Rejecting tunnel (hop throttle), previous hop: " + from + ": " + req);
@@ -864,7 +862,7 @@ class BuildHandler implements Runnable {
             }
         }
         if (response == 0 && (!isOutEnd) &&
-            _throttler.shouldThrottle(nextPeer)) {
+            _throttler != null && _throttler.shouldThrottle(nextPeer)) {
             if (_log.shouldLog(Log.WARN))
                 _log.warn("Rejecting tunnel (hop throttle), next hop: " + req);
             _context.statManager().addRateData("tunnel.rejectHopThrottle", 1);
@@ -1020,10 +1018,7 @@ class BuildHandler implements Runnable {
             I2NPMessage outMessage;
             if (state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) {
                 // garlic encrypt
-                OneTimeSession ots = req.readGarlicKeys();
-                SessionKey sk = ots.key;
-                RatchetSessionTag st = ots.rtag;
-                outMessage = MessageWrapper.wrap(_context, replyMsg, sk, st);
+                outMessage = MessageWrapper.wrap(_context, replyMsg, req.readGarlicKeys());
                 if (outMessage == null) {
                     if (_log.shouldWarn())
                         _log.warn("OTBRM encrypt fail");
@@ -1102,7 +1097,7 @@ class BuildHandler implements Runnable {
                             accept = false;
                         }
                     }
-                    if (accept) {
+                    if (accept && _requestThrottler != null) {
                         // early request throttle check, before queueing and decryption
                         Hash fh = fromHash;
                         if (fh == null && from != null)
diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java
index 9297993843..8680240777 100644
--- a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java
+++ b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java
@@ -146,19 +146,15 @@ abstract class BuildRequestor {
         Hash farEnd = cfg.getFarEnd();
         TunnelManagerFacade mgr = ctx.tunnelManager();
         boolean isInbound = settings.isInbound();
+        // OB only, short record only
+        SessionKeyManager replySKM = null;
         if (settings.isExploratory() || !usePairedTunnels(ctx)) {
             if (isInbound) {
                 pairedTunnel = mgr.selectOutboundExploratoryTunnel(farEnd);
             } else {
                 pairedTunnel = mgr.selectInboundExploratoryTunnel(farEnd);
                 if (pairedTunnel != null) {
-                    OneTimeSession ots = cfg.getGarlicReplyKeys();
-                    if (ots != null) {
-                        SessionKeyManager skm = ctx.sessionKeyManager();
-                        RatchetSKM rskm = (RatchetSKM) skm;
-                        rskm.tagsReceived(ots.key, ots.rtag, 2 * BUILD_MSG_TIMEOUT);
-                        cfg.setGarlicReplyKeys(null);
-                    }
+                    replySKM = ctx.sessionKeyManager();
                 }
             }
         } else {
@@ -169,26 +165,10 @@ abstract class BuildRequestor {
             } else {
                 pairedTunnel = mgr.selectInboundTunnel(from, farEnd);
                 if (pairedTunnel != null) {
-                    OneTimeSession ots = cfg.getGarlicReplyKeys();
-                    if (ots != null) {
-                        SessionKeyManager skm = ctx.clientManager().getClientSessionKeyManager(from);
-                        if (skm != null) {
-                            if (skm instanceof RatchetSKM) {
-                                RatchetSKM rskm = (RatchetSKM) skm;
-                                rskm.tagsReceived(ots.key, ots.rtag, 2 * BUILD_MSG_TIMEOUT);
-                                cfg.setGarlicReplyKeys(null);
-                            } else if (skm instanceof MuxedSKM) {
-                                MuxedSKM mskm = (MuxedSKM) skm;
-                                mskm.tagsReceived(ots.key, ots.rtag, 2 * BUILD_MSG_TIMEOUT);
-                                cfg.setGarlicReplyKeys(null);
-                            } else {
-                                // ElG-only won't work, fall back to expl.
-                                pairedTunnel = null;
-                            }
-                        } else {
-                            // no client SKM, fall back to expl.
-                            pairedTunnel = null;
-                        }
+                    replySKM = ctx.clientManager().getClientSessionKeyManager(from);
+                    if (replySKM == null && cfg.getGarlicReplyKeys() != null) {
+                        // no client SKM, fall back to expl.
+                        pairedTunnel = null;
                     }
                 }
             }
@@ -218,13 +198,7 @@ abstract class BuildRequestor {
                         pairedTunnel = null;
                     }
                     if (pairedTunnel != null) {
-                        OneTimeSession ots = cfg.getGarlicReplyKeys();
-                        if (ots != null) {
-                            SessionKeyManager skm = ctx.sessionKeyManager();
-                            RatchetSKM rskm = (RatchetSKM) skm;
-                            rskm.tagsReceived(ots.key, ots.rtag, 2 * BUILD_MSG_TIMEOUT);
-                            cfg.setGarlicReplyKeys(null);
-                        }
+                        replySKM = ctx.sessionKeyManager();
                     }
                 }
                 if (pairedTunnel != null && log.shouldLog(Log.INFO))
@@ -305,6 +279,21 @@ abstract class BuildRequestor {
             }
             OutNetMessage outMsg = new OutNetMessage(ctx, msg, ctx.clock().now() + FIRST_HOP_TIMEOUT, PRIORITY, peer);
             outMsg.setOnFailedSendJob(new TunnelBuildFirstHopFailJob(ctx, cfg, exec));
+            OneTimeSession ots = cfg.getGarlicReplyKeys();
+            if (ots != null && replySKM != null) {
+                if (replySKM instanceof RatchetSKM) {
+                    RatchetSKM rskm = (RatchetSKM) replySKM;
+                    rskm.tagsReceived(ots.key, ots.rtag, 2 * BUILD_MSG_TIMEOUT);
+                } else if (replySKM instanceof MuxedSKM) {
+                    MuxedSKM mskm = (MuxedSKM) replySKM;
+                    mskm.tagsReceived(ots.key, ots.rtag, 2 * BUILD_MSG_TIMEOUT);
+                } else {
+                    // non-EC client, shouldn't happen, checked at top of createTunnelBuildMessage() below
+                    if (log.shouldWarn())
+                        log.warn("Unsupported SKM for garlic reply to: " + cfg);
+                }
+                cfg.setGarlicReplyKeys(null);
+            }
             try {
                 ctx.outNetMessagePool().add(outMsg);
             } catch (RuntimeException re) {
@@ -345,8 +334,8 @@ abstract class BuildRequestor {
         Hash replyRouter;
         boolean useVariable = SEND_VARIABLE && cfg.getLength() <= MEDIUM_RECORDS;
         boolean useShortTBM = SEND_SHORT && ctx.keyManager().getPublicKey().getType() == EncType.ECIES_X25519;
-        if (useShortTBM && !pool.getSettings().isExploratory()) {
-            // pool must be EC also
+        if (useShortTBM && !cfg.isInbound() && !pool.getSettings().isExploratory()) {
+            // client must be EC also to get garlic OTBRM reply
             LeaseSetKeys lsk = ctx.keyManager().getKeys(pool.getSettings().getDestination());
             if (lsk != null) {
                 if (!lsk.isSupported(EncType.ECIES_X25519))
-- 
GitLab