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
|
2016-11-10 zzz
|
||||||
* Transport: Use NTCP for some outbound connections even before
|
* Transport: Use NTCP for some outbound connections even before
|
||||||
SSU minimums are met (ticket #1835)
|
SSU minimums are met (ticket #1835)
|
||||||
|
@ -18,7 +18,7 @@ public class RouterVersion {
|
|||||||
/** deprecated */
|
/** deprecated */
|
||||||
public final static String ID = "Monotone";
|
public final static String ID = "Monotone";
|
||||||
public final static String VERSION = CoreVersion.VERSION;
|
public final static String VERSION = CoreVersion.VERSION;
|
||||||
public final static long BUILD = 8;
|
public final static long BUILD = 9;
|
||||||
|
|
||||||
/** for example "-test" */
|
/** for example "-test" */
|
||||||
public final static String EXTRA = "";
|
public final static String EXTRA = "";
|
||||||
|
@ -24,6 +24,7 @@ import net.i2p.data.router.RouterInfo;
|
|||||||
import net.i2p.router.NetworkDatabaseFacade;
|
import net.i2p.router.NetworkDatabaseFacade;
|
||||||
import net.i2p.router.RouterContext;
|
import net.i2p.router.RouterContext;
|
||||||
import net.i2p.router.tunnel.pool.TunnelPeerSelector;
|
import net.i2p.router.tunnel.pool.TunnelPeerSelector;
|
||||||
|
import net.i2p.router.util.MaskedIPSet;
|
||||||
import net.i2p.router.util.RandomIterator;
|
import net.i2p.router.util.RandomIterator;
|
||||||
import net.i2p.stat.Rate;
|
import net.i2p.stat.Rate;
|
||||||
import net.i2p.stat.RateStat;
|
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) {
|
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());
|
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
|
// use RandomIterator to avoid shuffling the whole thing
|
||||||
for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
|
for (Iterator<Hash> iter = new RandomIterator<Hash>(all); (matches.size() < howMany) && iter.hasNext(); ) {
|
||||||
Hash peer = iter.next();
|
Hash peer = iter.next();
|
||||||
@ -1277,77 +1278,14 @@ public class ProfileOrganizer {
|
|||||||
* @param mask is 1-4 (number of bytes to match)
|
* @param mask is 1-4 (number of bytes to match)
|
||||||
* @param IPMatches all IPs so far, modified by this routine
|
* @param IPMatches all IPs so far, modified by this routine
|
||||||
*/
|
*/
|
||||||
private boolean notRestricted(Hash peer, Set<String> IPSet, int mask) {
|
private boolean notRestricted(Hash peer, MaskedIPSet IPSet, int mask) {
|
||||||
Set<String> peerIPs = maskedIPSet(peer, mask);
|
Set<String> peerIPs = new MaskedIPSet(_context, peer, mask);
|
||||||
if (containsAny(IPSet, peerIPs))
|
if (IPSet.containsAny(peerIPs))
|
||||||
return false;
|
return false;
|
||||||
IPSet.addAll(peerIPs);
|
IPSet.addAll(peerIPs);
|
||||||
return true;
|
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 randomKey used for deterministic random partitioning into subtiers
|
||||||
* @param subTierMode 2-7:
|
* @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