merge of '8bf9850eb3fe4fcfb63053838a188969b7ba9c5b'

and 'a40ea9b5f7545281195f00a80e31ae879197e76b'
This commit is contained in:
str4d
2016-11-20 06:08:40 +00:00
82 changed files with 1052 additions and 259 deletions

View File

@@ -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>

View File

@@ -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",

View File

@@ -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() {}

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

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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);
}
}

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

@@ -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);

View File

@@ -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 {

View File

@@ -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);
}
}
/**

View File

@@ -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);
}
/**

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View 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;
}
}

View File

@@ -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));

View File

@@ -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();
}