diff --git a/history.txt b/history.txt index ef65d315c57b546814f6642abdda20b1360c0868..4da6a73704e3208360404b750c8ce006350622ae 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,10 @@ -$Id: history.txt,v 1.330 2005/11/26 00:05:54 jrandom Exp $ +$Id: history.txt,v 1.331 2005/11/26 04:16:25 jrandom Exp $ + +2005-11-26 jrandom + * Be more explicit about what messages we will handle through a client + tunnel, and how we will handle them. This cuts off a set of attacks + that an active adversary could mount, though they're probably nonobvious + and would require at least some sophistication. 2005-11-26 Raccoon23 * Added support for 'dynamic keys' mode, where the router creates a new diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 9fc26a3286c004ac7cd4e8bc22662f9e92460a43..18e17bdcae84dd6d665d7af0f5e781172a433a69 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.298 $ $Date: 2005/11/26 00:05:53 $"; + public final static String ID = "$Revision: 1.299 $ $Date: 2005/11/26 04:16:13 $"; public final static String VERSION = "0.6.1.5"; - public final static long BUILD = 9; + public final static long BUILD = 10; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION + "-" + BUILD); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java index 23915ff5fbf5a48710d467aa863e14fbfbda2c98..ad994ab3434cc4ae08a9c392b1f1f741651faac2 100644 --- a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java +++ b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java @@ -5,6 +5,7 @@ import net.i2p.data.TunnelId; import net.i2p.data.Payload; import net.i2p.data.i2np.DataMessage; import net.i2p.data.i2np.DatabaseStoreMessage; +import net.i2p.data.i2np.DeliveryStatusMessage; import net.i2p.data.i2np.DeliveryInstructions; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.i2np.GarlicMessage; @@ -32,6 +33,7 @@ public class InboundMessageDistributor implements GarlicMessageReceiver.CloveRec _client = client; _log = ctx.logManager().getLog(InboundMessageDistributor.class); _receiver = new GarlicMessageReceiver(ctx, this, client); + _context.statManager().createRateStat("tunnel.dropDangerousClientTunnelMessage", "How many tunnel messages come down a client tunnel that we shouldn't expect (lifetime is the 'I2NP type')", "Tunnels", new long[] { 10*60*1000, 60*60*1000 }); } public void distribute(I2NPMessage msg, Hash target) { @@ -49,6 +51,16 @@ public class InboundMessageDistributor implements GarlicMessageReceiver.CloveRec } */ + if ( (_client != null) && + (msg.getType() != DeliveryStatusMessage.MESSAGE_TYPE) && + (msg.getType() != GarlicMessage.MESSAGE_TYPE) ) { + // drop it, since we should only get tunnel test messages and garlic messages down + // client tunnels + _context.statManager().addRateData("tunnel.dropDangerousClientTunnelMessage", 1, msg.getType()); + _log.error("Dropped dangerous message down a tunnel for " + _client.toBase64() + ": " + msg, new Exception("cause")); + return; + } + if ( (target == null) || ( (tunnel == null) && (_context.routerHash().equals(target) ) ) ) { // targetting us either implicitly (no target) or explicitly (no tunnel) // make sure we don't honor any remote requests directly (garlic instructions, etc) @@ -115,16 +127,39 @@ public class InboundMessageDistributor implements GarlicMessageReceiver.CloveRec // unnecessarily DatabaseStoreMessage dsm = (DatabaseStoreMessage)data; try { - if (dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) + if (dsm.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) { + // dont tell anyone else about it if we got it through a client tunnel + // (though this is the default, but it doesn't hurt to make it explicit) + if (_client != null) + dsm.getLeaseSet().setReceivedAsPublished(false); _context.netDb().store(dsm.getKey(), dsm.getLeaseSet()); - else + } else { + if (_client != null) { + // drop it, since the data we receive shouldn't include router + // references, as that might get us to talk to them (and therefore + // open an attack vector) + _context.statManager().addRateData("tunnel.dropDangerousClientTunnelMessage", 1, + DatabaseStoreMessage.MESSAGE_TYPE); + _log.error("Dropped dangerous message down a tunnel for " + _client.toBase64() + ": " + dsm, new Exception("cause")); + return; + } _context.netDb().store(dsm.getKey(), dsm.getRouterInfo()); + } } catch (IllegalArgumentException iae) { if (_log.shouldLog(Log.WARN)) _log.warn("Bad store attempt", iae); } } else { - _context.inNetMessagePool().add(data, null, null); + if ( (_client != null) && (data.getType() != DeliveryStatusMessage.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, + data.getType()); + _log.error("Dropped dangerous message down a tunnel for " + _client.toBase64() + ": " + data, new Exception("cause")); + return; + } else { + _context.inNetMessagePool().add(data, null, null); + } } return; }