forked from I2P_Developers/i2p.i2p
merge of '8bf9850eb3fe4fcfb63053838a188969b7ba9c5b'
and 'a40ea9b5f7545281195f00a80e31ae879197e76b'
This commit is contained in:
@@ -78,6 +78,8 @@
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Main-Class" value="net.i2p.router.CommandLine" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
<attribute name="X-Compile-Source-JDK" value="${javac.version}" />
|
||||
<attribute name="X-Compile-Target-JDK" value="${javac.version}" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
@@ -248,6 +248,10 @@ public class Blocklist {
|
||||
* hostname (DNS looked up at list readin time, not dynamically, so may not be much use)
|
||||
* 44-byte Base64 router hash
|
||||
*
|
||||
* Acceptable formats (IPV6 only):
|
||||
* comment:IPv6 (must replace : with ; e.g. abcd;1234;0;12;;ff)
|
||||
* IPv6 (must replace : with ; e.g. abcd;1234;0;12;;ff)
|
||||
*
|
||||
* No whitespace allowed after the last ':'.
|
||||
*
|
||||
* For further information and downloads:
|
||||
@@ -290,10 +294,14 @@ public class Blocklist {
|
||||
continue;
|
||||
}
|
||||
byte[] ip1 = e.ip1;
|
||||
byte[] ip2 = e.ip2;
|
||||
|
||||
store(ip1, ip2, count++);
|
||||
ipcount += 1 + toInt(ip2) - toInt(ip1); // includes dups, oh well
|
||||
if (ip1.length == 4) {
|
||||
byte[] ip2 = e.ip2;
|
||||
store(ip1, ip2, count++);
|
||||
ipcount += 1 + toInt(ip2) - toInt(ip1); // includes dups, oh well
|
||||
} else {
|
||||
// IPv6
|
||||
add(ip1);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
@@ -393,25 +401,25 @@ public class Blocklist {
|
||||
int start2 = -1;
|
||||
int mask = -1;
|
||||
String comment = null;
|
||||
int index = buf.indexOf("#");
|
||||
int index = buf.indexOf('#');
|
||||
if (index == 0)
|
||||
return null; // comment
|
||||
index = buf.lastIndexOf(":");
|
||||
index = buf.lastIndexOf(':');
|
||||
if (index >= 0) {
|
||||
comment = buf.substring(0, index);
|
||||
start1 = index + 1;
|
||||
}
|
||||
if (end1 - start1 == 44 && buf.substring(start1).indexOf(".") < 0) {
|
||||
if (end1 - start1 == 44 && buf.substring(start1).indexOf('.') < 0) {
|
||||
byte b[] = Base64.decode(buf.substring(start1));
|
||||
if (b != null)
|
||||
return new Entry(comment, Hash.create(b), null, null);
|
||||
}
|
||||
index = buf.indexOf("-", start1);
|
||||
index = buf.indexOf('-', start1);
|
||||
if (index >= 0) {
|
||||
end1 = index;
|
||||
start2 = index + 1;
|
||||
} else {
|
||||
index = buf.indexOf("/", start1);
|
||||
index = buf.indexOf('/', start1);
|
||||
if (index >= 0) {
|
||||
end1 = index;
|
||||
mask = index + 1;
|
||||
@@ -420,11 +428,14 @@ public class Blocklist {
|
||||
if (end1 - start1 <= 0)
|
||||
return null; // blank
|
||||
try {
|
||||
InetAddress pi = InetAddress.getByName(buf.substring(start1, end1));
|
||||
String sip = buf.substring(start1, end1);
|
||||
// IPv6
|
||||
sip = sip.replace(';', ':');
|
||||
InetAddress pi = InetAddress.getByName(sip);
|
||||
if (pi == null) return null;
|
||||
ip1 = pi.getAddress();
|
||||
if (ip1.length != 4)
|
||||
throw new UnknownHostException();
|
||||
//if (ip1.length != 4)
|
||||
// throw new UnknownHostException();
|
||||
if (start2 >= 0) {
|
||||
pi = InetAddress.getByName(buf.substring(start2));
|
||||
if (pi == null) return null;
|
||||
@@ -462,16 +473,16 @@ public class Blocklist {
|
||||
ip2 = ip1;
|
||||
}
|
||||
} catch (UnknownHostException uhe) {
|
||||
if (shouldLog && _log.shouldLog(Log.ERROR))
|
||||
_log.error("Format error in the blocklist file: " + buf);
|
||||
if (shouldLog)
|
||||
_log.logAlways(Log.WARN, "Format error in the blocklist file: " + buf);
|
||||
return null;
|
||||
} catch (NumberFormatException nfe) {
|
||||
if (shouldLog && _log.shouldLog(Log.ERROR))
|
||||
_log.error("Format error in the blocklist file: " + buf);
|
||||
if (shouldLog)
|
||||
_log.logAlways(Log.WARN, "Format error in the blocklist file: " + buf);
|
||||
return null;
|
||||
} catch (IndexOutOfBoundsException ioobe) {
|
||||
if (shouldLog && _log.shouldLog(Log.ERROR))
|
||||
_log.error("Format error in the blocklist file: " + buf);
|
||||
if (shouldLog)
|
||||
_log.logAlways(Log.WARN, "Format error in the blocklist file: " + buf);
|
||||
return null;
|
||||
}
|
||||
return new Entry(comment, null, ip1, ip2);
|
||||
@@ -743,6 +754,9 @@ public class Blocklist {
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* IPv4 only
|
||||
*/
|
||||
private void store(byte ip1[], byte ip2[], int idx) {
|
||||
_blocklist[idx] = toEntry(ip1, ip2);
|
||||
}
|
||||
@@ -1035,10 +1049,16 @@ public class Blocklist {
|
||||
}
|
||||
|
||||
/****
|
||||
public static void main(String args[]) {
|
||||
Blocklist b = new Blocklist();
|
||||
if ( (args != null) && (args.length == 1) )
|
||||
b.readBlocklistFile(args[0]);
|
||||
public static void main(String args[]) throws Exception {
|
||||
Blocklist b = new Blocklist(new Router().getContext());
|
||||
if (args != null && args.length == 1) {
|
||||
File f = new File(args[0]);
|
||||
b.allocate(Collections.singletonList(f));
|
||||
int count = b.readBlocklistFile(f, 0);
|
||||
b.merge(count);
|
||||
Writer w = new java.io.OutputStreamWriter(System.out);
|
||||
b.renderStatusHTML(w);
|
||||
}
|
||||
System.out.println("Saved " + b._blocklistSize + " records");
|
||||
String tests[] = {"0.0.0.0", "0.0.0.1", "0.0.0.2", "0.0.0.255", "1.0.0.0",
|
||||
"3.3.3.3", "77.1.2.3", "127.0.0.0", "127.127.127.127", "128.0.0.0",
|
||||
|
||||
@@ -23,7 +23,7 @@ public class CommandLine extends net.i2p.util.CommandLine {
|
||||
"net.i2p.router.tasks.CryptoChecker",
|
||||
"net.i2p.router.transport.GeoIPv6",
|
||||
"net.i2p.router.transport.udp.MTU",
|
||||
//"net.i2p.router.transport.UPnP"
|
||||
"net.i2p.router.transport.UPnP"
|
||||
});
|
||||
|
||||
protected CommandLine() {}
|
||||
|
||||
@@ -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 = 6;
|
||||
public final static long BUILD = 9;
|
||||
|
||||
/** for example "-test" */
|
||||
public final static String EXTRA = "";
|
||||
|
||||
@@ -329,14 +329,14 @@ class ClientMessageEventListener implements I2CPMessageReader.I2CPMessageEventLi
|
||||
pw = props.getProperty("i2cp.password");
|
||||
}
|
||||
if (user == null || user.length() == 0 || pw == null || pw.length() == 0) {
|
||||
_log.error("I2CP auth failed");
|
||||
_log.logAlways(Log.WARN, "I2CP authentication failed");
|
||||
_runner.disconnectClient("Authorization required, specify i2cp.username and i2cp.password in options");
|
||||
_authorized = false;
|
||||
return false;
|
||||
}
|
||||
PasswordManager mgr = new PasswordManager(_context);
|
||||
if (!mgr.checkHash(PROP_AUTH, user, pw)) {
|
||||
_log.error("I2CP auth failed user: " + user);
|
||||
_log.logAlways(Log.WARN, "I2CP authentication failed, user: " + user);
|
||||
_runner.disconnectClient("Authorization failed, user = " + user);
|
||||
_authorized = false;
|
||||
return false;
|
||||
|
||||
@@ -10,6 +10,7 @@ import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.cert.X509CRL;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -44,6 +45,7 @@ public class FamilyKeyCrypto {
|
||||
private final Log _log;
|
||||
private final Map<Hash, String> _verified;
|
||||
private final Set<Hash> _negativeCache;
|
||||
private final Set<Hash> _ourFamily;
|
||||
// following for verification only, otherwise null
|
||||
private final String _fname;
|
||||
private final SigningPrivateKey _privkey;
|
||||
@@ -82,13 +84,15 @@ public class FamilyKeyCrypto {
|
||||
_fname = _context.getProperty(PROP_FAMILY_NAME);
|
||||
if (_fname != null) {
|
||||
if (_fname.contains("/") || _fname.contains("\\") ||
|
||||
_fname.contains("..") || (new File(_fname)).isAbsolute())
|
||||
throw new GeneralSecurityException("Illegal family name");
|
||||
_fname.contains("..") || (new File(_fname)).isAbsolute() ||
|
||||
_fname.length() <= 0)
|
||||
throw new GeneralSecurityException("Illegal family name: " + _fname);
|
||||
}
|
||||
_privkey = (_fname != null) ? initialize() : null;
|
||||
_pubkey = (_privkey != null) ? _privkey.toPublic() : null;
|
||||
_verified = new ConcurrentHashMap<Hash, String>(4);
|
||||
_negativeCache = new ConcurrentHashSet<Hash>(4);
|
||||
_ourFamily = (_privkey != null) ? new ConcurrentHashSet<Hash>(4) : Collections.<Hash>emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,6 +148,35 @@ public class FamilyKeyCrypto {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we have a valid family?
|
||||
* @since 0.9.28
|
||||
*/
|
||||
public boolean hasFamily() {
|
||||
return _pubkey != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get verified members of our family.
|
||||
* Will not contain ourselves.
|
||||
*
|
||||
* @return non-null, not a copy, do not modify
|
||||
* @since 0.9.28
|
||||
*/
|
||||
public Set<Hash> getOurFamily() {
|
||||
return _ourFamily;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get our family name.
|
||||
*
|
||||
* @return name or null
|
||||
* @since 0.9.28
|
||||
*/
|
||||
public String getOurFamilyName() {
|
||||
return _fname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the family signature in a RouterInfo.
|
||||
* @return true if good sig or if no family specified at all
|
||||
@@ -152,6 +185,44 @@ public class FamilyKeyCrypto {
|
||||
String name = ri.getOption(OPT_NAME);
|
||||
if (name == null)
|
||||
return true;
|
||||
return verify(ri, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the family in a RouterInfo matches ours and the signature is good.
|
||||
* Returns false if we don't have a family and sig, or they don't.
|
||||
* Returns false for ourselves.
|
||||
*
|
||||
* @return true if family matches with good sig
|
||||
* @since 0.9.28
|
||||
*/
|
||||
public boolean verifyOurFamily(RouterInfo ri) {
|
||||
if (_pubkey == null)
|
||||
return false;
|
||||
String name = ri.getOption(OPT_NAME);
|
||||
if (!_fname.equals(name))
|
||||
return false;
|
||||
Hash h = ri.getHash();
|
||||
if (_ourFamily.contains(h))
|
||||
return true;
|
||||
if (h.equals(_context.routerHash()))
|
||||
return false;
|
||||
boolean rv = verify(ri, name);
|
||||
if (rv) {
|
||||
_ourFamily.add(h);
|
||||
_log.logAlways(Log.INFO, "Found and verified member of our family (" + _fname + "): " + h);
|
||||
} else {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Found spoofed member of our family (" + _fname + "): " + h);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the family in a RouterInfo, name already retrieved
|
||||
* @since 0.9.28
|
||||
*/
|
||||
private boolean verify(RouterInfo ri, String name) {
|
||||
Hash h = ri.getHash();
|
||||
String ssig = ri.getOption(OPT_SIG);
|
||||
if (ssig == null) {
|
||||
|
||||
@@ -19,6 +19,7 @@ import net.i2p.router.MessageSelector;
|
||||
import net.i2p.router.ReplyJob;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.router.TunnelInfo;
|
||||
import net.i2p.router.util.MaskedIPSet;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -39,11 +40,13 @@ class FloodfillVerifyStoreJob extends JobImpl {
|
||||
private final boolean _isRouterInfo;
|
||||
private MessageWrapper.WrappedMessage _wrappedMessage;
|
||||
private final Set<Hash> _ignore;
|
||||
private final MaskedIPSet _ipSet;
|
||||
|
||||
private static final int START_DELAY = 18*1000;
|
||||
private static final int START_DELAY_RAND = 9*1000;
|
||||
private static final int VERIFY_TIMEOUT = 20*1000;
|
||||
private static final int MAX_PEERS_TO_TRY = 4;
|
||||
private static final int IP_CLOSE_BYTES = 3;
|
||||
|
||||
/**
|
||||
* Delay a few seconds, then start the verify
|
||||
@@ -60,7 +63,10 @@ class FloodfillVerifyStoreJob extends JobImpl {
|
||||
_facade = facade;
|
||||
_ignore = new HashSet<Hash>(MAX_PEERS_TO_TRY);
|
||||
if (sentTo != null) {
|
||||
_ipSet = new MaskedIPSet(ctx, sentTo, IP_CLOSE_BYTES);
|
||||
_ignore.add(_sentTo);
|
||||
} else {
|
||||
_ipSet = new MaskedIPSet(4);
|
||||
}
|
||||
// wait some time before trying to verify the store
|
||||
getTiming().setStartAfter(ctx.clock().now() + START_DELAY + ctx.random().nextInt(START_DELAY_RAND));
|
||||
@@ -188,10 +194,19 @@ class FloodfillVerifyStoreJob extends JobImpl {
|
||||
break;
|
||||
Hash peer = peers.get(0);
|
||||
RouterInfo ri = _facade.lookupRouterInfoLocally(peer);
|
||||
if (ri != null && StoreJob.supportsCert(ri, keyCert))
|
||||
return peer;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getJobId() + ": Skipping verify w/ router that doesn't support key certs " + peer);
|
||||
if (ri != null && StoreJob.supportsCert(ri, keyCert)) {
|
||||
Set<String> peerIPs = new MaskedIPSet(getContext(), ri, IP_CLOSE_BYTES);
|
||||
if (!_ipSet.containsAny(peerIPs)) {
|
||||
_ipSet.addAll(peerIPs);
|
||||
return peer;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getJobId() + ": Skipping verify w/ router too close to the store " + peer);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getJobId() + ": Skipping verify w/ router that doesn't support key certs " + peer);
|
||||
}
|
||||
_ignore.add(peer);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.router.RouterInfo;
|
||||
@@ -43,6 +44,9 @@ class PeerManager {
|
||||
private final Map<Character, Set<Hash>> _peersByCapability;
|
||||
/** value strings are lower case */
|
||||
private final Map<Hash, String> _capabilitiesByPeer;
|
||||
private final AtomicBoolean _storeLock = new AtomicBoolean();
|
||||
private volatile long _lastStore;
|
||||
|
||||
private static final long REORGANIZE_TIME = 45*1000;
|
||||
private static final long REORGANIZE_TIME_MEDIUM = 123*1000;
|
||||
/**
|
||||
@@ -52,6 +56,8 @@ class PeerManager {
|
||||
* Rate contained in the profile, as the Rates must be coalesced.
|
||||
*/
|
||||
private static final long REORGANIZE_TIME_LONG = 351*1000;
|
||||
private static final long STORE_TIME = 19*60*60*1000;
|
||||
private static final long EXPIRE_AGE = 3*24*60*60*1000;
|
||||
|
||||
public static final String TRACKED_CAPS = "" +
|
||||
FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL +
|
||||
@@ -97,11 +103,14 @@ class PeerManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorganize the profiles. Also periodically store them,
|
||||
* and delete very old ones.
|
||||
*
|
||||
* This takes too long to run on the SimpleTimer2 queue
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private class ReorgThread extends I2PThread {
|
||||
private SimpleTimer2.TimedEvent _event;
|
||||
private final SimpleTimer2.TimedEvent _event;
|
||||
|
||||
public ReorgThread(SimpleTimer2.TimedEvent event) {
|
||||
super("PeerManager Reorg");
|
||||
@@ -117,6 +126,19 @@ class PeerManager {
|
||||
_log.log(Log.CRIT, "Error evaluating profiles", t);
|
||||
}
|
||||
long orgtime = System.currentTimeMillis() - start;
|
||||
if (_lastStore == 0) {
|
||||
_lastStore = start;
|
||||
} else if (start - _lastStore > STORE_TIME) {
|
||||
_lastStore = start;
|
||||
try {
|
||||
_log.debug("Periodic profile store start");
|
||||
storeProfiles();
|
||||
_persistenceHelper.deleteOldProfiles(EXPIRE_AGE);
|
||||
_log.debug("Periodic profile store end");
|
||||
} catch (Throwable t) {
|
||||
_log.log(Log.CRIT, "Error storing profiles", t);
|
||||
}
|
||||
}
|
||||
long uptime = _context.router().getUptime();
|
||||
long delay;
|
||||
if (orgtime > 1000 || uptime > 2*60*60*1000)
|
||||
@@ -130,9 +152,16 @@ class PeerManager {
|
||||
}
|
||||
|
||||
void storeProfiles() {
|
||||
Set<Hash> peers = selectPeers();
|
||||
for (Hash peer : peers) {
|
||||
storeProfile(peer);
|
||||
// lock in case shutdown bumps into periodic store
|
||||
if (!_storeLock.compareAndSet(false, true))
|
||||
return;
|
||||
try {
|
||||
Set<Hash> peers = selectPeers();
|
||||
for (Hash peer : peers) {
|
||||
storeProfile(peer);
|
||||
}
|
||||
} finally {
|
||||
_storeLock.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -229,6 +229,26 @@ class ProfilePersistenceHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete profile files with timestamps older than 'age' ago
|
||||
* @since 0.9.28
|
||||
*/
|
||||
public void deleteOldProfiles(long age) {
|
||||
long cutoff = System.currentTimeMillis() - age;
|
||||
List<File> files = selectFiles();
|
||||
int i = 0;
|
||||
for (File f : files) {
|
||||
if (!f.isFile())
|
||||
continue;
|
||||
if (f.lastModified() < cutoff) {
|
||||
i++;
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Deleted " + i + " old profiles");
|
||||
}
|
||||
|
||||
private boolean isExpired(long lastSentToSuccessfully) {
|
||||
long timeSince = _context.clock().now() - lastSentToSuccessfully;
|
||||
return (timeSince > EXPIRE_AGE);
|
||||
|
||||
@@ -49,17 +49,23 @@ public class OOMListener implements I2PThread.OOMEventListener {
|
||||
log.log(Log.CRIT, "Thread ran out of memory, shutting down I2P", oom);
|
||||
log.log(Log.CRIT, "free mem: " + Runtime.getRuntime().freeMemory() +
|
||||
" total mem: " + Runtime.getRuntime().totalMemory());
|
||||
// Can't find any System property or wrapper property that gives
|
||||
// you the actual config file path, have to guess
|
||||
String path;
|
||||
if (SystemVersion.isLinuxService()) {
|
||||
path = "/etc/i2p";
|
||||
} else {
|
||||
path = _context.getBaseDir().toString();
|
||||
}
|
||||
if (_context.hasWrapper()) {
|
||||
// Can't find any System property or wrapper property that gives
|
||||
// you the actual config file path, have to guess
|
||||
String path;
|
||||
if (SystemVersion.isLinuxService()) {
|
||||
path = "/etc/i2p";
|
||||
} else {
|
||||
path = _context.getBaseDir().toString();
|
||||
}
|
||||
log.log(Log.CRIT, "To prevent future shutdowns, increase wrapper.java.maxmemory in " +
|
||||
path + File.separatorChar + "wrapper.config");
|
||||
} else if (!SystemVersion.isWindows()) {
|
||||
log.log(Log.CRIT, "To prevent future shutdowns, increase MAXMEMOPT in " +
|
||||
path + File.separatorChar + "runplain.sh or /usr/bin/i2prouter-nowrapper");
|
||||
} else {
|
||||
log.log(Log.CRIT, "To prevent future shutdowns, run the restartable version of I2P, and increase wrapper.java.maxmemory in " +
|
||||
path + File.separatorChar + "wrapper.config");
|
||||
}
|
||||
} catch (OutOfMemoryError oome) {}
|
||||
try {
|
||||
|
||||
@@ -11,6 +11,7 @@ package net.i2p.router.transport;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -165,7 +166,7 @@ public class TransportManager implements TransportEventListener {
|
||||
// so that NTCP may bind early
|
||||
int port = udp.getRequestedPort();
|
||||
if (port > 0)
|
||||
ntcp.externalAddressReceived(SOURCE_CONFIG, null, port);
|
||||
ntcp.externalAddressReceived(SOURCE_CONFIG, (byte[]) null, port);
|
||||
}
|
||||
}
|
||||
if (_transports.isEmpty())
|
||||
@@ -182,15 +183,52 @@ public class TransportManager implements TransportEventListener {
|
||||
*/
|
||||
private void initializeAddress(Transport t) {
|
||||
Set<String> ipset = Addresses.getAddresses(false, true); // non-local, include IPv6
|
||||
//
|
||||
// Avoid IPv6 temporary addresses if we have a non-temporary one
|
||||
//
|
||||
boolean hasNonTempV6Address = false;
|
||||
List<InetAddress> addresses = new ArrayList<InetAddress>(4);
|
||||
List<Inet6Address> tempV6Addresses = new ArrayList<Inet6Address>(4);
|
||||
for (String ips : ipset) {
|
||||
try {
|
||||
InetAddress ia = InetAddress.getByName(ips);
|
||||
byte[] ip = ia.getAddress();
|
||||
t.externalAddressReceived(SOURCE_INTERFACE, ip, 0);
|
||||
InetAddress addr = InetAddress.getByName(ips);
|
||||
if (ips.contains(":") && (addr instanceof Inet6Address)) {
|
||||
Inet6Address v6addr = (Inet6Address) addr;
|
||||
// getAddresses(false, true) will not return deprecated addresses
|
||||
//if (Addresses.isDeprecated(v6addr)) {
|
||||
// if (_log.shouldWarn())
|
||||
// _log.warn("Not binding to deprecated temporary address " + bt);
|
||||
// continue;
|
||||
//}
|
||||
if (Addresses.isTemporary(v6addr)) {
|
||||
// Save temporary addresses
|
||||
// we only use these if we don't have a non-temporary adress
|
||||
tempV6Addresses.add(v6addr);
|
||||
continue;
|
||||
}
|
||||
hasNonTempV6Address = true;
|
||||
}
|
||||
addresses.add(addr);
|
||||
} catch (UnknownHostException e) {
|
||||
_log.error("UDP failed to bind to local address", e);
|
||||
}
|
||||
}
|
||||
// we only use these if we don't have a non-temporary adress
|
||||
if (!tempV6Addresses.isEmpty()) {
|
||||
if (hasNonTempV6Address) {
|
||||
if (_log.shouldWarn()) {
|
||||
for (Inet6Address addr : tempV6Addresses) {
|
||||
_log.warn("Not binding to temporary address " + addr.getHostAddress());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addresses.addAll(tempV6Addresses);
|
||||
}
|
||||
}
|
||||
for (InetAddress ia : addresses) {
|
||||
byte[] ip = ia.getAddress();
|
||||
t.externalAddressReceived(SOURCE_INTERFACE, ip, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,8 @@ public abstract class TransportUtil {
|
||||
public static final String NTCP_IPV6_CONFIG = "i2np.ntcp.ipv6";
|
||||
public static final String SSU_IPV6_CONFIG = "i2np.udp.ipv6";
|
||||
public static final String PROP_IPV4_FIREWALLED = "i2np.ipv4.firewalled";
|
||||
/** @since 0.9.28 */
|
||||
public static final String PROP_IPV6_FIREWALLED = "i2np.ipv6.firewalled";
|
||||
|
||||
public enum IPv6Config {
|
||||
/** IPv6 disabled */
|
||||
@@ -99,12 +101,10 @@ public abstract class TransportUtil {
|
||||
* This returns true if the force-firewalled setting is configured, false otherwise.
|
||||
*
|
||||
* @param transportStyle ignored
|
||||
* @since 0.9.27
|
||||
* @since 0.9.27, implemented in 0.9.28
|
||||
*/
|
||||
public static boolean isIPv6Firewalled(RouterContext ctx, String transportStyle) {
|
||||
// TODO
|
||||
//return ctx.getBooleanProperty(PROP_IPV6_FIREWALLED);
|
||||
return false;
|
||||
return ctx.getBooleanProperty(PROP_IPV6_FIREWALLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,6 +58,8 @@ import org.freenetproject.ForwardPortStatus;
|
||||
*
|
||||
* some code has been borrowed from Limewire : @see com.limegroup.gnutella.UPnPManager
|
||||
*
|
||||
* Public only for command line usage. Not a public API, not for external use.
|
||||
*
|
||||
* @see "http://www.upnp.org/"
|
||||
* @see "http://en.wikipedia.org/wiki/Universal_Plug_and_Play"
|
||||
* @since 0.7.4
|
||||
@@ -68,7 +70,7 @@ import org.freenetproject.ForwardPortStatus;
|
||||
* TODO: Advertise the node like the MDNS plugin does
|
||||
* TODO: Implement EventListener and react on ip-change
|
||||
*/
|
||||
class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
public class UPnP extends ControlPoint implements DeviceChangeListener, EventListener {
|
||||
private final Log _log;
|
||||
private final I2PAppContext _context;
|
||||
|
||||
|
||||
@@ -150,6 +150,8 @@ public class NTCPTransport extends TransportImpl {
|
||||
//_context.statManager().createRateStat("ntcp.inboundCheckConnection", "", "ntcp", RATES);
|
||||
_context.statManager().createRateStat("ntcp.inboundEstablished", "", "ntcp", RATES);
|
||||
_context.statManager().createRateStat("ntcp.inboundEstablishedDuplicate", "", "ntcp", RATES);
|
||||
_context.statManager().createRateStat("ntcp.inboundIPv4Conn", "Inbound IPv4 NTCP Connection", "ntcp", RATES);
|
||||
_context.statManager().createRateStat("ntcp.inboundIPv6Conn", "Inbound IPv6 NTCP Connection", "ntcp", RATES);
|
||||
//_context.statManager().createRateStat("ntcp.infoMessageEnqueued", "", "ntcp", RATES);
|
||||
//_context.statManager().createRateStat("ntcp.floodInfoMessageEnqueued", "", "ntcp", RATES);
|
||||
_context.statManager().createRateStat("ntcp.invalidDH", "", "ntcp", RATES);
|
||||
@@ -213,10 +215,13 @@ public class NTCPTransport extends TransportImpl {
|
||||
synchronized (_conLock) {
|
||||
old = _conByIdent.put(peer, con);
|
||||
}
|
||||
if (con.isIPv6())
|
||||
if (con.isIPv6()) {
|
||||
_lastInboundIPv6 = con.getCreated();
|
||||
else
|
||||
_context.statManager().addRateData("ntcp.inboundIPv6Conn", 1);
|
||||
} else {
|
||||
_lastInboundIPv4 = con.getCreated();
|
||||
_context.statManager().addRateData("ntcp.inboundIPv4Conn", 1);
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
@@ -289,6 +289,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_context.statManager().createRateStat("udp.proactiveReestablish", "How long a session was idle for when we proactively reestablished it", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.dropPeerDroplist", "How many peers currently have their packets dropped outright when a new peer is added to the list?", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.dropPeerConsecutiveFailures", "How many consecutive failed sends to a peer did we attempt before giving up and reestablishing a new session (lifetime is inactivity perood)", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.inboundIPv4Conn", "Inbound IPv4 UDP Connection", "udp", RATES);
|
||||
_context.statManager().createRateStat("udp.inboundIPv6Conn", "Inbound IPv4 UDP Connection", "udp", RATES);
|
||||
// following are for PacketBuider
|
||||
//_context.statManager().createRateStat("udp.packetAuthTime", "How long it takes to encrypt and MAC a packet for sending", "udp", RATES);
|
||||
//_context.statManager().createRateStat("udp.packetAuthTimeSlow", "How long it takes to encrypt and MAC a packet for sending (when its slow)", "udp", RATES);
|
||||
@@ -780,6 +782,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
void inboundConnectionReceived(boolean isIPv6) {
|
||||
if (isIPv6) {
|
||||
_lastInboundIPv6 = _context.clock().now();
|
||||
_context.statManager().addRateData("udp.inboundIPv6Conn", 1);
|
||||
// former workaround for lack of IPv6 peer testing
|
||||
//if (_currentOurV6Address != null)
|
||||
// setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true);
|
||||
@@ -788,6 +791,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
// that we are not firewalled.
|
||||
// use OS clock since its an ordering thing, not a time thing
|
||||
_lastInboundReceivedOn = System.currentTimeMillis();
|
||||
_context.statManager().addRateData("udp.inboundIPv4Conn", 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1765,13 +1769,23 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
// (Otherwise we only talk UDP to those that are firewalled, and we will
|
||||
// never get any introducers)
|
||||
int count = _peersByIdent.size();
|
||||
if (alwaysPreferUDP() || count < _min_peers ||
|
||||
(_haveIPv6Address && count < _min_v6_peers) ||
|
||||
(introducersRequired() && _introManager.introducerCount() < MIN_INTRODUCER_POOL))
|
||||
if (alwaysPreferUDP()) {
|
||||
return _cachedBid[SLOW_PREFERRED_BID];
|
||||
else if (preferUDP())
|
||||
} else if (count < _min_peers ||
|
||||
(_haveIPv6Address && count < _min_v6_peers) ||
|
||||
(introducersRequired() && _introManager.introducerCount() < MIN_INTRODUCER_POOL)) {
|
||||
// Even if we haven't hit our minimums, give NTCP a chance some of the time.
|
||||
// This may make things work a little faster at startup
|
||||
// (especially when we have an IPv6 address and the increased minimums),
|
||||
// and if UDP is completely blocked we'll still have some connectivity.
|
||||
// TODO After some time, decide that UDP is blocked/broken and return TRANSIENT_FAIL_BID?
|
||||
if (_context.random().nextInt(4) == 0)
|
||||
return _cachedBid[SLOWEST_BID];
|
||||
else
|
||||
return _cachedBid[SLOW_PREFERRED_BID];
|
||||
} else if (preferUDP()) {
|
||||
return _cachedBid[SLOW_BID];
|
||||
else if (haveCapacity()) {
|
||||
} else if (haveCapacity()) {
|
||||
if (addr.getCost() > DEFAULT_COST)
|
||||
return _cachedBid[SLOWEST_COST_BID];
|
||||
else
|
||||
|
||||
@@ -104,7 +104,6 @@ class BloomFilterIVValidator implements IVValidator {
|
||||
return;
|
||||
// Can't find any System property or wrapper property that gives
|
||||
// you the actual config file path, have to guess
|
||||
// TODO if !SystemVersion.hasWrapper ...
|
||||
String path;
|
||||
if (SystemVersion.isLinuxService()) {
|
||||
path = "/etc/i2p";
|
||||
@@ -114,13 +113,21 @@ class BloomFilterIVValidator implements IVValidator {
|
||||
String msg =
|
||||
"Configured for " + DataHelper.formatSize(KBps *1024L) +
|
||||
"Bps share bandwidth but only " +
|
||||
DataHelper.formatSize(maxMemory) + "B available memory." +
|
||||
" Recommend increasing wrapper.java.maxmemory in " +
|
||||
path + File.separatorChar + "wrapper.config" +
|
||||
// getMaxMemory() returns significantly lower than wrapper config, so add 10%
|
||||
" to at least " + (recMaxMem * 11 / 10 / (1024*1024)) + " (MB)" +
|
||||
" if the actual share bandwidth exceeds " +
|
||||
DataHelper.formatSize(threshKBps * 1024L) + "Bps.";
|
||||
DataHelper.formatSize(maxMemory) + "B available memory.";
|
||||
if (_context.hasWrapper()) {
|
||||
msg += " Recommend increasing wrapper.java.maxmemory in " +
|
||||
path + File.separatorChar + "wrapper.config";
|
||||
} else if (!SystemVersion.isWindows()) {
|
||||
msg += " Recommend increasing MAXMEMOPT in " +
|
||||
path + File.separatorChar + "runplain.sh or /usr/bin/i2prouter-nowrapper";
|
||||
} else {
|
||||
msg += " Recommend running the restartable version of I2P, and increasing wrapper.java.maxmemory in " +
|
||||
path + File.separatorChar + "wrapper.config";
|
||||
}
|
||||
// getMaxMemory() returns significantly lower than wrapper config, so add 10%
|
||||
msg += " to at least " + (recMaxMem * 11 / 10 / (1024*1024)) + " (MB)" +
|
||||
" if the actual share bandwidth exceeds " +
|
||||
DataHelper.formatSize(threshKBps * 1024L) + "Bps.";
|
||||
System.out.println("WARN: " + msg);
|
||||
_context.logManager().getLog(BloomFilterIVValidator.class).logAlways(Log.WARN, msg);
|
||||
}
|
||||
|
||||
@@ -25,9 +25,23 @@ import net.i2p.util.VersionComparator;
|
||||
*/
|
||||
abstract class BuildRequestor {
|
||||
private static final List<Integer> ORDER = new ArrayList<Integer>(TunnelBuildMessage.MAX_RECORD_COUNT);
|
||||
private static final String MIN_VARIABLE_VERSION = "0.7.12";
|
||||
private static final boolean SEND_VARIABLE = true;
|
||||
private static final int SHORT_RECORDS = 4;
|
||||
private static final List<Integer> SHORT_ORDER = new ArrayList<Integer>(SHORT_RECORDS);
|
||||
/** 5 (~2600 bytes) fits nicely in 3 tunnel messages */
|
||||
private static final int MEDIUM_RECORDS = 5;
|
||||
private static final List<Integer> MEDIUM_ORDER = new ArrayList<Integer>(MEDIUM_RECORDS);
|
||||
static {
|
||||
for (int i = 0; i < TunnelBuildMessage.MAX_RECORD_COUNT; i++)
|
||||
for (int i = 0; i < TunnelBuildMessage.MAX_RECORD_COUNT; i++) {
|
||||
ORDER.add(Integer.valueOf(i));
|
||||
}
|
||||
for (int i = 0; i < SHORT_RECORDS; i++) {
|
||||
SHORT_ORDER.add(Integer.valueOf(i));
|
||||
}
|
||||
for (int i = 0; i < MEDIUM_RECORDS; i++) {
|
||||
MEDIUM_ORDER.add(Integer.valueOf(i));
|
||||
}
|
||||
}
|
||||
|
||||
private static final int PRIORITY = OutNetMessage.PRIORITY_MY_BUILD_REQUEST;
|
||||
@@ -223,17 +237,6 @@ abstract class BuildRequestor {
|
||||
// + "ms and dispatched in " + (System.currentTimeMillis()-beforeDispatch));
|
||||
return true;
|
||||
}
|
||||
|
||||
private static final String MIN_VARIABLE_VERSION = "0.7.12";
|
||||
/** change this to true in 0.7.13 if testing goes well */
|
||||
private static final boolean SEND_VARIABLE = true;
|
||||
/** 5 (~2600 bytes) fits nicely in 3 tunnel messages */
|
||||
private static final int SHORT_RECORDS = 5;
|
||||
private static final List<Integer> SHORT_ORDER = new ArrayList<Integer>(SHORT_RECORDS);
|
||||
static {
|
||||
for (int i = 0; i < SHORT_RECORDS; i++)
|
||||
SHORT_ORDER.add(Integer.valueOf(i));
|
||||
}
|
||||
|
||||
/** @since 0.7.12 */
|
||||
private static boolean supportsVariable(RouterContext ctx, Hash h) {
|
||||
@@ -256,7 +259,7 @@ abstract class BuildRequestor {
|
||||
Log log = ctx.logManager().getLog(BuildRequestor.class);
|
||||
long replyTunnel = 0;
|
||||
Hash replyRouter = null;
|
||||
boolean useVariable = SEND_VARIABLE && cfg.getLength() <= SHORT_RECORDS;
|
||||
boolean useVariable = SEND_VARIABLE && cfg.getLength() <= MEDIUM_RECORDS;
|
||||
if (cfg.isInbound()) {
|
||||
//replyTunnel = 0; // as above
|
||||
replyRouter = ctx.routerHash();
|
||||
@@ -295,10 +298,13 @@ abstract class BuildRequestor {
|
||||
TunnelBuildMessage msg;
|
||||
List<Integer> order;
|
||||
if (useVariable) {
|
||||
msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS);
|
||||
order = new ArrayList<Integer>(SHORT_ORDER);
|
||||
//if (log.shouldLog(Log.INFO))
|
||||
// log.info("Using new VTBM");
|
||||
if (cfg.getLength() <= SHORT_RECORDS) {
|
||||
msg = new VariableTunnelBuildMessage(ctx, SHORT_RECORDS);
|
||||
order = new ArrayList<Integer>(SHORT_ORDER);
|
||||
} else {
|
||||
msg = new VariableTunnelBuildMessage(ctx, MEDIUM_RECORDS);
|
||||
order = new ArrayList<Integer>(MEDIUM_ORDER);
|
||||
}
|
||||
} else {
|
||||
msg = new TunnelBuildMessage(ctx);
|
||||
order = new ArrayList<Integer>(ORDER);
|
||||
|
||||
106
router/java/src/net/i2p/router/util/MaskedIPSet.java
Normal file
106
router/java/src/net/i2p/router/util/MaskedIPSet.java
Normal file
@@ -0,0 +1,106 @@
|
||||
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)
|
||||
* @return an opaque set of masked IPs for this peer
|
||||
*/
|
||||
public MaskedIPSet(RouterContext ctx, Hash peer, int mask) {
|
||||
this(ctx, 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)
|
||||
* @return an opaque set of masked IPs for this peer
|
||||
*/
|
||||
public MaskedIPSet(RouterContext ctx, RouterInfo pinfo, int mask) {
|
||||
super(4);
|
||||
if (pinfo == null)
|
||||
return;
|
||||
byte[] commIP = ctx.commSystem().getIP(pinfo.getHash());
|
||||
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));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -116,6 +116,9 @@ public class HTTPHeader
|
||||
|
||||
public final static String getValue(String data, String name)
|
||||
{
|
||||
// I2P #1480 avoid IAE
|
||||
if (data.length() <= 0)
|
||||
return "";
|
||||
/* Thanks for Stephan Mehlhase (2010-10-26) */
|
||||
StringReader strReader = new StringReader(data);
|
||||
LineNumberReader lineReader = new LineNumberReader(strReader, Math.min(data.length(), MAX_LENGTH));
|
||||
|
||||
@@ -92,6 +92,9 @@ public class HTTPUSocket
|
||||
{
|
||||
if (0 < localAddr.length())
|
||||
return localAddr;
|
||||
// I2P prevent NPE #1681
|
||||
if (ssdpUniSock == null)
|
||||
return "";
|
||||
return ssdpUniSock.getLocalAddress().getHostAddress();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user