Profiles: Pull same-IP detection into a utility class, for use by netdb

This commit is contained in:
zzz
2016-11-16 18:05:40 +00:00
parent 37d3204e43
commit 68e5fd6d08
4 changed files with 132 additions and 68 deletions

View File

@ -1,3 +1,37 @@
2016-11-16 zzz
* Console: Remove dead home page links (ticket #1882)
* Profiles: Pull same-IP detection into a utility class
* Router: Add methods to verify and track members of our family
2016-11-15 zzz
* Certs: Add Let's Encrypt ISRG Root X1 cert
2016-11-14 zzz
* Logs: Fix output of dup message after 30 minutes
2016-11-13 zzz
* Console: Add initial news to bottom of news page (ticket #1153)
* i2psnark: Periodically DHT nodes (ticket #1328)
* UPnP:
- Prevent exception on bad HTTP header (ticket #1480)
- Prevent NPE on socket creation fail (tickets #728, #1681)
2016-11-12 zzz
* Console:
- Fix inadvertent config save when clicking sidebar
buttons on /configstats
- Add IPv6 firewalled setting on /confignet
* I2CP: Reduce error level on session closed while signing LS (ticket #1606)
* JRobin: Move DeallocationHelper logging from wrapper log to router log
* Profiles: Periodically save, delete old ones after saving (ticket #1328)
* Susimail:
- Add logout button to more pages (ticket #1374)
- Fix nonce error on login after logout
- Fix internal error after cancel button on settings form when not logged in
2016-11-11 zzz
* Build: Truncate history.txt bundled in installers
2016-11-10 zzz
* Transport: Use NTCP for some outbound connections even before
SSU minimums are met (ticket #1835)

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 = 8;
public final static long BUILD = 9;
/** for example "-test" */
public final static String EXTRA = "";

View File

@ -24,6 +24,7 @@ import net.i2p.data.router.RouterInfo;
import net.i2p.router.NetworkDatabaseFacade;
import net.i2p.router.RouterContext;
import net.i2p.router.tunnel.pool.TunnelPeerSelector;
import net.i2p.router.util.MaskedIPSet;
import net.i2p.router.util.RandomIterator;
import net.i2p.stat.Rate;
import net.i2p.stat.RateStat;
@ -1245,7 +1246,7 @@ public class ProfileOrganizer {
*/
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<String> IPSet = new HashSet<String>(8);
MaskedIPSet IPSet = new MaskedIPSet(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();
@ -1277,77 +1278,14 @@ public class ProfileOrganizer {
* @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<String> IPSet, int mask) {
Set<String> peerIPs = maskedIPSet(peer, mask);
if (containsAny(IPSet, peerIPs))
private boolean notRestricted(Hash peer, MaskedIPSet IPSet, int mask) {
Set<String> peerIPs = new MaskedIPSet(_context, peer, mask);
if (IPSet.containsAny(peerIPs))
return false;
IPSet.addAll(peerIPs);
return true;
}
/**
* 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<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));
RouterInfo pinfo = _context.netDb().lookupRouterInfoLocally(peer);
if (pinfo == null)
return rv;
Collection<RouterAddress> paddr = pinfo.getAddresses();
for (RouterAddress pa : paddr) {
byte[] pib = pa.getIP();
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 = 6.
*/
private static String maskedIP(byte[] ip, int mask) {
final StringBuilder buf = new StringBuilder(1 + (mask*2));
final char delim;
if (ip.length == 16) {
mask = 6;
delim = ':';
} else {
delim = '.';
}
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;
}
return false;
}
/**
* @param randomKey used for deterministic random partitioning into subtiers
* @param subTierMode 2-7:

View File

@ -0,0 +1,92 @@
package net.i2p.router.util;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.data.router.RouterAddress;
import net.i2p.data.router.RouterInfo;
import net.i2p.router.RouterContext;
/**
* Used for detection of routers with matching IPs or family.
* Moved out of ProfileOrganizer for use in netdb also.
*
* @since 0.9.28
*/
public class MaskedIPSet extends HashSet<String> {
public MaskedIPSet() {
super();
}
public MaskedIPSet(int initialCapacity) {
super(initialCapacity);
}
/**
* 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.
*
* @param mask is 1-4 (number of bytes to match)
* @return an opaque set of masked IPs for this peer
*/
public MaskedIPSet(RouterContext ctx, Hash peer, int mask) {
super(4);
byte[] commIP = ctx.commSystem().getIP(peer);
if (commIP != null)
add(maskedIP(commIP, mask));
RouterInfo pinfo = ctx.netDb().lookupRouterInfoLocally(peer);
if (pinfo == null)
return;
Collection<RouterAddress> paddr = pinfo.getAddresses();
for (RouterAddress pa : paddr) {
byte[] pib = pa.getIP();
if (pib == null) continue;
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
add('x' + family);
}
}
/**
* generate an arbitrary unique value for this ip/mask (mask = 1-4)
* If IPv6, force mask = 6.
* @param mask is 1-4 (number of bytes to match)
*/
private static String maskedIP(byte[] ip, int mask) {
final StringBuilder buf = new StringBuilder(1 + (mask*2));
final char delim;
if (ip.length == 16) {
mask = 6;
delim = ':';
} else {
delim = '.';
}
buf.append(delim);
buf.append(Long.toHexString(DataHelper.fromLong(ip, 0, mask)));
return buf.toString();
}
/** does this contain any of the elements in b? */
public boolean containsAny(Set<String> b) {
if (isEmpty() || b.isEmpty())
return false;
for (String s : b) {
if (contains(s))
return true;
}
return false;
}
}