From 8226e9297338b7a6a70d4d4c20a9652f1b79647a Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Wed, 16 Dec 2015 14:37:40 +0000 Subject: [PATCH] Profiles: Don't use same family in a tunnel Reduce IPv6 mask from 8 to 6 --- .../router/peermanager/ProfileOrganizer.java | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index ea800858bc..5e6e2f7a92 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -17,7 +17,7 @@ import java.util.TreeSet; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; -import net.i2p.crypto.SHA256Generator; +import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.router.RouterAddress; import net.i2p.data.router.RouterInfo; @@ -1234,12 +1234,15 @@ public class ProfileOrganizer { } /** + * + * As of 0.9.24, checks for a netdb family match as well, unless mask == 0. + * * @param mask 0-4 Number of bytes to match to determine if peers in the same IP range should * not be in the same tunnel. 0 = disable check; 1 = /8; 2 = /16; 3 = /24; 4 = exact IP match */ private void locked_selectPeers(Map<Hash, PeerProfile> peers, int howMany, Set<Hash> toExclude, Set<Hash> matches, int mask) { List<Hash> all = new ArrayList<Hash>(peers.keySet()); - Set<Integer> IPSet = new HashSet<Integer>(8); + Set<String> IPSet = new HashSet<String>(8); // use RandomIterator to avoid shuffling the whole thing for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) { Hash peer = iter.next(); @@ -1265,11 +1268,14 @@ public class ProfileOrganizer { /** * Does the peer's IP address NOT match the IP address of any peer already in the set, * on any transport, within a given mask? + * + * As of 0.9.24, checks for a netdb family match as well. + * * @param mask is 1-4 (number of bytes to match) * @param IPMatches all IPs so far, modified by this routine */ - private boolean notRestricted(Hash peer, Set<Integer> IPSet, int mask) { - Set<Integer> peerIPs = maskedIPSet(peer, mask); + private boolean notRestricted(Hash peer, Set<String> IPSet, int mask) { + Set<String> peerIPs = maskedIPSet(peer, mask); if (containsAny(IPSet, peerIPs)) return false; IPSet.addAll(peerIPs); @@ -1280,10 +1286,12 @@ public class ProfileOrganizer { * The Set of IPs for this peer, with a given mask. * Includes the comm system's record of the IP, and all netDb addresses. * + * As of 0.9.24, returned set will include netdb family as well. + * * @return an opaque set of masked IPs for this peer */ - private Set<Integer> maskedIPSet(Hash peer, int mask) { - Set<Integer> rv = new HashSet<Integer>(4); + private Set<String> maskedIPSet(Hash peer, int mask) { + Set<String> rv = new HashSet<String>(4); byte[] commIP = _context.commSystem().getIP(peer); if (commIP != null) rv.add(maskedIP(commIP, mask)); @@ -1296,31 +1304,40 @@ public class ProfileOrganizer { if (pib == null) continue; rv.add(maskedIP(pib, mask)); } + String family = pinfo.getOption("family"); + if (family != null) { + // TODO should KNDF put a family-verified indicator in the RI, + // after checking the sig, or does it matter? + // What's the threat here of not avoid ding a router + // falsely claiming to be in the family? + // Prefix with something so an IP can't be spoofed + rv.add('x' + family); + } return rv; } /** * generate an arbitrary unique value for this ip/mask (mask = 1-4) - * If IPv6, force mask = 8. + * If IPv6, force mask = 6. */ - private static Integer maskedIP(byte[] ip, int mask) { - int rv = ip[0]; + private static String maskedIP(byte[] ip, int mask) { + final StringBuilder buf = new StringBuilder(1 + (mask*2)); + final char delim; if (ip.length == 16) { - for (int i = 1; i < 8; i++) { - rv <<= i * 4; - rv ^= ip[i]; - } + mask = 6; + delim = ':'; } else { - for (int i = 1; i < mask; i++) { - rv <<= 8; - rv ^= ip[i]; - } + delim = '.'; } - return Integer.valueOf(rv); + buf.append(delim); + buf.append(Long.toHexString(DataHelper.fromLong(ip, 0, mask))); + return buf.toString(); } /** does a contain any of the elements in b? */ private static <T> boolean containsAny(Set<T> a, Set<T> b) { + if (a.isEmpty() || b.isEmpty()) + return false; for (T o : b) { if (a.contains(o)) return true; -- GitLab