- 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
This commit is contained in:
zzz
2013-02-09 19:29:08 +00:00
parent 7f5d6ca1c7
commit 5eba38a24e
5 changed files with 111 additions and 11 deletions

View File

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

View File

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

View File

@ -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<Integer> 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<Integer> 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<Integer> maskedIPSet(Hash peer, RouterInfo pinfo, int mask) {
Set<Integer> rv = new HashSet(2);
byte[] commIP = _context.commSystem().getIP(peer);
if (commIP != null)
rv.add(maskedIP(commIP, mask));
if (pinfo == null)
return rv;
Collection<RouterAddress> 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<Hash> _sorted;
private final List<Hash> _floodfillMatches;

View File

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

View File

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