From 5eba38a24ef3b2cc356809057d418905dc2f974c Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 9 Feb 2013 19:29:08 +0000 Subject: [PATCH] * NetDB: - Encrypt DatabaseLookup messages out exploratory tunnels when we already have the RI of the ff - Don't use multiple routers from the same /16 in lookups or stores --- history.txt | 16 +++-- .../src/net/i2p/router/RouterVersion.java | 2 +- .../kademlia/FloodfillPeerSelector.java | 60 +++++++++++++++++-- .../kademlia/IterativeSearchJob.java | 17 +++++- .../networkdb/kademlia/MessageWrapper.java | 27 +++++++++ 5 files changed, 111 insertions(+), 11 deletions(-) diff --git a/history.txt b/history.txt index 9be67d005b..cd759bc419 100644 --- a/history.txt +++ b/history.txt @@ -1,6 +1,12 @@ +2013-02-10 zzz + * NetDB: + - Encrypt DatabaseLookup messages out exploratory tunnels + when we already have the RI of the ff + - Don't use multiple routers from the same /16 in lookups or stores + 2013-02-06 kytv -* German, Polish, Portuguese, Spanish, and Swedish translation updates - from Transifex + * German, Polish, Portuguese, Spanish, and Swedish translation updates + from Transifex 2013-02-04 str4d * i2ptunnel: @@ -9,8 +15,8 @@ - Allow any domain name to be mapped, not just .i2p 2013-01-31 kytv -* Add Norwegian Bokmål language to the router console -* Add Bokmål translations from Transifex + * Add Norwegian Bokmål language to the router console + * Add Bokmål translations from Transifex 2013-01-31 zzz * EepGet: @@ -18,7 +24,7 @@ - Add port to Host header to conform to RFC 2616 2013-01-29 zzz - * Console: Catch IllegalStateException storing nonces (ticket #852) + * Console: Catch IllegalStateException storing nonces (tickets #836, #852, #858) * Translations: - Use JVM language name if available - Correct Estonian language code from ee to et diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index f2522cd4ed..7ca1a3ec2c 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 = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 9; + public final static long BUILD = 10; /** for example "-test" */ public final static String EXTRA = ""; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java index 08b902f6ac..23a34c32f9 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java @@ -9,6 +9,7 @@ package net.i2p.router.networkdb.kademlia; */ import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; @@ -17,6 +18,7 @@ import java.util.Set; import java.util.TreeSet; import net.i2p.data.Hash; +import net.i2p.data.RouterAddress; import net.i2p.data.RouterInfo; import net.i2p.router.RouterContext; import net.i2p.router.peermanager.PeerProfile; @@ -205,17 +207,29 @@ class FloodfillPeerSelector extends PeerSelector { } } - // 8 == FNDF.MAX_TO_FLOOD + 1 - int limit = Math.max(8, howMany); + // 5 == FNDF.MAX_TO_FLOOD + 1 + int limit = Math.max(5, howMany); limit = Math.min(limit, ffs.size()); + Set maskedIPs = new HashSet(limit + 4); // split sorted list into 3 sorted lists for (int i = 0; found < howMany && i < limit; i++) { Hash entry = sorted.first(); - sorted.remove(entry); if (entry == null) break; // shouldn't happen + sorted.remove(entry); + // put anybody in the same /16 at the end RouterInfo info = _context.netDb().lookupRouterInfoLocally(entry); - if (info != null && now - info.getPublished() > 3*60*60*1000) { + Set entryIPs = maskedIPSet(entry, info, 2); + boolean sameIP = false; + for (Integer ip : entryIPs) { + if (!maskedIPs.add(ip)) + sameIP = true; + } + if (sameIP) { + badff.add(entry); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Same /16: " + entry); + } else if (info != null && now - info.getPublished() > 3*60*60*1000) { badff.add(entry); if (_log.shouldLog(Log.DEBUG)) _log.debug("Old: " + entry); @@ -270,6 +284,44 @@ class FloodfillPeerSelector extends PeerSelector { return rv; } + + /** + * The Set of IPs for this peer, with a given mask. + * Includes the comm system's record of the IP, and all netDb addresses. + * + * @param pinfo may be null + * @return an opaque set of masked IPs for this peer + * @since 0.9.5 modified from ProfileOrganizer + */ + private Set maskedIPSet(Hash peer, RouterInfo pinfo, int mask) { + Set rv = new HashSet(2); + byte[] commIP = _context.commSystem().getIP(peer); + if (commIP != null) + rv.add(maskedIP(commIP, mask)); + if (pinfo == null) + return rv; + Collection paddr = pinfo.getAddresses(); + if (paddr == null) + return rv; + for (RouterAddress pa : paddr) { + byte[] pib = pa.getIP(); + if (pib == null) continue; + rv.add(maskedIP(pib, mask)); + } + return rv; + } + + /** + * generate an arbitrary unique value for this ip/mask (mask = 1-4) + * @since 0.9.5 copied from ProfileOrganizer + */ + private static Integer maskedIP(byte[] ip, int mask) { + int rv = 0; + for (int i = 0; i < mask; i++) + rv = (rv << 8) | (ip[i] & 0xff); + return Integer.valueOf(rv); + } + private class FloodfillSelectionCollector implements SelectionCollector { private final TreeSet _sorted; private final List _floodfillMatches; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java index a27c9a5bae..25d57f6f83 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/IterativeSearchJob.java @@ -14,6 +14,7 @@ import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseLookupMessage; +import net.i2p.data.i2np.I2NPMessage; import net.i2p.router.CommSystemFacade; import net.i2p.router.Job; import net.i2p.router.MessageSelector; @@ -225,7 +226,21 @@ class IterativeSearchJob extends FloodSearchJob { _log.info(getJobId() + ": Iterative search for " + _key + " to " + peer); long now = getContext().clock().now(); _sentTime.put(peer, Long.valueOf(now)); - getContext().tunnelDispatcher().dispatchOutbound(dlm, outTunnel.getSendTunnelId(0), peer); + + I2NPMessage outMsg = null; + if (_isLease) { + // Full ElG is fairly expensive so only do it for LS lookups + // if we have the ff RI, garlic encrypt it + RouterInfo ri = getContext().netDb().lookupRouterInfoLocally(peer); + if (ri != null) { + outMsg = MessageWrapper.wrap(getContext(), dlm, ri); + if (_log.shouldLog(Log.DEBUG)) + _log.debug(getJobId() + ": Encrypted DLM for " + _key + " to " + peer); + } + } + if (outMsg == null) + outMsg = dlm; + getContext().tunnelDispatcher().dispatchOutbound(outMsg, outTunnel.getSendTunnelId(0), peer); // The timeout job is always run (never cancelled) // Note that the timeout is much shorter than the message expiration (see above) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java index 5bed6aec7a..4359b840de 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java @@ -115,4 +115,31 @@ class MessageWrapper { } } } + + /** + * Garlic wrap a message from nobody, destined for a router, + * to hide the contents from the OBEP. + * Forces ElGamal. + * + * @return null on encrypt failure + * @since 0.9.5 + */ + static GarlicMessage wrap(RouterContext ctx, I2NPMessage m, RouterInfo to) { + DeliveryInstructions instructions = new DeliveryInstructions(); + instructions.setDeliveryMode(DeliveryInstructions.DELIVERY_MODE_LOCAL); + + PayloadGarlicConfig payload = new PayloadGarlicConfig(); + payload.setCertificate(Certificate.NULL_CERT); + payload.setId(ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE)); + payload.setPayload(m); + payload.setRecipient(to); + payload.setDeliveryInstructions(instructions); + payload.setExpiration(m.getMessageExpiration()); + + SessionKey sentKey = ctx.keyGenerator().generateSessionKey(); + PublicKey key = to.getIdentity().getPublicKey(); + GarlicMessage msg = GarlicMessageBuilder.buildMessage(ctx, payload, null, null, + key, sentKey, null); + return msg; + } }