diff --git a/history.txt b/history.txt index 2d9d95d50..ad37ccb60 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,6 @@ +2021-07-28 zzz + * Tunnels: Fixes for proposal 157 + 2021-07-23 zzz * Transport: Fix UPnP IPv6 NPE diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index f2424bd3b..707cdcd34 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Git"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 6; + public final static long BUILD = 7; /** for example "-test" */ public final static String EXTRA = ""; 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 f6eb4ee22..430dc304d 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java @@ -316,7 +316,6 @@ class BuildHandler implements Runnable { if (_log.shouldLog(Log.INFO)) _log.info(msg.getUniqueId() + ": Handling the reply after " + rtt + ", delayed " + delay + " waiting for " + cfg); - // TODO OTBRM List order = cfg.getReplyOrder(); int statuses[] = _buildReplyHandler.decrypt(msg, cfg, order); if (statuses != null) { @@ -628,11 +627,11 @@ class BuildHandler implements Runnable { _currentLookups.decrementAndGet(); getContext().statManager().addRateData("tunnel.rejectTimeout", 1); getContext().statManager().addRateData("tunnel.buildLookupSuccess", 0); - if (_log.shouldLog(Log.WARN)) { + if (_log.shouldInfo()) { Hash from = _state.fromHash; if (from == null && _state.from != null) from = _state.from.calculateHash(); - _log.warn("Next hop lookup failure: " + _req + _log.info("Next hop lookup failure: " + _req + " From: " + from + " ID: " + _state.msg.getUniqueId()); } @@ -1025,8 +1024,9 @@ class BuildHandler implements Runnable { } replyMsg.setUniqueId(req.readReplyMessageId()); replyMsg.setMessageExpiration(expires); + boolean replyGwIsUs = _context.routerHash().equals(nextPeer); I2NPMessage outMessage; - if (state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) { + if (!replyGwIsUs && state.msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE && !_context.getBooleanProperty("router.disableEncryptOTBRM")) { // garlic encrypt outMessage = MessageWrapper.wrap(_context, replyMsg, req.readGarlicKeys()); if (outMessage == null) { @@ -1041,7 +1041,7 @@ class BuildHandler implements Runnable { m.setMessage(outMessage); m.setMessageExpiration(expires); m.setTunnelId(new TunnelId(nextId)); - if (_context.routerHash().equals(nextPeer)) { + if (replyGwIsUs) { // ok, we are the gateway, so inject it if (_log.shouldLog(Log.DEBUG)) _log.debug("We are the reply gateway for " + nextId @@ -1282,8 +1282,8 @@ class BuildHandler implements Runnable { //getContext().tunnelDispatcher().remove(_cfg); getContext().statManager().addRateData("tunnel.rejectTimeout2", 1); Log log = getContext().logManager().getLog(BuildHandler.class); - if (log.shouldLog(Log.WARN)) - log.warn("Timeout contacting next hop for " + _cfg); + if (log.shouldInfo()) + log.info("Timeout contacting next hop for " + _cfg); } } diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java b/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java index 7715cf641..f597c5b20 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildMessageGenerator.java @@ -94,6 +94,8 @@ abstract class BuildMessageGenerator { private static BuildRequestRecord createUnencryptedRecord(I2PAppContext ctx, TunnelCreatorConfig cfg, int hop, Hash replyRouter, long replyTunnel, boolean isEC, boolean isShort) { + if (isShort && !isEC) + throw new IllegalArgumentException(); if (hop < cfg.getLength()) { // ok, now lets fill in some data HopConfig hopConfig = cfg.getConfig(hop); @@ -118,8 +120,6 @@ abstract class BuildMessageGenerator { nextPeer = peer; // self } } - SessionKey layerKey = hopConfig.getLayerKey(); - SessionKey ivKey = hopConfig.getIVKey(); boolean isInGW = (cfg.isInbound() && (hop == 0)); boolean isOutEnd = (!cfg.isInbound() && (hop + 1 >= cfg.getLength())); @@ -138,6 +138,8 @@ abstract class BuildMessageGenerator { nextMsgId, isInGW, isOutEnd, EmptyProperties.INSTANCE); } else { + SessionKey layerKey = hopConfig.getLayerKey(); + SessionKey ivKey = hopConfig.getIVKey(); SessionKey replyKey = cfg.getAESReplyKey(hop); byte iv[] = cfg.getAESReplyIV(hop); if (iv == null) @@ -147,6 +149,8 @@ abstract class BuildMessageGenerator { iv, isInGW, isOutEnd, EmptyProperties.INSTANCE); } } else { + SessionKey layerKey = hopConfig.getLayerKey(); + SessionKey ivKey = hopConfig.getIVKey(); SessionKey replyKey = cfg.getAESReplyKey(hop); byte iv[] = cfg.getAESReplyIV(hop); if (iv == 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 868024077..5dd6c7af9 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildRequestor.java @@ -3,9 +3,11 @@ package net.i2p.router.tunnel.pool; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.StringTokenizer; import net.i2p.crypto.EncType; import net.i2p.crypto.SessionKeyManager; +import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.PublicKey; @@ -233,7 +235,9 @@ abstract class BuildRequestor { //long beforeDispatch = System.currentTimeMillis(); if (cfg.isInbound()) { Hash ibgw = cfg.getPeer(0); - if (msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE) { + // don't wrap if IBGW == OBEP + if (msg.getType() == ShortTunnelBuildMessage.MESSAGE_TYPE && + !ibgw.equals(pairedTunnel.getEndpoint())) { // STBM is garlic encrypted to the IBGW, to hide it from the OBEP RouterInfo peer = ctx.netDb().lookupRouterInfoLocally(ibgw); if (peer != null) { @@ -263,6 +267,7 @@ abstract class BuildRequestor { if (log.shouldLog(Log.INFO)) log.info("Sending the tunnel build request directly to " + cfg.getPeer(1) + " for " + cfg + " waiting for the reply of " + cfg.getReplyMessageId() + + " via IB tunnel " + pairedTunnel + " with msgId=" + msg.getUniqueId()); // send it directly to the first hop // Add some fuzz to the TBM expiration to make it harder to guess how many hops @@ -345,13 +350,36 @@ abstract class BuildRequestor { } } + // Testing, send to explicitPeers only + List explicitPeers = null; + if (useShortTBM) { + String peers = ctx.getProperty("explicitPeers"); + if (peers != null && !peers.isEmpty()) { + explicitPeers = new ArrayList(4); + StringTokenizer tok = new StringTokenizer(peers, ","); + while (tok.hasMoreTokens()) { + String peerStr = tok.nextToken(); + Hash peer = new Hash(); + try { + peer.fromBase64(peerStr); + explicitPeers.add(peer); + } catch (DataFormatException dfe) {} + } + if (explicitPeers.isEmpty()) + useShortTBM = false; + } else { + useShortTBM = false; + } + } + if (cfg.isInbound()) { //replyTunnel = 0; // as above replyRouter = ctx.routerHash(); if (useShortTBM) { // check all the tunnel peers except ourselves for (int i = 0; i < cfg.getLength() - 1; i++) { - if (!supportsShortTBM(ctx, cfg.getPeer(i))) { + // TODO remove explicit check + if (!explicitPeers.contains(cfg.getPeer(i)) || !supportsShortTBM(ctx, cfg.getPeer(i))) { useShortTBM = false; break; } @@ -362,8 +390,9 @@ abstract class BuildRequestor { replyRouter = pairedTunnel.getPeer(0); if (useShortTBM) { // check all the tunnel peers except ourselves - for (int i = 1; i < cfg.getLength() - 1; i++) { - if (!supportsShortTBM(ctx, cfg.getPeer(i))) { + for (int i = 1; i < cfg.getLength(); i++) { + // TODO remove explicit check + if (!explicitPeers.contains(cfg.getPeer(i)) || !supportsShortTBM(ctx, cfg.getPeer(i))) { useShortTBM = false; break; } @@ -451,6 +480,8 @@ abstract class BuildRequestor { BuildMessageGenerator.createRecord(i, hop, msg, cfg, replyRouter, replyTunnel, ctx, key); } BuildMessageGenerator.layeredEncrypt(ctx, msg, cfg, order); + //if (useShortTBM && log.shouldWarn()) + // log.warn("Sending STBM: " + cfg.toStringFull()); return msg; } diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index df47a76da..06bc41118 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -106,6 +106,9 @@ public abstract class TunnelPeerSelector extends ConnectChecker { */ protected boolean shouldSelectExplicit(TunnelPoolSettings settings) { if (settings.isExploratory()) return false; + // To test IB or OB only + //if (settings.isInbound()) return false; + //if (!settings.isInbound()) return false; Properties opts = settings.getUnknownOptions(); String peers = opts.getProperty("explicitPeers"); if (peers == null) @@ -216,7 +219,8 @@ public abstract class TunnelPeerSelector extends ConnectChecker { Set peers = new HashSet(8); peers.addAll(ctx.profileOrganizer().selectPeersRecentlyRejecting()); - peers.addAll(ctx.tunnelManager().selectPeersInTooManyTunnels()); + if (!ctx.getBooleanProperty("i2np.allowLocal")) + peers.addAll(ctx.tunnelManager().selectPeersInTooManyTunnels()); if (filterUnreachable(isInbound, isExploratory)) { // This is the only use for getPeersByCapability? And the whole set of datastructures in PeerManager? Collection caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE);