propagate from branch 'i2p.i2p' (head d046bffcd4f94b253e1aa2bfc9a90482974363dd)

to branch 'i2p.i2p.zzz.test2' (head d00c6fd9c9aef6c37218a791a12f2da957181cd2)
This commit is contained in:
zzz
2015-05-18 11:09:26 +00:00
422 changed files with 40305 additions and 27854 deletions

View File

@ -60,7 +60,7 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
{
// http://en.wikipedia.org/wiki/Cpuid
// http://web.archive.org/web/20110307080258/http://www.intel.com/Assets/PDF/appnote/241618.pdf
// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-2a-manual.pdf
// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
String modelString = null;
int family = CPUID.getCPUFamily();
int model = CPUID.getCPUModel();
@ -156,9 +156,8 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
isPentiumMCompatible = true;
isCore2Compatible = true;
isX64 = true;
}
if (extmodel >= 2) {
isCoreiCompatible = true;
if (extmodel >= 2)
isCoreiCompatible = true;
}
switch (model) {
case 0:
@ -350,6 +349,11 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
// most flags are set above
// isCoreiCompatible = true is the default
// 22 nm
case 0x45:
modelString = "Mobile Celeron";
break;
// Atom Silvermont / Bay Trail / Avoton 22 nm
// Supports SSE 4.2
case 0x4d:

View File

@ -1,7 +1,9 @@
<html>
<body>
<p>
CPUID implementaion, borrowed from freenet, updated and heavily modified
CPUID implementaion, borrowed from freenet, updated and heavily modified.
Not recommended for external use, not maintained as a public API.
</p>
</body>
</html>

View File

@ -18,7 +18,7 @@ public class CoreVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = "0.9.18";
public final static String VERSION = "0.9.19";
/**
* For Vuze.

View File

@ -939,6 +939,7 @@ public class I2PAppContext {
/**
* Use instead of SimpleScheduler.getInstance()
* @since 0.9 to replace static instance in the class
* @deprecated in 0.9.20, use simpleTimer2()
*/
public SimpleScheduler simpleScheduler() {
if (!_simpleSchedulerInitialized)
@ -946,6 +947,9 @@ public class I2PAppContext {
return _simpleScheduler;
}
/**
* @deprecated in 0.9.20
*/
private void initializeSimpleScheduler() {
synchronized (_lock18) {
if (_simpleScheduler == null)

View File

@ -59,9 +59,14 @@ import net.i2p.util.VersionComparator;
* Implementation of an I2P session running over TCP. This class is NOT thread safe -
* only one thread should send messages at any given time
*
* Public only for clearCache().
* Except for methods defined in I2PSession and I2CPMessageEventListener,
* not maintained as a public API, not for external use.
* Use I2PClientFactory to get an I2PClient and then createSession().
*
* @author jrandom
*/
abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessageEventListener {
public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessageEventListener {
protected final Log _log;
/** who we are */
private final Destination _myDestination;
@ -1149,6 +1154,13 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
}
/** @since 0.9.20 */
public static void clearCache() {
synchronized (_lookupCache) {
_lookupCache.clear();
}
}
/**
* Blocking. Waits a max of 10 seconds by default.
* See lookupDest with maxWait parameter to change.
@ -1353,7 +1365,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
boolean close = Boolean.parseBoolean(_options.getProperty("i2cp.closeOnIdle"));
if (reduce || close) {
updateActivity();
_context.simpleScheduler().addEvent(new SessionIdleTimer(_context, this, reduce, close), SessionIdleTimer.MINIMUM_TIME);
_context.simpleTimer2().addEvent(new SessionIdleTimer(_context, this, reduce, close), SessionIdleTimer.MINIMUM_TIME);
}
}

View File

@ -118,6 +118,6 @@ class SessionIdleTimer implements SimpleTimer.TimedEvent {
} else {
nextDelay = _minimumTime - (now - lastActivity);
}
_context.simpleScheduler().addEvent(this, nextDelay);
_context.simpleTimer2().addEvent(this, nextDelay);
}
}

View File

@ -97,7 +97,8 @@ public final class I2PDatagramDissector {
}
} catch (IOException e) {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramDissector.class);
log.error("Caught IOException - INCONSISTENT STATE!", e);
log.error("Error loading datagram", e);
throw new DataFormatException("Error loading datagram", e);
//} catch(AssertionError e) {
// Log log = I2PAppContext.getGlobalContext().logManager().getLog(I2PDatagramDissector.class);
// log.error("Assertion failed!", e);

View File

@ -18,11 +18,14 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeMap;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
@ -860,7 +863,7 @@ public class BlockfileNamingService extends DummyNamingService {
iter = sl.find(beginWith);
else
iter = sl.iterator();
Map<String, Destination> rv = new HashMap<String, Destination>();
Map<String, Destination> rv = new TreeMap<String, Destination>();
for (int i = 0; i < skip && iter.hasNext(); i++) {
// don't bother validating here
iter.next();
@ -896,6 +899,188 @@ public class BlockfileNamingService extends DummyNamingService {
}
}
/**
* @param options If non-null and contains the key "list", get
* from that list (default "hosts.txt", NOT all lists)
* Key "skip": skip that many entries
* Key "limit": max number to return
* Key "search": return only those matching substring
* Key "startsWith": return only those starting with
* ("[0-9]" allowed)
* Key "beginWith": start here in the iteration
* Don't use both startsWith and beginWith.
* Search, startsWith, and beginWith values must be lower case.
* @since 0.9.20
*/
@Override
public Map<String, String> getBase64Entries(Properties options) {
String listname = FALLBACK_LIST;
String search = null;
String startsWith = null;
String beginWith = null;
int limit = Integer.MAX_VALUE;
int skip = 0;
if (options != null) {
String ln = options.getProperty("list");
if (ln != null)
listname = ln;
search = options.getProperty("search");
startsWith = options.getProperty("startsWith");
beginWith = options.getProperty("beginWith");
if (beginWith == null && startsWith != null) {
if (startsWith.equals("[0-9]"))
beginWith = "0";
else
beginWith = startsWith;
}
String lim = options.getProperty("limit");
try {
limit = Integer.parseInt(lim);
} catch (NumberFormatException nfe) {}
String sk = options.getProperty("skip");
try {
skip = Integer.parseInt(sk);
} catch (NumberFormatException nfe) {}
}
synchronized(_bf) {
if (_isClosed)
return Collections.emptyMap();
try {
SkipList sl = _bf.getIndex(listname, _stringSerializer, _destSerializer);
if (sl == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No skiplist found for lookup in " + listname);
return Collections.emptyMap();
}
SkipIterator iter;
if (beginWith != null)
iter = sl.find(beginWith);
else
iter = sl.iterator();
Map<String, String> rv = new TreeMap<String, String>();
for (int i = 0; i < skip && iter.hasNext(); i++) {
// don't bother validating here
iter.next();
}
for (int i = 0; i < limit && iter.hasNext(); ) {
String key = (String) iter.nextKey();
if (startsWith != null) {
if (startsWith.equals("[0-9]")) {
if (key.charAt(0) > '9')
break;
} else if (!key.startsWith(startsWith)) {
break;
}
}
DestEntry de = (DestEntry) iter.next();
if (!validate(key, de, listname))
continue;
if (search != null && key.indexOf(search) < 0)
continue;
rv.put(key, de.dest.toBase64());
i++;
}
return rv;
} catch (IOException ioe) {
_log.error("DB lookup error", ioe);
return Collections.emptyMap();
} catch (RuntimeException re) {
_log.error("DB lookup error", re);
return Collections.emptyMap();
} finally {
deleteInvalid();
}
}
}
/**
* @param options If non-null and contains the key "list", get
* from that list (default "hosts.txt", NOT all lists)
* Key "skip": skip that many entries
* Key "limit": max number to return
* Key "search": return only those matching substring
* Key "startsWith": return only those starting with
* ("[0-9]" allowed)
* Key "beginWith": start here in the iteration
* Don't use both startsWith and beginWith.
* Search, startsWith, and beginWith values must be lower case.
* @since 0.9.20
*/
@Override
public Set<String> getNames(Properties options) {
String listname = FALLBACK_LIST;
String search = null;
String startsWith = null;
String beginWith = null;
int limit = Integer.MAX_VALUE;
int skip = 0;
if (options != null) {
String ln = options.getProperty("list");
if (ln != null)
listname = ln;
search = options.getProperty("search");
startsWith = options.getProperty("startsWith");
beginWith = options.getProperty("beginWith");
if (beginWith == null && startsWith != null) {
if (startsWith.equals("[0-9]"))
beginWith = "0";
else
beginWith = startsWith;
}
String lim = options.getProperty("limit");
try {
limit = Integer.parseInt(lim);
} catch (NumberFormatException nfe) {}
String sk = options.getProperty("skip");
try {
skip = Integer.parseInt(sk);
} catch (NumberFormatException nfe) {}
}
synchronized(_bf) {
if (_isClosed)
return Collections.emptySet();
try {
SkipList sl = _bf.getIndex(listname, _stringSerializer, _destSerializer);
if (sl == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No skiplist found for lookup in " + listname);
return Collections.emptySet();
}
SkipIterator iter;
if (beginWith != null)
iter = sl.find(beginWith);
else
iter = sl.iterator();
Set<String> rv = new HashSet<String>();
for (int i = 0; i < skip && iter.hasNext(); i++) {
iter.next();
}
for (int i = 0; i < limit && iter.hasNext(); ) {
String key = (String) iter.nextKey();
if (startsWith != null) {
if (startsWith.equals("[0-9]")) {
if (key.charAt(0) > '9')
break;
} else if (!key.startsWith(startsWith)) {
break;
}
}
if (search != null && key.indexOf(search) < 0)
continue;
rv.add(key);
i++;
}
return rv;
} catch (IOException ioe) {
_log.error("DB lookup error", ioe);
return Collections.emptySet();
} catch (RuntimeException re) {
_log.error("DB lookup error", re);
return Collections.emptySet();
}
}
}
/**
* @param options ignored
* @since 0.8.9

View File

@ -1,5 +1,7 @@
package net.i2p.client.naming;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.HashMap;
@ -179,6 +181,19 @@ public class MetaNamingService extends DummyNamingService {
return rv;
}
/**
* All services aggregated
* @since 0.9.20
*/
@Override
public Map<String, String> getBase64Entries(Properties options) {
Map<String, String> rv = new HashMap<String, String>();
for (NamingService ns : _services) {
rv.putAll(ns.getBase64Entries(options));
}
return rv;
}
/**
* All services aggregated
*/
@ -191,6 +206,17 @@ public class MetaNamingService extends DummyNamingService {
return rv;
}
/**
* All services aggregated.
* Duplicates not removed (for efficiency)
* @since 0.9.20
*/
public void export(Writer out, Properties options) throws IOException {
for (NamingService ns : _services) {
export(out, options);
}
}
/**
* All services aggregated
*/

View File

@ -7,12 +7,16 @@
*/
package net.i2p.client.naming;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArraySet;
import net.i2p.I2PAppContext;
@ -235,14 +239,83 @@ public abstract class NamingService {
* Warning - This will bring the whole database into memory
* if options is null, empty, or unsupported, use with caution.
*
* This implementation calls getEntries(options) and returns a SortedMap.
* Subclasses should override if they store base64 natively.
*
* @param options NamingService-specific, can be null
* @return all mappings (matching the options if non-null)
* or empty Map if none;
* Returned Map is not necessarily sorted, implementation dependent
* @since 0.8.7
* @since 0.8.7, implemented in 0.9.20
*/
public Map<String, String> getBase64Entries(Properties options) {
return Collections.emptyMap();
Map<String, Destination> entries = getEntries(options);
if (entries.size() <= 0)
return Collections.emptyMap();
Map<String, String> rv = new TreeMap<String, String>();
for (Map.Entry<String, Destination> e : entries.entrySet()) {
rv.put(e.getKey(), e.getValue().toBase64());
}
return rv;
}
/**
* Export in a hosts.txt format.
* Output is not necessarily sorted, implementation dependent.
* Output may or may not contain comment lines, implementation dependent.
* Caller must close writer.
*
* This implementation calls getBase64Entries().
* Subclasses should override if they store in a hosts.txt format natively.
*
* @since 0.9.20
*/
public void export(Writer out) throws IOException {
export(out, null);
}
/**
* Export in a hosts.txt format.
* Output is not necessarily sorted, implementation dependent.
* Output may or may not contain comment lines, implementation dependent.
* Caller must close writer.
*
* This implementation calls getBase64Entries(options).
* Subclasses should override if they store in a hosts.txt format natively.
*
* @param options NamingService-specific, can be null
* @since 0.9.20
*/
public void export(Writer out, Properties options) throws IOException {
Map<String, String> entries = getBase64Entries(options);
out.write("# Address book: ");
out.write(getName());
if (options != null) {
String list = options.getProperty("list");
if (list != null)
out.write(" (" + list + ')');
}
final String nl = System.getProperty("line.separator", "\n");
out.write(nl);
int sz = entries.size();
if (sz <= 0) {
out.write("# No entries");
out.write(nl);
return;
}
out.write("# Exported: ");
out.write((new Date()).toString());
out.write(nl);
if (sz > 1) {
out.write("# " + sz + " entries");
out.write(nl);
}
for (Map.Entry<String, String> e : entries.entrySet()) {
out.write(e.getKey());
out.write('=');
out.write(e.getValue());
out.write(nl);
}
}
/**

View File

@ -15,7 +15,9 @@ import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -364,6 +366,103 @@ public class SingleFileNamingService extends NamingService {
}
}
/**
* Overridden since we store base64 natively.
*
* @param options As follows:
* Key "search": return only those matching substring
* Key "startsWith": return only those starting with
* ("[0-9]" allowed)
* @return all mappings (matching the options if non-null)
* or empty Map if none.
* Returned Map is not sorted.
* @since 0.9.20
*/
public Map<String, String> getBase64Entries(Properties options) {
if (!_file.exists())
return Collections.emptyMap();
String searchOpt = null;
String startsWith = null;
if (options != null) {
searchOpt = options.getProperty("search");
startsWith = options.getProperty("startsWith");
}
BufferedReader in = null;
getReadLock();
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(_file), "UTF-8"), 16*1024);
String line = null;
Map<String, String> rv = new HashMap<String, String>();
while ( (line = in.readLine()) != null) {
if (line.length() <= 0)
continue;
if (startsWith != null) {
if (startsWith.equals("[0-9]")) {
if (line.charAt(0) < '0' || line.charAt(0) > '9')
continue;
} else if (!line.startsWith(startsWith)) {
continue;
}
}
if (line.startsWith("#"))
continue;
if (line.indexOf('#') > 0) // trim off any end of line comment
line = line.substring(0, line.indexOf('#')).trim();
int split = line.indexOf('=');
if (split <= 0)
continue;
String key = line.substring(0, split);
if (searchOpt != null && key.indexOf(searchOpt) < 0)
continue;
String b64 = line.substring(split+1); //.trim() ??????????????
if (b64.length() < 387)
continue;
rv.put(key, b64);
}
if (searchOpt == null && startsWith == null) {
_lastWrite = _file.lastModified();
_size = rv.size();
}
return rv;
} catch (IOException ioe) {
_log.error("getEntries error", ioe);
return Collections.emptyMap();
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
releaseReadLock();
}
}
/**
* Overridden for efficiency.
* Output is not sorted.
*
* @param options ignored
* @since 0.9.20
*/
public void export(Writer out, Properties options) throws IOException {
out.write("# Address book: ");
out.write(getName());
final String nl = System.getProperty("line.separator", "\n");
out.write(nl);
out.write("# Exported: ");
out.write((new Date()).toString());
out.write(nl);
BufferedReader in = null;
getReadLock();
try {
in = new BufferedReader(new InputStreamReader(new FileInputStream(_file), "UTF-8"), 16*1024);
String line = null;
while ( (line = in.readLine()) != null) {
out.write(line);
out.write(nl);
}
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
releaseReadLock();
}
}
/**
* @param options ignored
* @return all known host names, unsorted

View File

@ -53,6 +53,8 @@ public class CertUtil {
}
wr.println("-----END CERTIFICATE-----");
wr.flush();
if (wr.checkError())
throw new IOException("Failed write to " + file);
return true;
} catch (CertificateEncodingException cee) {
error("Error writing X509 Certificate " + file.getAbsolutePath(), cee);

View File

@ -32,6 +32,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
// Debugging methods and variables
//...........................................................................
/****
private static final String _NAME = "Rijndael_Algorithm";
private static final boolean _IN = true, _OUT = false;
@ -53,6 +54,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
private static void trace(String s) {
if (_TRACE) _err.println("<=> " + _NAME + "." + s);
}
****/
// Constants and variables
//...........................................................................
@ -89,11 +91,13 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
//...........................................................................
static {
/****
if (_RDEBUG && _debuglevel > 6) {
System.out.println("Algorithm Name: Rijndael ver 0.1");
System.out.println("Electronic Codebook (ECB) Mode");
System.out.println();
}
****/
int ROOT = 0x11B;
int i, j = 0;
@ -383,7 +387,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
* @param sessionKey The session key to use for encryption.
*/
public static final void blockEncrypt(byte[] in, byte[] result, int inOffset, int outOffset, Object sessionKey) {
if (_RDEBUG) trace(_IN, "blockEncrypt(" + in + ", " + inOffset + ", " + sessionKey + ")");
//if (_RDEBUG) trace(_IN, "blockEncrypt(" + in + ", " + inOffset + ", " + sessionKey + ")");
int[][] Ke = (int[][]) ((Object[]) sessionKey)[0]; // extract encryption round keys
int ROUNDS = Ke.length - 1;
int[] Ker = Ke[0];
@ -409,9 +413,11 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
t1 = a1;
t2 = a2;
t3 = a3;
/****
if (_RDEBUG && _debuglevel > 6)
System.out.println("CT" + r + "=" + intToString(t0) + intToString(t1) + intToString(t2)
+ intToString(t3));
****/
}
// last round is special
@ -436,11 +442,13 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
result[outOffset++] = (byte) (_S[(t0 >>> 16) & 0xFF] ^ (tt >>> 16));
result[outOffset++] = (byte) (_S[(t1 >>> 8) & 0xFF] ^ (tt >>> 8));
result[outOffset++] = (byte) (_S[t2 & 0xFF] ^ tt);
/****
if (_RDEBUG && _debuglevel > 6) {
System.out.println("CT=" + toString(result));
System.out.println();
}
if (_RDEBUG) trace(_OUT, "blockEncrypt()");
****/
}
/**
@ -458,7 +466,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
+ " result.len=" + result.length + " result.offset=" + outOffset);
if (in.length - inOffset <= 15)
throw new IllegalArgumentException("data too small: " + in.length + " inOffset: " + inOffset);
if (_RDEBUG) trace(_IN, "blockDecrypt(" + in + ", " + inOffset + ", " + sessionKey + ")");
//if (_RDEBUG) trace(_IN, "blockDecrypt(" + in + ", " + inOffset + ", " + sessionKey + ")");
int[][] Kd = (int[][]) ((Object[]) sessionKey)[1]; // extract decryption round keys
int ROUNDS = Kd.length - 1;
int[] Kdr = Kd[0];
@ -484,9 +492,11 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
t1 = a1;
t2 = a2;
t3 = a3;
/****
if (_RDEBUG && _debuglevel > 6)
System.out.println("PT" + r + "=" + intToString(t0) + intToString(t1) + intToString(t2)
+ intToString(t3));
****/
}
// last round is special
@ -511,11 +521,13 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
result[outOffset++] = (byte) (_Si[(t2 >>> 16) & 0xFF] ^ (tt >>> 16));
result[outOffset++] = (byte) (_Si[(t1 >>> 8) & 0xFF] ^ (tt >>> 8));
result[outOffset++] = (byte) (_Si[t0 & 0xFF] ^ tt);
/****
if (_RDEBUG && _debuglevel > 6) {
System.out.println("PT=" + toString(result));
System.out.println();
}
if (_RDEBUG) trace(_OUT, "blockDecrypt()");
****/
}
/** A basic symmetric encryption/decryption test. */
@ -544,7 +556,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
return makeKey(k, blockSize, null);
}
public static final/* synchronized */Object makeKey(byte[] k, int blockSize, CryptixAESKeyCache.KeyCacheEntry keyData) throws InvalidKeyException {
if (_RDEBUG) trace(_IN, "makeKey(" + k + ", " + blockSize + ")");
//if (_RDEBUG) trace(_IN, "makeKey(" + k + ", " + blockSize + ")");
if (k == null) throw new InvalidKeyException("Empty key");
if (!(k.length == 16 || k.length == 24 || k.length == 32))
throw new InvalidKeyException("Incorrect key length");
@ -629,7 +641,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
sessionKey = new Object[] { Ke, Kd};
else
sessionKey = keyData.key;
if (_RDEBUG) trace(_OUT, "makeKey()");
//if (_RDEBUG) trace(_OUT, "makeKey()");
return sessionKey;
}
@ -647,7 +659,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
blockEncrypt(in, result, inOffset, outOffset, sessionKey);
return;
}
if (_RDEBUG) trace(_IN, "blockEncrypt(" + in + ", " + inOffset + ", " + sessionKey + ", " + blockSize + ")");
//if (_RDEBUG) trace(_IN, "blockEncrypt(" + in + ", " + inOffset + ", " + sessionKey + ", " + blockSize + ")");
Object[] sKey = (Object[]) sessionKey; // extract encryption round keys
int[][] Ke = (int[][]) sKey[0];
@ -673,7 +685,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
^ _T3[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ _T4[t[(i + s3) % BC] & 0xFF])
^ Ke[r][i];
System.arraycopy(a, 0, t, 0, BC);
if (_RDEBUG && _debuglevel > 6) System.out.println("CT" + r + "=" + toString(t));
//if (_RDEBUG && _debuglevel > 6) System.out.println("CT" + r + "=" + toString(t));
}
for (i = 0; i < BC; i++) { // last round is special
tt = Ke[ROUNDS][i];
@ -682,11 +694,13 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
result[j++] = (byte) (_S[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8));
result[j++] = (byte) (_S[t[(i + s3) % BC] & 0xFF] ^ tt);
}
/****
if (_RDEBUG && _debuglevel > 6) {
System.out.println("CT=" + toString(result));
System.out.println();
}
if (_RDEBUG) trace(_OUT, "blockEncrypt()");
****/
}
/**
@ -704,7 +718,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
return;
}
if (_RDEBUG) trace(_IN, "blockDecrypt(" + in + ", " + inOffset + ", " + sessionKey + ", " + blockSize + ")");
//if (_RDEBUG) trace(_IN, "blockDecrypt(" + in + ", " + inOffset + ", " + sessionKey + ", " + blockSize + ")");
Object[] sKey = (Object[]) sessionKey; // extract decryption round keys
int[][] Kd = (int[][]) sKey[1];
@ -730,7 +744,7 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
^ _T7[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ _T8[t[(i + s3) % BC] & 0xFF])
^ Kd[r][i];
System.arraycopy(a, 0, t, 0, BC);
if (_RDEBUG && _debuglevel > 6) System.out.println("PT" + r + "=" + toString(t));
//if (_RDEBUG && _debuglevel > 6) System.out.println("PT" + r + "=" + toString(t));
}
for (i = 0; i < BC; i++) { // last round is special
tt = Kd[ROUNDS][i];
@ -739,11 +753,13 @@ public final class CryptixRijndael_Algorithm // implicit no-argument constructor
result[j++] = (byte) (_Si[(t[(i + s2) % BC] >>> 8) & 0xFF] ^ (tt >>> 8));
result[j++] = (byte) (_Si[t[(i + s3) % BC] & 0xFF] ^ tt);
}
/****
if (_RDEBUG && _debuglevel > 6) {
System.out.println("PT=" + toString(result));
System.out.println();
}
if (_RDEBUG) trace(_OUT, "blockDecrypt()");
****/
}
/** A basic symmetric encryption/decryption test for a given key size. */

View File

@ -77,8 +77,9 @@ public final class SHA256Generator {
digest.digest(out, outOffset, Hash.HASH_LENGTH);
} catch (DigestException e) {
throw new RuntimeException(e);
} finally {
release(digest);
}
release(digest);
}
private MessageDigest acquire() {

View File

@ -529,6 +529,11 @@ public class DataHelper {
out.flush();
fos.getFD().sync();
out.close();
if (out.checkError()) {
out = null;
tmpFile.delete();
throw new IOException("Failed to write properties to " + tmpFile);
}
out = null;
if (!FileUtil.rename(tmpFile, file))
throw new IOException("Failed rename from " + tmpFile + " to " + file);

View File

@ -41,7 +41,7 @@ import net.i2p.util.SecureFileOutputStream;
* - Certificate if length != 0
* - Private key (256 bytes)
* - Signing Private key (20 bytes, or length specified by key certificate)
* Total 663 bytes
* Total: 663 or more bytes
*</pre>
*
* @author welterde, zzz

View File

@ -96,7 +96,7 @@ public class MessagePayloadMessage extends I2CPMessageImpl {
int size = 2 + 4 + 4 + _payload.getSize();
try {
DataHelper.writeLong(out, 4, size);
DataHelper.writeLong(out, 1, getType());
DataHelper.writeLong(out, 1, MESSAGE_TYPE);
DataHelper.writeLong(out, 2, _sessionId);
DataHelper.writeLong(out, 4, _messageId);
DataHelper.writeLong(out, 4, _payload.getSize());

View File

@ -308,7 +308,7 @@ public class MessageStatusMessage extends I2CPMessageImpl {
try {
DataHelper.writeLong(out, 4, len);
DataHelper.writeLong(out, 1, getType());
DataHelper.writeLong(out, 1, MESSAGE_TYPE);
DataHelper.writeLong(out, 2, _sessionId);
DataHelper.writeLong(out, 4, _messageId);
DataHelper.writeLong(out, 1, _status);

View File

@ -76,7 +76,7 @@ public class ReceiveMessageBeginMessage extends I2CPMessageImpl {
try {
DataHelper.writeLong(out, 4, len);
DataHelper.writeLong(out, 1, getType());
DataHelper.writeLong(out, 1, MESSAGE_TYPE);
DataHelper.writeLong(out, 2, _sessionId);
DataHelper.writeLong(out, 4, _messageId);
} catch (DataFormatException dfe) {

View File

@ -74,7 +74,7 @@ public class SendMessageMessage extends I2CPMessageImpl {
@Override
protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException {
if (true) throw new IllegalStateException("wtf, do not run me");
throw new UnsupportedOperationException();
}
/**

View File

@ -69,7 +69,7 @@ public final class ByteCache {
/**
* Get a cache responsible for objects of the given size.
* Warning, if you store the result in a static field, the cleaners will
* not operate after a restart on Android, as the old context's SimpleScheduler will have shut down.
* not operate after a restart on Android, as the old context's SimpleTimer2 will have shut down.
* TODO tie this to the context or clean up all calls.
*
* @param cacheSize how large we want the cache to grow
@ -123,7 +123,7 @@ public final class ByteCache {
_maxCached = maxCachedEntries;
_entrySize = entrySize;
_lastOverflow = -1;
SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 777)); //stagger
SimpleTimer2.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 777)); //stagger
I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 10*60*1000 });
}

View File

@ -11,6 +11,7 @@ import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.UnknownHostException;
@ -61,6 +62,7 @@ public class EepGet {
protected List<String> _extraHeaders;
protected boolean _keepFetching;
// The proxy or the actual site if not proxied. Warning - null when extended by I2PSocketEepGet
protected Socket _proxy;
protected OutputStream _proxyOut;
protected InputStream _proxyIn;
@ -82,9 +84,9 @@ public class EepGet {
protected boolean _transferFailed;
protected boolean _headersRead;
protected boolean _aborted;
private long _fetchHeaderTimeout;
protected int _fetchHeaderTimeout;
private long _fetchEndTime;
protected long _fetchInactivityTimeout;
protected int _fetchInactivityTimeout;
protected int _redirects;
protected String _redirectLocation;
protected boolean _isGzippedResponse;
@ -96,8 +98,8 @@ public class EepGet {
/** this will be replaced by the HTTP Proxy if we are using it */
protected static final String USER_AGENT = "Wget/1.11.4";
protected static final long CONNECT_TIMEOUT = 45*1000;
protected static final long INACTIVITY_TIMEOUT = 60*1000;
protected static final int CONNECT_TIMEOUT = 45*1000;
protected static final int INACTIVITY_TIMEOUT = 60*1000;
/** maximum times to try without getting any data at all, even if numRetries is higher @since 0.7.14 */
protected static final int MAX_COMPLETE_FAILS = 5;
@ -577,9 +579,9 @@ public class EepGet {
* @param inactivityTimeout <= 0 for default 60 sec
*/
public boolean fetch(long fetchHeaderTimeout, long totalTimeout, long inactivityTimeout) {
_fetchHeaderTimeout = fetchHeaderTimeout;
_fetchHeaderTimeout = (int) Math.min(fetchHeaderTimeout, Integer.MAX_VALUE);
_fetchEndTime = (totalTimeout > 0 ? System.currentTimeMillis() + totalTimeout : -1);
_fetchInactivityTimeout = inactivityTimeout;
_fetchInactivityTimeout = (int) Math.min(inactivityTimeout, Integer.MAX_VALUE);
_keepFetching = true;
if (_log.shouldLog(Log.DEBUG))
@ -677,6 +679,14 @@ public class EepGet {
else
timeout.setInactivityTimeout(INACTIVITY_TIMEOUT);
}
// _proxy is null when extended by I2PSocketEepGet
if (_proxy != null && !_shouldProxy) {
// we only set the soTimeout before the headers if not proxied
if (_fetchInactivityTimeout > 0)
_proxy.setSoTimeout(_fetchInactivityTimeout);
else
_proxy.setSoTimeout(INACTIVITY_TIMEOUT);
}
if (_redirectLocation != null) {
// we also are here after a 407
@ -906,11 +916,14 @@ public class EepGet {
return;
case 400: // bad req
case 401: // server auth
case 402: // payment required
case 403: // bad req
case 404: // not found
case 408: // req timeout
case 409: // bad addr helper
case 410: // gone
case 414: // URI too long
case 429: // too many requests
case 431: // headers too long
case 503: // no outproxy
_transferFailed = true;
@ -1193,7 +1206,13 @@ public class EepGet {
int port = url.getPort();
if (port == -1)
port = 80;
_proxy = new Socket(host, port);
if (_fetchHeaderTimeout > 0) {
_proxy = new Socket();
_proxy.setSoTimeout(_fetchHeaderTimeout);
_proxy.connect(new InetSocketAddress(host, port), _fetchHeaderTimeout);
} else {
_proxy = new Socket(host, port);
}
} else {
throw new MalformedURLException("URL is not supported:" + _actualURL);
}

View File

@ -21,8 +21,44 @@ package net.i2p.util;
* ========================================================================
*/
/*
* Contains code adapted from:
* Apache httpcomponents PublicSuffixMatcherLoader.java
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.Locale;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyStore;
@ -34,8 +70,13 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
@ -43,14 +84,41 @@ import javax.net.ssl.TrustManagerFactory;
import net.i2p.I2PAppContext;
import net.i2p.crypto.KeyStoreUtil;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.util.PublicSuffixList;
import org.apache.http.conn.util.PublicSuffixListParser;
import org.apache.http.conn.util.PublicSuffixMatcher;
/**
* Loads trusted ASCII certs from ~/.i2p/certificates/ and $I2P/certificates/.
*
* TODO extend SSLSocketFactory
*
* @author zzz
* @since 0.9.9 moved from ../client, original since 0.8.3
*/
public class I2PSSLSocketFactory {
private static final String PROP_DISABLE = "i2p.disableSSLHostnameVerification";
private static final String PROP_GEOIP_DIR = "geoip.dir";
private static final String GEOIP_DIR_DEFAULT = "geoip";
private static final String GEOIP_FILE_DEFAULT = "geoip.txt";
private static final String COUNTRY_FILE_DEFAULT = "countries.txt";
private static final String PUBLIC_SUFFIX_LIST = "public-suffix-list.txt";
private static PublicSuffixMatcher DEFAULT_MATCHER;
private static boolean _matcherLoaded;
// not in countries.txt, but only the public ones, not the private ones
private static final String[] DEFAULT_TLDS = {
"arpa", "asia", "biz", "cat", "com", "coop",
"edu", "gov", "info", "int", "jobs", "mil",
"mobi", "museum", "name", "net", "org", "post",
"pro", "tel", "travel", "xxx"
};
// not in countries.txt or public-suffix-list.txt
private static final String[] ADDITIONAL_TLDS = {
"i2p", "mooo.com", "onion"
};
/**
* Unmodifiable.
* Public for RouterConsoleRunner.
@ -148,7 +216,9 @@ public class I2PSSLSocketFactory {
*/
public static final List<String> INCLUDE_CIPHERS = Collections.emptyList();
/** the "real" factory */
private final SSLSocketFactory _factory;
private final I2PAppContext _context;
/**
* @param relativeCertPath e.g. "certificates/i2cp"
@ -157,27 +227,230 @@ public class I2PSSLSocketFactory {
public I2PSSLSocketFactory(I2PAppContext context, boolean loadSystemCerts, String relativeCertPath)
throws GeneralSecurityException {
_factory = initSSLContext(context, loadSystemCerts, relativeCertPath);
_context = context;
}
/**
* Returns a socket to the host.
*
* A host argument that's an IP address (instead of a host name)
* is not recommended, as this will probably fail
* SSL certificate validation.
*
* Hostname validation is skipped for localhost addresses, but you still
* must trust the certificate.
*
*/
public Socket createSocket(String host, int port) throws IOException {
SSLSocket rv = (SSLSocket) _factory.createSocket(host, port);
setProtocolsAndCiphers(rv);
verifyHostname(_context, rv, host);
return rv;
}
/**
* Returns a socket to the host.
*
* An InetAddress argument created with an IP address (instead of a host name)
* is not recommended, as this will perform a reverse DNS lookup to
* get the host name for certificate validation, which will probably then fail.
*
* Hostname validation is skipped for localhost addresses, but you still
* must trust the certificate.
*
* @since 0.9.9
*/
public Socket createSocket(InetAddress host, int port) throws IOException {
SSLSocket rv = (SSLSocket) _factory.createSocket(host, port);
setProtocolsAndCiphers(rv);
String name = host.getHostName();
verifyHostname(_context, rv, name);
return rv;
}
/**
* Validate the hostname
*
* ref: https://developer.android.com/training/articles/security-ssl.html
* ref: http://op-co.de/blog/posts/java_sslsocket_mitm/
* ref: http://kevinlocke.name/bits/2012/10/03/ssl-certificate-verification-in-dispatch-and-asynchttpclient/
*
* @throws SSLException on hostname verification failure
* @since 0.9.20
*/
public static void verifyHostname(I2PAppContext ctx, SSLSocket socket, String host) throws SSLException {
Log log = ctx.logManager().getLog(I2PSSLSocketFactory.class);
if (ctx.getBooleanProperty(PROP_DISABLE) ||
host.equals("localhost") ||
host.equals("127.0.0.1") ||
host.equals("::1") ||
host.equals("0:0:0:0:0:0:0::1")) {
if (log.shouldWarn())
log.warn("Skipping hostname validation for " + host);
return;
}
HostnameVerifier hv;
if (SystemVersion.isAndroid()) {
// https://developer.android.com/training/articles/security-ssl.html
hv = HttpsURLConnection.getDefaultHostnameVerifier();
} else {
// haha the above may work for Android but it doesn't in Oracle
//
// quote http://kevinlocke.name/bits/2012/10/03/ssl-certificate-verification-in-dispatch-and-asynchttpclient/ :
// Unlike SSLContext, using the Java default (HttpsURLConnection.getDefaultHostnameVerifier)
// is not a viable option because the default HostnameVerifier expects to only be called
// in the case that there is a mismatch (and therefore always returns false) while some
// of the AsyncHttpClient providers (e.g. Netty, the default) call it on all connections.
// in the case that there is a mismatch (and therefore always returns false) while some
// To make matters worse, the check is not trivial (consider SAN and wildcard matching)
// and is implemented in sun.security.util.HostnameChecker (a Sun internal proprietary API).
// This leaves the developer in the position of either depending on an internal API or
// finding/copying/creating another implementation of this functionality.
//
hv = new DefaultHostnameVerifier(getDefaultMatcher(ctx));
}
SSLSession sess = socket.getSession();
// Verify that the certicate hostname is for mail.google.com
// This is due to lack of SNI support in the current SSLSocket.
if (!hv.verify(host, sess)) {
throw new SSLHandshakeException("SSL hostname verify failed, Expected " + host +
// throws SSLPeerUnverifiedException
//", found " + sess.getPeerPrincipal() +
// returns null
//", found " + sess.getPeerHost() +
// enable logging for DefaultHostnameVerifier to find out the CN and SANs
" - set " + PROP_DISABLE +
"=true to disable verification (dangerous!)");
}
// At this point SSLSocket performed certificate verificaiton and
// we have performed hostname verification, so it is safe to proceed.
}
/**
* From Apache PublicSuffixMatcherLoader.getDefault()
*
* https://publicsuffix.org/list/effective_tld_names.dat
* What does this get us?
* Deciding whether to issue or accept an SSL wildcard certificate for *.public.suffix.
*
* @return null on failure
* @since 0.9.20
*/
private static PublicSuffixMatcher getDefaultMatcher(I2PAppContext ctx) {
synchronized (I2PSSLSocketFactory.class) {
if (!_matcherLoaded) {
String geoDir = ctx.getProperty(PROP_GEOIP_DIR, GEOIP_DIR_DEFAULT);
File geoFile = new File(geoDir);
if (!geoFile.isAbsolute())
geoFile = new File(ctx.getBaseDir(), geoDir);
geoFile = new File(geoFile, PUBLIC_SUFFIX_LIST);
Log log = ctx.logManager().getLog(I2PSSLSocketFactory.class);
if (geoFile.exists()) {
try {
// we can't use PublicSuffixMatcherLoader.load() here because we
// want to add some of our own and a PublicSuffixMatcher's
// underlying PublicSuffixList is immutable and inaccessible
long begin = System.currentTimeMillis();
InputStream in = null;
PublicSuffixList list = new PublicSuffixList(Arrays.asList(ADDITIONAL_TLDS),
Collections.<String>emptyList());
try {
in = new FileInputStream(geoFile);
PublicSuffixList list2 = new PublicSuffixListParser().parse(
new InputStreamReader(in, "UTF-8"));
list = merge(list, list2);
} finally {
try { if (in != null) in.close(); } catch (IOException ioe) {}
}
DEFAULT_MATCHER = new PublicSuffixMatcher(list.getRules(), list.getExceptions());
if (log.shouldWarn())
log.warn("Loaded " + geoFile + " in " + (System.currentTimeMillis() - begin) +
" ms and created list with " + list.getRules().size() + " entries and " +
list.getExceptions().size() + " exceptions");
} catch (IOException ex) {
log.error("Failure loading public suffix list from " + geoFile, ex);
// DEFAULT_MATCHER remains null
}
} else {
List<String> list = new ArrayList<String>(320);
addCountries(ctx, list);
list.addAll(Arrays.asList(DEFAULT_TLDS));
list.addAll(Arrays.asList(ADDITIONAL_TLDS));
DEFAULT_MATCHER = new PublicSuffixMatcher(list, null);
if (log.shouldWarn())
log.warn("No public suffix list found at " + geoFile +
" - created default with " + list.size() + " entries");
}
}
_matcherLoaded = true;
}
return DEFAULT_MATCHER;
}
/**
* Merge two PublicSuffixLists
* Have to do this because they are unmodifiable
*
* @since 0.9.20
*/
private static PublicSuffixList merge(PublicSuffixList a, PublicSuffixList b) {
List<String> ar = a.getRules();
List<String> ae = a.getExceptions();
List<String> br = b.getRules();
List<String> be = b.getExceptions();
List<String> cr = new ArrayList<String>(ar.size() + br.size());
List<String> ce = new ArrayList<String>(ae.size() + be.size());
cr.addAll(ar);
cr.addAll(br);
ce.addAll(ae);
ce.addAll(be);
return new PublicSuffixList(cr, ce);
}
/**
* Read in the country file and add all TLDs to the list.
* It would almost be easier just to add all possible 26*26 two-letter codes.
*
* @param tlds out parameter
* @since 0.9.20 adapted from GeoIP.loadCountryFile()
*/
private static void addCountries(I2PAppContext ctx, List<String> tlds) {
Log log = ctx.logManager().getLog(I2PSSLSocketFactory.class);
String geoDir = ctx.getProperty(PROP_GEOIP_DIR, GEOIP_DIR_DEFAULT);
File geoFile = new File(geoDir);
if (!geoFile.isAbsolute())
geoFile = new File(ctx.getBaseDir(), geoDir);
geoFile = new File(geoFile, COUNTRY_FILE_DEFAULT);
if (!geoFile.exists()) {
if (log.shouldWarn())
log.warn("Country file not found: " + geoFile.getAbsolutePath());
return;
}
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(
new FileInputStream(geoFile), "UTF-8"));
String line = null;
int i = 0;
while ( (line = br.readLine()) != null) {
try {
if (line.charAt(0) == '#')
continue;
String[] s = line.split(",");
String lc = s[0].toLowerCase(Locale.US);
tlds.add(lc);
i++;
} catch (IndexOutOfBoundsException ioobe) {}
}
if (log.shouldInfo())
log.info("Loaded " + i + " TLDs from " + geoFile.getAbsolutePath());
} catch (IOException ioe) {
log.error("Error reading the Country File", ioe);
} finally {
if (br != null) try { br.close(); } catch (IOException ioe) {}
}
}
/**
* Loads certs from
* the ~/.i2p/certificates/ and $I2P/certificates/ directories.

View File

@ -76,6 +76,29 @@ public class I2PThread extends Thread {
}
****/
/**
* Overridden to provide useful info to users on OOM, and to prevent
* shutting down the whole JVM for what is most likely not a heap issue.
* If the calling thread is an I2PThread an OOM would shut down the JVM.
* Telling the user to increase the heap size may make the problem worse.
* We may be able to continue without this thread, particularly in app context.
*
* @since 0.9.20
*/
@Override
public void start() {
try {
super.start();
} catch (OutOfMemoryError oom) {
System.out.println("ERROR: Thread could not be started: " + getName());
if (!(SystemVersion.isWindows() || SystemVersion.isAndroid())) {
System.out.println("Check ulimit -u, /etc/security/limits.conf, or /proc/sys/kernel/threads-max");
}
oom.printStackTrace();
throw new RuntimeException("Thread could not be started", oom);
}
}
@Override
public void run() {
//_name = Thread.currentThread().getName();

View File

@ -184,6 +184,26 @@ public class Log {
public boolean shouldLog(int priority) {
return priority >= _minPriority;
}
/** @since 0.9.20 */
public boolean shouldDebug() {
return shouldLog(DEBUG);
}
/** @since 0.9.20 */
public boolean shouldInfo() {
return shouldLog(INFO);
}
/** @since 0.9.20 */
public boolean shouldWarn() {
return shouldLog(WARN);
}
/** @since 0.9.20 */
public boolean shouldError() {
return shouldLog(ERROR);
}
/**
* logs a loop when closing a resource with level INFO

View File

@ -74,6 +74,9 @@ class LogWriter extends LogWriterBase {
}
}
/**
* @since 0.9.19
*/
protected void flushWriter() {
try {
if (_currentOut != null)
@ -84,6 +87,9 @@ class LogWriter extends LogWriterBase {
}
}
/**
* @since 0.9.19 renamed from closeFile()
*/
protected void closeWriter() {
Writer out = _currentOut;
if (out != null) {

View File

@ -16,6 +16,7 @@ import java.util.Queue;
* the log. This also periodically instructs the LogManager to reread its config
* file.
*
* @since 0.9.19 pulled from LogWriter so Android may extend
*/
abstract class LogWriterBase implements Runnable {
/** every 10 seconds? why? Just have the gui force a reread after a change?? */

View File

@ -196,15 +196,14 @@ public class NativeBigInteger extends BigInteger {
private final static String sCPUType; //The CPU Type to optimize for (one of the above strings)
static {
if (_isX86) {// Don't try to resolve CPU type on non x86 hardware
if (_isX86) { // Don't try to resolve CPU type on non x86 hardware
sCPUType = resolveCPUType();
}
else if (_isArm) {
} else if (_isArm) {
sCPUType = JBIGI_OPTIMIZATION_ARM;
} else if (_isPPC && !_isMac) {
sCPUType = JBIGI_OPTIMIZATION_PPC;
sCPUType = JBIGI_OPTIMIZATION_PPC;
} else {
sCPUType = null;
sCPUType = null;
}
loadNative();
}

View File

@ -1,5 +1,10 @@
package net.i2p.util;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext;
@ -73,4 +78,18 @@ public class PortMapper {
return def;
return port.intValue();
}
/**
* For debugging only
* @since 0.9.20
*/
public void renderStatusHTML(Writer out) throws IOException {
List<String> services = new ArrayList(_dir.keySet());
out.write("<h2>Port Mapper</h2><table><tr><th>Service<th>Port\n");
Collections.sort(services);
for (String s : services) {
out.write("<tr><td>" + s + "<td>" + _dir.get(s) + '\n');
}
out.write("</table>\n");
}
}

View File

@ -168,6 +168,21 @@ public class ResettableGZIPInputStream extends InflaterInputStream {
}
}
/**
* Does NOT call super.close(), as it cannot be reused if we do that.
* Broken before 0.9.20.
* @since 0.9.20
*/
@Override
public void close() throws IOException {
len = 0;
inf.reset();
_complete = false;
_crc32.reset();
_buf1[0] = 0x0;
_extraByteInputStream.close();
}
/**
* Moved from i2ptunnel HTTPResponseOutputStream.InternalGZIPInputStream
* @since 0.8.9

View File

@ -44,6 +44,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.KeyStore;
@ -54,7 +55,7 @@ import java.util.Arrays;
import java.util.Locale;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
@ -82,7 +83,9 @@ import net.i2p.data.DataHelper;
*/
public class SSLEepGet extends EepGet {
/** if true, save cert chain on cert error */
private boolean _saveCerts;
private int _saveCerts;
/** if true, don't do hostname verification */
private boolean _bypassVerification;
/** true if called from main(), used for logging */
private boolean _commandLine;
/** may be null if init failed */
@ -153,15 +156,20 @@ public class SSLEepGet extends EepGet {
* SSLEepGet -s https://foo/bar
*/
public static void main(String args[]) {
boolean saveCerts = false;
int saveCerts = 0;
boolean noVerify = false;
boolean error = false;
Getopt g = new Getopt("ssleepget", args, "s");
Getopt g = new Getopt("ssleepget", args, "sz");
try {
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 's':
saveCerts = true;
saveCerts++;
break;
case 'z':
noVerify = true;
break;
case '?':
@ -193,8 +201,10 @@ public class SSLEepGet extends EepGet {
}
SSLEepGet get = new SSLEepGet(I2PAppContext.getGlobalContext(), out, url);
if (saveCerts)
get._saveCerts = true;
if (saveCerts > 0)
get._saveCerts = saveCerts;
if (noVerify)
get._bypassVerification = true;
get._commandLine = true;
get.addStatusListener(get.new CLIStatusListener(1024, 40));
if(!get.fetch(45*1000, -1, 60*1000))
@ -202,8 +212,10 @@ public class SSLEepGet extends EepGet {
}
private static void usage() {
System.err.println("Usage: SSLEepGet https://url\n" +
"To save unknown certs, use: SSLEepGet -s https://url");
System.err.println("Usage: SSLEepGet [-sz] https://url\n" +
" -s save unknown certs\n" +
" -s -s save all certs\n" +
" -z bypass hostname verification");
}
/**
@ -351,7 +363,7 @@ public class SSLEepGet extends EepGet {
for (int k = 0; k < chain.length; k++) {
X509Certificate cert = chain[k];
String name = host + '-' + (k + 1) + ".crt";
System.out.println("NOTE: Saving untrusted X509 certificate as " + name);
System.out.println("NOTE: Saving X509 certificate as " + name);
System.out.println(" Issuer: " + cert.getIssuerX500Principal());
System.out.println(" Valid From: " + cert.getNotBefore());
System.out.println(" Valid To: " + cert.getNotAfter());
@ -363,7 +375,6 @@ public class SSLEepGet extends EepGet {
CertUtil.saveCert(cert, new File(name));
}
System.out.println("NOTE: To trust them, copy the certificate file(s) to the certificates directory and rerun without the -s option");
System.out.println("NOTE: EepGet failed, certificate error follows:");
}
/**
@ -409,6 +420,10 @@ public class SSLEepGet extends EepGet {
else
timeout.setInactivityTimeout(60*1000);
}
if (_fetchInactivityTimeout > 0)
_proxy.setSoTimeout(_fetchInactivityTimeout);
else
_proxy.setSoTimeout(INACTIVITY_TIMEOUT);
if (_redirectLocation != null) {
throw new IOException("Server redirect to " + _redirectLocation + " not allowed");
@ -549,12 +564,28 @@ public class SSLEepGet extends EepGet {
port = url.getPort();
if (port == -1)
port = 443;
// Warning, createSocket() followed by connect(InetSocketAddress)
// disables SNI, at least on Java 7.
// So we must do createSocket(host, port) and then setSoTimeout;
// we can't crate a disconnected socket and then call setSoTimeout, sadly.
if (_sslContext != null)
_proxy = _sslContext.getSocketFactory().createSocket(host, port);
else
_proxy = SSLSocketFactory.getDefault().createSocket(host, port);
if (_fetchHeaderTimeout > 0) {
_proxy.setSoTimeout(_fetchHeaderTimeout);
}
SSLSocket socket = (SSLSocket) _proxy;
I2PSSLSocketFactory.setProtocolsAndCiphers(socket);
if (!_bypassVerification) {
try {
I2PSSLSocketFactory.verifyHostname(_context, socket, host);
} catch (SSLException ssle) {
if (_saveCerts > 0 && _stm != null)
saveCerts(host, _stm);
throw ssle;
}
}
} else {
throw new MalformedURLException("Only https supported: " + _actualURL);
}
@ -570,12 +601,14 @@ public class SSLEepGet extends EepGet {
try {
_proxyOut.write(DataHelper.getUTF8(req));
_proxyOut.flush();
} catch (SSLHandshakeException sslhe) {
if (_saveCerts > 1 && _stm != null)
saveCerts(host, _stm);
} catch (SSLException sslhe) {
// this maybe would be better done in the catch in super.fetch(), but
// then we'd have to copy it all over here.
_log.error("SSL negotiation error with " + host + ':' + port +
" - self-signed certificate or untrusted certificate authority?", sslhe);
if (_saveCerts && _stm != null)
if (_saveCerts > 0 && _stm != null)
saveCerts(host, _stm);
else if (_commandLine) {
System.out.println("FAILED (probably due to untrusted certificates) - Run with -s option to save certificates");

View File

@ -24,12 +24,15 @@ import net.i2p.I2PAppContext;
* For periodic events, use addPeriodicEvent(). Unlike SimpleTimer,
* uncaught Exceptions will not prevent subsequent executions.
*
* @deprecated in 0.9.20, use SimpleTimer2 instead
*
* @author zzz
*/
public class SimpleScheduler {
/**
* If you have a context, use context.simpleScheduler() instead
* @deprecated in 0.9.20, replaced by SimpleTimer2
*/
public static SimpleScheduler getInstance() {
return I2PAppContext.getGlobalContext().simpleScheduler();
@ -46,6 +49,7 @@ public class SimpleScheduler {
/**
* To be instantiated by the context.
* Others should use context.simpleTimer() instead
* @deprecated in 0.9.20, replaced by SimpleTimer2
*/
public SimpleScheduler(I2PAppContext context) {
this(context, "SimpleScheduler");
@ -54,6 +58,7 @@ public class SimpleScheduler {
/**
* To be instantiated by the context.
* Others should use context.simpleTimer() instead
* @deprecated in 0.9.20, replaced by SimpleTimer2
*/
private SimpleScheduler(I2PAppContext context, String name) {
_log = context.logManager().getLog(SimpleScheduler.class);

View File

@ -14,7 +14,7 @@ import net.i2p.I2PAppContext;
* they b0rk the timer).
*
* WARNING - Deprecated.
* This is an inefficient mess. Use SimpleScheduler or SimpleTimer2 if possible.
* This is an inefficient mess. Use SimpleTimer2 if possible.
*/
public class SimpleTimer {

View File

@ -124,6 +124,81 @@ public class SimpleTimer2 {
private ScheduledFuture schedule(TimedEvent t, long timeoutMs) {
return _executor.schedule(t, timeoutMs, TimeUnit.MILLISECONDS);
}
/**
* Queue up the given event to be fired no sooner than timeoutMs from now.
*
* For transition from SimpleScheduler. Uncancellable.
* New code should use SimpleTimer2.TimedEvent.
*
* @param event to be run once
* @param timeoutMs run after this delay
* @since 0.9.20
*/
public void addEvent(final SimpleTimer.TimedEvent event, final long timeoutMs) {
if (event == null)
throw new IllegalArgumentException("addEvent null");
new TimedEvent(this, timeoutMs) {
@Override
public void timeReached() {
event.timeReached();
}
@Override
public String toString() {
return event.toString();
}
};
}
/**
* Schedule periodic event
*
* The TimedEvent must not do its own rescheduling.
* As all Exceptions are caught in run(), these will not prevent
* subsequent executions (unlike SimpleTimer, where the TimedEvent does
* its own rescheduling).
*
* For transition from SimpleScheduler. Uncancellable.
* New code should use SimpleTimer2.TimedEvent.
*
* @since 0.9.20
* @param timeoutMs run first and subsequent iterations of this event every timeoutMs ms
*/
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long timeoutMs) {
addPeriodicEvent(event, timeoutMs, timeoutMs);
}
/**
* Schedule periodic event
*
* The TimedEvent must not do its own rescheduling.
* As all Exceptions are caught in run(), these will not prevent
* subsequent executions (unlike SimpleTimer, where the TimedEvent does
* its own rescheduling).
*
* For transition from SimpleScheduler. Uncancellable.
* New code should use SimpleTimer2.TimedEvent.
*
* @since 0.9.20
* @param delay run the first iteration of this event after delay ms
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms
*/
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long delay, final long timeoutMs) {
new PeriodicTimedEvent(this, delay, timeoutMs) {
@Override
public void timeReached() {
event.timeReached();
}
@Override
public String toString() {
return event.toString();
}
};
}
/**
* state of a given TimedEvent
@ -141,6 +216,7 @@ public class SimpleTimer2 {
CANCELLED
};
/**
* Similar to SimpleTimer.TimedEvent but users must extend instead of implement,
* and all schedule and cancel methods are through this class rather than SimpleTimer2.
@ -228,7 +304,6 @@ public class SimpleTimer2 {
break;
case SCHEDULED: // nothing
}
}
/**
@ -403,5 +478,30 @@ public class SimpleTimer2 {
" Completed: " + _executor.getCompletedTaskCount() +
" Queued: " + _executor.getQueue().size();
}
/**
* For transition from SimpleScheduler.
* @since 0.9.20
*/
private static abstract class PeriodicTimedEvent extends TimedEvent {
private long _timeoutMs;
/**
* Schedule periodic event
*
* @param delay run the first iteration of this event after delay ms
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms
*/
public PeriodicTimedEvent(SimpleTimer2 pool, long delay, long timeoutMs) {
super(pool, delay);
_timeoutMs = timeoutMs;
}
@Override
public void run() {
super.run();
schedule(_timeoutMs);
}
}
}

View File

@ -30,7 +30,9 @@ package net.metanotion.io.block.index;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
@ -61,7 +63,16 @@ public class BSkipLevels extends SkipLevels {
public final BlockFile bf;
private final BSkipList bsl;
private boolean isKilled;
// the level pages, passed from the constructor to initializeLevels(),
// NOT kept up to date
private final int[] lps;
/**
* Non-recursive initializer initializeLevels()
* MUST be called on the first BSkipLevel in the skiplist
* after the constructor, unless it's a new empty
* level and init() was previously called.
*/
public BSkipLevels(BlockFile bf, int levelPage, BSkipList bsl) throws IOException {
this.levelPage = levelPage;
this.bf = bf;
@ -88,25 +99,57 @@ public class BSkipLevels extends SkipLevels {
this.levels = new BSkipLevels[maxLen];
if (bf.log.shouldLog(Log.DEBUG))
bf.log.debug("Reading New BSkipLevels with " + nonNull + " / " + maxLen + " valid levels page " + levelPage);
bf.log.debug("Reading New BSkipLevels with " + nonNull + " / " + maxLen + " valid levels page " + levelPage +
" in skiplist " + bsl);
// We have to read now because new BSkipLevels() will move the file pointer
int[] lps = new int[nonNull];
lps = new int[nonNull];
for(int i = 0; i < nonNull; i++) {
lps[i] = bf.file.readUnsignedInt();
}
}
/**
* Non-recursive initializer.
* MUST be called on the first BSkipLevel in the skiplist
* after the constructor, unless it's a new empty
* level and init() was previously called.
* Only call on the first skiplevel in the list!
*
* @since 0.9.20
*/
public void initializeLevels() {
List<BSkipLevels> toInit = new ArrayList<BSkipLevels>(32);
List<BSkipLevels> nextInit = new ArrayList<BSkipLevels>(32);
initializeLevels(toInit);
while (!toInit.isEmpty()) {
for (BSkipLevels bsl : toInit) {
bsl.initializeLevels(nextInit);
}
List<BSkipLevels> tmp = toInit;
toInit = nextInit;
nextInit = tmp;
nextInit.clear();
}
}
/**
* Non-recursive initializer.
* MUST be called after constructor.
*
* @param nextInit out parameter, next levels to initialize
* @since 0.9.20
*/
private void initializeLevels(List<BSkipLevels> nextInit) {
boolean fail = false;
for(int i = 0; i < nonNull; i++) {
for(int i = 0; i < lps.length; i++) {
int lp = lps[i];
if(lp != 0) {
levels[i] = bsl.levelHash.get(Integer.valueOf(lp));
if(levels[i] == null) {
try {
// FIXME this will explode the stack if too big
// Redo this without recursion?
// Lots of recursion in super to be fixed also...
levels[i] = new BSkipLevels(bf, lp, bsl);
bsl.levelHash.put(Integer.valueOf(lp), levels[i]);
BSkipLevels lev = new BSkipLevels(bf, lp, bsl);
levels[i] = lev;
nextInit.add(lev);
} catch (IOException ioe) {
bf.log.error("Corrupt database, bad level " + i +
" at page " + lp, ioe);
@ -129,7 +172,9 @@ public class BSkipLevels extends SkipLevels {
// TODO also check that the level[] array is not out-of-order
} else {
if (bf.log.shouldLog(Log.WARN))
bf.log.warn("WTF " + this + " i = " + i + " of " + nonNull + " / " + maxLen + " valid levels but page is zero");
bf.log.warn("WTF " + this + " i = " + i + " of " +
lps.length + " / " + levels.length +
" valid levels but page is zero");
levels[i] = null;
fail = true;
}
@ -200,6 +245,7 @@ public class BSkipLevels extends SkipLevels {
if (bf.log.shouldLog(Log.DEBUG))
bf.log.debug("New BSkipLevels height " + levels + " page " + page);
return new BSkipLevels(bf, page, bsl);
// do not need to call initLevels() here
} catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); }
}
@ -382,7 +428,8 @@ public class BSkipLevels extends SkipLevels {
@Override
public String toString() {
String rv = "BSL height: " + levels.length + " page: " + levelPage + " span: " + bottom;
String rv = "BSLevel height: " + levels.length + " page: " + levelPage + " span: " + bottom +
" in skiplist " + bsl;
if (isKilled)
rv += " KILLED";
return rv;

View File

@ -91,7 +91,9 @@ public class BSkipList extends SkipList {
first = new IBSkipSpan(bf, this, firstSpanPage, key, val);
else
first = new BSkipSpan(bf, this, firstSpanPage, key, val);
stack = new BSkipLevels(bf, firstLevelPage, this);
BSkipLevels bstack = new BSkipLevels(bf, firstLevelPage, this);
bstack.initializeLevels();
stack = bstack;
int total = 0;
for (BSkipSpan ss : spanHash.values()) {
total += ss.nKeys;

View File

@ -0,0 +1,296 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn.ssl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.NoSuchElementException;
import javax.naming.InvalidNameException;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.security.auth.x500.X500Principal;
import org.apache.http.conn.util.InetAddressUtils;
import org.apache.http.conn.util.PublicSuffixMatcher;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
/**
* Default {@link javax.net.ssl.HostnameVerifier} implementation.
*
* @since 4.4
*/
public final class DefaultHostnameVerifier implements HostnameVerifier {
final static int DNS_NAME_TYPE = 2;
final static int IP_ADDRESS_TYPE = 7;
private final Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
private final PublicSuffixMatcher publicSuffixMatcher;
public DefaultHostnameVerifier(final PublicSuffixMatcher publicSuffixMatcher) {
this.publicSuffixMatcher = publicSuffixMatcher;
}
public DefaultHostnameVerifier() {
this(null);
}
@Override
public final boolean verify(final String host, final SSLSession session) {
try {
final Certificate[] certs = session.getPeerCertificates();
final X509Certificate x509 = (X509Certificate) certs[0];
verify(host, x509);
return true;
} catch(final SSLException ex) {
if (log.shouldWarn()) {
log.warn(ex.getMessage(), ex);
}
return false;
}
}
public final void verify(
final String host, final X509Certificate cert) throws SSLException {
final boolean ipv4 = InetAddressUtils.isIPv4Address(host);
final boolean ipv6 = InetAddressUtils.isIPv6Address(host);
final int subjectType = ipv4 || ipv6 ? IP_ADDRESS_TYPE : DNS_NAME_TYPE;
final List<String> subjectAlts = extractSubjectAlts(cert, subjectType);
if (subjectAlts != null && !subjectAlts.isEmpty()) {
if (ipv4) {
matchIPAddress(host, subjectAlts);
} else if (ipv6) {
matchIPv6Address(host, subjectAlts);
} else {
matchDNSName(host, subjectAlts, this.publicSuffixMatcher);
}
} else {
// CN matching has been deprecated by rfc2818 and can be used
// as fallback only when no subjectAlts are available
final X500Principal subjectPrincipal = cert.getSubjectX500Principal();
final String cn = extractCN(subjectPrincipal.getName(X500Principal.RFC2253));
if (cn == null) {
throw new SSLException("Certificate subject for <" + host + "> doesn't contain " +
"a common name and does not have alternative names");
}
matchCN(host, cn, this.publicSuffixMatcher);
}
}
static void matchIPAddress(final String host, final List<String> subjectAlts) throws SSLException {
for (int i = 0; i < subjectAlts.size(); i++) {
final String subjectAlt = subjectAlts.get(i);
if (host.equals(subjectAlt)) {
return;
}
}
throw new SSLException("Certificate for <" + host + "> doesn't match any " +
"of the subject alternative names: " + subjectAlts);
}
static void matchIPv6Address(final String host, final List<String> subjectAlts) throws SSLException {
final String normalisedHost = normaliseAddress(host);
for (int i = 0; i < subjectAlts.size(); i++) {
final String subjectAlt = subjectAlts.get(i);
final String normalizedSubjectAlt = normaliseAddress(subjectAlt);
if (normalisedHost.equals(normalizedSubjectAlt)) {
return;
}
}
throw new SSLException("Certificate for <" + host + "> doesn't match any " +
"of the subject alternative names: " + subjectAlts);
}
static void matchDNSName(final String host, final List<String> subjectAlts,
final PublicSuffixMatcher publicSuffixMatcher) throws SSLException {
final String normalizedHost = host.toLowerCase(Locale.ROOT);
for (int i = 0; i < subjectAlts.size(); i++) {
final String subjectAlt = subjectAlts.get(i);
final String normalizedSubjectAlt = subjectAlt.toLowerCase(Locale.ROOT);
if (matchIdentityStrict(normalizedHost, normalizedSubjectAlt, publicSuffixMatcher)) {
return;
}
}
throw new SSLException("Certificate for <" + host + "> doesn't match any " +
"of the subject alternative names: " + subjectAlts);
}
static void matchCN(final String host, final String cn,
final PublicSuffixMatcher publicSuffixMatcher) throws SSLException {
if (!matchIdentityStrict(host, cn, publicSuffixMatcher)) {
throw new SSLException("Certificate for <" + host + "> doesn't match " +
"common name of the certificate subject: " + cn);
}
}
static boolean matchDomainRoot(final String host, final String domainRoot) {
if (domainRoot == null) {
return false;
}
return host.endsWith(domainRoot) && (host.length() == domainRoot.length()
|| host.charAt(host.length() - domainRoot.length() - 1) == '.');
}
private static boolean matchIdentity(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher,
final boolean strict) {
if (publicSuffixMatcher != null && host.contains(".")) {
if (!matchDomainRoot(host, publicSuffixMatcher.getDomainRoot(identity))) {
return false;
}
}
// RFC 2818, 3.1. Server Identity
// "...Names may contain the wildcard
// character * which is considered to match any single domain name
// component or component fragment..."
// Based on this statement presuming only singular wildcard is legal
final int asteriskIdx = identity.indexOf('*');
if (asteriskIdx != -1) {
final String prefix = identity.substring(0, asteriskIdx);
final String suffix = identity.substring(asteriskIdx + 1);
if (!prefix.isEmpty() && !host.startsWith(prefix)) {
return false;
}
if (!suffix.isEmpty() && !host.endsWith(suffix)) {
return false;
}
// Additional sanity checks on content selected by wildcard can be done here
if (strict) {
final String remainder = host.substring(
prefix.length(), host.length() - suffix.length());
if (remainder.contains(".")) {
return false;
}
}
return true;
}
return host.equalsIgnoreCase(identity);
}
static boolean matchIdentity(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher) {
return matchIdentity(host, identity, publicSuffixMatcher, false);
}
static boolean matchIdentity(final String host, final String identity) {
return matchIdentity(host, identity, null, false);
}
static boolean matchIdentityStrict(final String host, final String identity,
final PublicSuffixMatcher publicSuffixMatcher) {
return matchIdentity(host, identity, publicSuffixMatcher, true);
}
static boolean matchIdentityStrict(final String host, final String identity) {
return matchIdentity(host, identity, null, true);
}
static String extractCN(final String subjectPrincipal) throws SSLException {
if (subjectPrincipal == null) {
return null;
}
try {
final LdapName subjectDN = new LdapName(subjectPrincipal);
final List<Rdn> rdns = subjectDN.getRdns();
for (int i = rdns.size() - 1; i >= 0; i--) {
final Rdn rds = rdns.get(i);
final Attributes attributes = rds.toAttributes();
final Attribute cn = attributes.get("cn");
if (cn != null) {
try {
final Object value = cn.get();
if (value != null) {
return value.toString();
}
} catch (NoSuchElementException ignore) {
} catch (NamingException ignore) {
}
}
}
return null;
} catch (InvalidNameException e) {
throw new SSLException(subjectPrincipal + " is not a valid X500 distinguished name");
}
}
static List<String> extractSubjectAlts(final X509Certificate cert, final int subjectType) {
Collection<List<?>> c = null;
try {
c = cert.getSubjectAlternativeNames();
} catch(final CertificateParsingException ignore) {
}
List<String> subjectAltList = null;
if (c != null) {
for (final List<?> aC : c) {
final List<?> list = aC;
final int type = ((Integer) list.get(0)).intValue();
if (type == subjectType) {
final String s = (String) list.get(1);
if (subjectAltList == null) {
subjectAltList = new ArrayList<String>();
}
subjectAltList.add(s);
}
}
}
return subjectAltList;
}
/*
* Normalize IPv6 or DNS name.
*/
static String normaliseAddress(final String hostname) {
if (hostname == null) {
return hostname;
}
try {
final InetAddress inetAddress = InetAddress.getByName(hostname);
return inetAddress.getHostAddress();
} catch (final UnknownHostException unexpected) { // Should not happen, because we check for IPv6 address above
return hostname;
}
}
}

View File

@ -0,0 +1,8 @@
<html><body>
<p>
From Apache HttpClient 4.4.1.
For I2PSSSLSocketFactory.
Small modifications to remove additional Apache dependencies.
Apache 2.0 license.
</p>
</body></html>

View File

@ -0,0 +1,122 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn.util;
import java.util.regex.Pattern;
/**
* A collection of utilities relating to InetAddresses.
*
* @since 4.0
*/
public class InetAddressUtils {
private InetAddressUtils() {
}
private static final String IPV4_BASIC_PATTERN_STRING =
"(([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){1}" + // initial first field, 1-255
"(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){2}" + // following 2 fields, 0-255 followed by .
"([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])"; // final field, 0-255
private static final Pattern IPV4_PATTERN =
Pattern.compile("^" + IPV4_BASIC_PATTERN_STRING + "$");
private static final Pattern IPV4_MAPPED_IPV6_PATTERN = // TODO does not allow for redundant leading zeros
Pattern.compile("^::[fF]{4}:" + IPV4_BASIC_PATTERN_STRING + "$");
private static final Pattern IPV6_STD_PATTERN =
Pattern.compile(
"^[0-9a-fA-F]{1,4}(:[0-9a-fA-F]{1,4}){7}$");
private static final Pattern IPV6_HEX_COMPRESSED_PATTERN =
Pattern.compile(
"^(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)" + // 0-6 hex fields
"::" +
"(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); // 0-6 hex fields
/*
* The above pattern is not totally rigorous as it allows for more than 7 hex fields in total
*/
private static final char COLON_CHAR = ':';
// Must not have more than 7 colons (i.e. 8 fields)
private static final int MAX_COLON_COUNT = 7;
/**
* Checks whether the parameter is a valid IPv4 address
*
* @param input the address string to check for validity
* @return true if the input parameter is a valid IPv4 address
*/
public static boolean isIPv4Address(final String input) {
return IPV4_PATTERN.matcher(input).matches();
}
public static boolean isIPv4MappedIPv64Address(final String input) {
return IPV4_MAPPED_IPV6_PATTERN.matcher(input).matches();
}
/**
* Checks whether the parameter is a valid standard (non-compressed) IPv6 address
*
* @param input the address string to check for validity
* @return true if the input parameter is a valid standard (non-compressed) IPv6 address
*/
public static boolean isIPv6StdAddress(final String input) {
return IPV6_STD_PATTERN.matcher(input).matches();
}
/**
* Checks whether the parameter is a valid compressed IPv6 address
*
* @param input the address string to check for validity
* @return true if the input parameter is a valid compressed IPv6 address
*/
public static boolean isIPv6HexCompressedAddress(final String input) {
int colonCount = 0;
for(int i = 0; i < input.length(); i++) {
if (input.charAt(i) == COLON_CHAR) {
colonCount++;
}
}
return colonCount <= MAX_COLON_COUNT && IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
}
/**
* Checks whether the parameter is a valid IPv6 address (including compressed).
*
* @param input the address string to check for validity
* @return true if the input parameter is a valid standard or compressed IPv6 address
*/
public static boolean isIPv6Address(final String input) {
return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input);
}
}

View File

@ -0,0 +1,61 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn.util;
import java.util.Collections;
import java.util.List;
import org.apache.http.util.Args;
/**
* Public suffix is a set of DNS names or wildcards concatenated with dots. It represents
* the part of a domain name which is not under the control of the individual registrant
* <p>
* An up-to-date list of suffixes can be obtained from
* <a href="http://publicsuffix.org/">publicsuffix.org</a>
*
* @since 4.4
*/
public final class PublicSuffixList {
private final List<String> rules;
private final List<String> exceptions;
public PublicSuffixList(final List<String> rules, final List<String> exceptions) {
this.rules = Collections.unmodifiableList(Args.notNull(rules, "Domain suffix rules"));
this.exceptions = Collections.unmodifiableList(Args.notNull(exceptions, "Domain suffix exceptions"));
}
public List<String> getRules() {
return rules;
}
public List<String> getExceptions() {
return exceptions;
}
}

View File

@ -0,0 +1,112 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* Parses the list from <a href="http://publicsuffix.org/">publicsuffix.org</a>
* and configures a PublicSuffixFilter.
*
* @since 4.4
*/
public final class PublicSuffixListParser {
private static final int MAX_LINE_LEN = 256;
public PublicSuffixListParser() {
}
/**
* Parses the public suffix list format. When creating the reader from the file, make sure to
* use the correct encoding (the original list is in UTF-8).
*
* @param reader the data reader. The caller is responsible for closing the reader.
* @throws java.io.IOException on error while reading from list
*/
public PublicSuffixList parse(final Reader reader) throws IOException {
final List<String> rules = new ArrayList<String>();
final List<String> exceptions = new ArrayList<String>();
final BufferedReader r = new BufferedReader(reader);
final StringBuilder sb = new StringBuilder(256);
boolean more = true;
while (more) {
more = readLine(r, sb);
String line = sb.toString();
if (line.isEmpty()) {
continue;
}
if (line.startsWith("//")) {
continue; //entire lines can also be commented using //
}
if (line.startsWith(".")) {
line = line.substring(1); // A leading dot is optional
}
// An exclamation mark (!) at the start of a rule marks an exception to a previous wildcard rule
final boolean isException = line.startsWith("!");
if (isException) {
line = line.substring(1);
}
if (isException) {
exceptions.add(line);
} else {
rules.add(line);
}
}
return new PublicSuffixList(rules, exceptions);
}
private boolean readLine(final Reader r, final StringBuilder sb) throws IOException {
sb.setLength(0);
int b;
boolean hitWhitespace = false;
while ((b = r.read()) != -1) {
final char c = (char) b;
if (c == '\n') {
break;
}
// Each line is only read up to the first whitespace
if (Character.isWhitespace(c)) {
hitWhitespace = true;
}
if (!hitWhitespace) {
sb.append(c);
}
if (sb.length() > MAX_LINE_LEN) {
return false; // prevent excess memory usage
}
}
return (b != -1);
}
}

View File

@ -0,0 +1,119 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.conn.util;
import java.net.IDN;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.http.util.Args;
/**
* Utility class that can test if DNS names match the content of the Public Suffix List.
* <p>
* An up-to-date list of suffixes can be obtained from
* <a href="http://publicsuffix.org/">publicsuffix.org</a>
*
* @see org.apache.http.conn.util.PublicSuffixList
*
* @since 4.4
*/
public final class PublicSuffixMatcher {
private final Map<String, String> rules;
private final Map<String, String> exceptions;
public PublicSuffixMatcher(final Collection<String> rules, final Collection<String> exceptions) {
Args.notNull(rules, "Domain suffix rules");
this.rules = new ConcurrentHashMap<String, String>(rules.size());
for (String rule: rules) {
this.rules.put(rule, rule);
}
if (exceptions != null) {
this.exceptions = new ConcurrentHashMap<String, String>(exceptions.size());
for (String exception: exceptions) {
this.exceptions.put(exception, exception);
}
} else {
this.exceptions = null;
}
}
/**
* Returns registrable part of the domain for the given domain name of {@code null}
* if given domain represents a public suffix.
*
* @param domain
* @return domain root
*/
public String getDomainRoot(final String domain) {
if (domain == null) {
return null;
}
if (domain.startsWith(".")) {
return null;
}
String domainName = null;
String segment = domain.toLowerCase(Locale.ROOT);
while (segment != null) {
// An exception rule takes priority over any other matching rule.
if (this.exceptions != null && this.exceptions.containsKey(IDN.toUnicode(segment))) {
return segment;
}
if (this.rules.containsKey(IDN.toUnicode(segment))) {
break;
}
final int nextdot = segment.indexOf('.');
final String nextSegment = nextdot != -1 ? segment.substring(nextdot + 1) : null;
if (nextSegment != null) {
if (this.rules.containsKey("*." + IDN.toUnicode(nextSegment))) {
break;
}
}
if (nextdot != -1) {
domainName = segment;
}
segment = nextSegment;
}
return domainName;
}
public boolean matches(final String domain) {
if (domain == null) {
return false;
}
final String domainRoot = getDomainRoot(domain.startsWith(".") ? domain.substring(1) : domain);
return domainRoot == null;
}
}

View File

@ -0,0 +1,8 @@
<html><body>
<p>
From Apache HttpClient 4.4.1.
For HostnameVerifier.
Small modifications to remove additional Apache dependencies.
Apache 2.0 license.
</p>
</body></html>

View File

@ -0,0 +1,38 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.util;
public class Args {
public static <T> T notNull(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
return argument;
}
}

View File

@ -0,0 +1,8 @@
<html><body>
<p>
From Apache HttpCore 4.4.1.
For HostnameVerifier.
Small modifications to remove additional Apache dependencies.
Apache 2.0 license.
</p>
</body></html>