From cb22f31d963c606e2ee6f6aa918a4bf778b5dda9 Mon Sep 17 00:00:00 2001
From: zzz <zzz@i2pmail.org>
Date: Sun, 24 Jan 2021 09:38:03 -0500
Subject: [PATCH] Tunnels: Update profiles for tunnel peers on corrupt message
 at endpoint

---
 .../i2p/router/tunnel/FragmentHandler.java    | 13 ++++++----
 .../router/tunnel/OutboundTunnelEndpoint.java | 14 +++++++++--
 .../i2p/router/tunnel/TunnelParticipant.java  | 24 +++++++++++++++----
 3 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
index 962e205fc0..892eb2e66b 100644
--- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
+++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java
@@ -117,8 +117,9 @@ class FragmentHandler {
      * sending the resulting I2NPMessages where necessary.  The received 
      * fragments are all verified.
      *
+     * @return ok (false if corrupt)
      */
-    public void receiveTunnelMessage(byte preprocessed[], int offset, int length) {
+    public boolean receiveTunnelMessage(byte preprocessed[], int offset, int length) {
         boolean ok = verifyPreprocessed(preprocessed, offset, length);
         if (!ok) {
             if (_log.shouldLog(Log.WARN))
@@ -126,7 +127,7 @@ class FragmentHandler {
                           + preprocessed.length + " off=" +offset + " len=" + length);
             _cache.release(new ByteArray(preprocessed));
             _context.statManager().addRateData("tunnel.corruptMessage", 1);
-            return;
+            return false;
         }
         offset += HopProcessor.IV_LENGTH; // skip the IV
         offset += 4; // skip the hash segment
@@ -139,7 +140,7 @@ class FragmentHandler {
                 _context.statManager().addRateData("tunnel.corruptMessage", 1);
                 if (_log.shouldWarn())
                     _log.warn("Corrupt fragment received: off = " + offset);
-                return;
+                return false;
             }
             padding++;
         }
@@ -155,7 +156,7 @@ class FragmentHandler {
                     _context.statManager().addRateData("tunnel.corruptMessage", 1);
                     if (_log.shouldWarn())
                         _log.warn("Corrupt fragment received: off = " + off);
-                    return;
+                    return false;
                 }
                 offset = off;
             }
@@ -163,10 +164,12 @@ class FragmentHandler {
             _context.statManager().addRateData("tunnel.corruptMessage", 1);
             if (_log.shouldWarn())
                 _log.warn("Corrupt fragment received: offset = " + offset, aioobe);
+            return false;
         } catch (NullPointerException npe) {
             if (_log.shouldWarn())
                 _log.warn("Corrupt fragment received: offset = " + offset, npe);
             _context.statManager().addRateData("tunnel.corruptMessage", 1);
+            return false;
         } catch (RuntimeException e) {
             if (_log.shouldWarn())
                 _log.warn("Corrupt fragment received: offset = " + offset, e);
@@ -183,6 +186,7 @@ class FragmentHandler {
             // let's limit the damage here and skip the:
             // .transport.udp.MessageReceiver: b0rked receiving a message.. wazza huzza hmm?
             //throw e;
+            return false;
         } finally {
             // each of the FragmentedMessages populated make a copy out of the
             // payload, which they release separately, so we can release 
@@ -192,6 +196,7 @@ class FragmentHandler {
             // in order to put it in the pool, but it shouldn't cause any harm.
             _cache.release(new ByteArray(preprocessed));
         }
+        return true;
     }
     
     public int getCompleteCount() { return _completed.get(); }
diff --git a/router/java/src/net/i2p/router/tunnel/OutboundTunnelEndpoint.java b/router/java/src/net/i2p/router/tunnel/OutboundTunnelEndpoint.java
index b394f514df..34bb787950 100644
--- a/router/java/src/net/i2p/router/tunnel/OutboundTunnelEndpoint.java
+++ b/router/java/src/net/i2p/router/tunnel/OutboundTunnelEndpoint.java
@@ -32,7 +32,8 @@ class OutboundTunnelEndpoint {
 
     public void dispatch(TunnelDataMessage msg, Hash recvFrom) {
         _config.incrementProcessedMessages();
-        boolean ok = _processor.process(msg.getData(), 0, msg.getData().length, recvFrom);
+        byte[] data = msg.getData();
+        boolean ok = _processor.process(data, 0, data.length, recvFrom);
         if (!ok) {
             // invalid IV
             // If we pass it on to the handler, it will fail
@@ -41,7 +42,16 @@ class OutboundTunnelEndpoint {
                 _log.warn("Invalid IV, dropping at OBEP " + _config);
             return;
         }
-        _handler.receiveTunnelMessage(msg.getData(), 0, msg.getData().length);
+        ok = _handler.receiveTunnelMessage(data, 0, data.length);
+        if (!ok) {
+            // blame previous hop
+            Hash h = _config.getReceiveFrom();
+            if (h != null) {
+                if (_log.shouldLog(Log.WARN))
+                    _log.warn(toString() + ": Blaming " + h + " 50%");
+                _context.profileManager().tunnelFailed(h, 50);
+            }
+        }
     }
     
     private class DefragmentedHandler implements FragmentHandler.DefragmentedReceiver {
diff --git a/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java b/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java
index c27ceecb39..4741927705 100644
--- a/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java
+++ b/router/java/src/net/i2p/router/tunnel/TunnelParticipant.java
@@ -122,10 +122,26 @@ class TunnelParticipant {
                                                   new TimeoutJob(_context, msg), MAX_LOOKUP_TIME);
             }
         } else {
-            _inboundEndpointProcessor.getConfig().incrementProcessedMessages();
-            if (_log.shouldLog(Log.DEBUG))
-                _log.debug("Receive fragment: on " + _config + ": " + msg);
-            _handler.receiveTunnelMessage(data, 0, data.length);
+            // IBEP
+            TunnelCreatorConfig cfg = _inboundEndpointProcessor.getConfig();
+            cfg.incrementProcessedMessages();
+            ok = _handler.receiveTunnelMessage(data, 0, data.length);
+            if (ok) {
+                if (_log.shouldLog(Log.DEBUG))
+                    _log.debug("Receive fragment: on " + _config + ": " + msg);
+            } else {
+                // blame everybody equally
+                int lenm1 = cfg.getLength() - 1;
+                if (lenm1 > 0) {
+                    int pct = 100 / (lenm1);
+                    for (int i = 0; i < lenm1; i++) {
+                        Hash h = cfg.getPeer(i);
+                        if (_log.shouldLog(Log.WARN))
+                            _log.warn(toString() + ": Blaming " + h + ' ' + pct + '%');
+                        _context.profileManager().tunnelFailed(h, pct);
+                    }
+                }
+            }
         }
     }
     
-- 
GitLab