Tunnels: Updates for proposal 157

- Fix compatibility check for OB tunnels
- Add test code to send STBM to explicit peers
- Skip too-many-tunnels check when in test mode
- Cleanups and Log tweaks
This commit is contained in:
zzz
2021-07-28 11:09:51 -04:00
parent d246689242
commit 2edac95be9
6 changed files with 57 additions and 15 deletions

View File

@@ -1,3 +1,6 @@
2021-07-28 zzz
* Tunnels: Fixes for proposal 157
2021-07-23 zzz
* Transport: Fix UPnP IPv6 NPE

View File

@@ -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 = "";

View File

@@ -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<Integer> 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);
}
}

View File

@@ -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)

View File

@@ -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<Hash> explicitPeers = null;
if (useShortTBM) {
String peers = ctx.getProperty("explicitPeers");
if (peers != null && !peers.isEmpty()) {
explicitPeers = new ArrayList<Hash>(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;
}

View File

@@ -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<Hash> peers = new HashSet<Hash>(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<Hash> caps = ctx.peerManager().getPeersByCapability(Router.CAPABILITY_UNREACHABLE);