forked from I2P_Developers/i2p.i2p
Profiles: Pull same-IP detection into a utility class, for use by netdb
This commit is contained in:
34
history.txt
34
history.txt
@ -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)
|
||||
|
@ -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 = "";
|
||||
|
@ -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:
|
||||
|
92
router/java/src/net/i2p/router/util/MaskedIPSet.java
Normal file
92
router/java/src/net/i2p/router/util/MaskedIPSet.java
Normal 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user