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 peer non-null
* @param mask is 1-4 (number of bytes to match)
*/
public MaskedIPSet(RouterContext ctx, Hash peer, int mask) {
this(ctx, peer, ctx.netDb().lookupRouterInfoLocally(peer), mask);
}
/**
* 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 pinfo may be null
* @param mask is 1-4 (number of bytes to match)
*/
public MaskedIPSet(RouterContext ctx, RouterInfo pinfo, int mask) {
this(ctx, pinfo != null ? pinfo.getHash() : null, pinfo, mask);
}
/**
* 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 pinfo may be null
* @param mask is 1-4 (number of bytes to match)
*/
public MaskedIPSet(RouterContext ctx, Hash peer, RouterInfo pinfo, int mask) {
super(4);
if (pinfo == null)
return;
byte[] commIP = ctx.commSystem().getIP(peer);
if (commIP != null)
add(maskedIP(commIP, mask));
Collection<RouterAddress> paddr = pinfo.getAddresses();
for (RouterAddress pa : paddr) {
byte[] pib = pa.getIP();
if (pib == null) continue;
add(maskedIP(pib, mask));
// Routers with a common port may be run
// by a single entity with a common configuration
int port = pa.getPort();
if (port > 0)
add("p" + port);
if (pa.getCost() == 2 && "NTCP".equals(pa.getTransportStyle()))
add("=cost2");
}
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;
}
}