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

to branch 'i2p.i2p.zzz.test2' (head 6212892778308db10a86e58f9f275c838f604973)
This commit is contained in:
zzz
2014-09-09 19:27:10 +00:00
83 changed files with 1081 additions and 236 deletions

View File

@@ -54,8 +54,15 @@ public interface CompleteListener {
*/
public void gotPiece(Snark snark);
// not really listeners but the easiest way to get back to an optional SnarkManager
/** not really listeners but the easiest way to get back to an optional SnarkManager */
public long getSavedTorrentTime(Snark snark);
public BitField getSavedTorrentBitField(Snark snark);
/**
* @since 0.9.15
*/
public boolean getSavedPreserveNamesSetting(Snark snark);
/**
* @since 0.9.15
*/
public long getSavedUploaded(Snark snark);
}

View File

@@ -281,6 +281,14 @@ class PeerCoordinator implements PeerListener
return uploaded;
}
/**
* Sets the initial total of uploaded bytes of all peers (from a saved status)
* @since 0.9.15
*/
public void setUploaded(long up) {
uploaded = up;
}
/**
* Returns the total number of downloaded bytes of all peers.
*/

View File

@@ -237,6 +237,7 @@ public class Snark
private volatile boolean _autoStoppable;
// String indicating main activity
private volatile String activity = "Not started";
private final long savedUploaded;
/**
@@ -463,6 +464,7 @@ public class Snark
trackerclient = new TrackerClient(meta, coordinator);
*/
savedUploaded = (completeListener != null) ? completeListener.getSavedUploaded(this) : 0;
if (start)
startTorrent();
}
@@ -488,6 +490,7 @@ public class Snark
this.infoHash = ih;
this.additionalTrackerURL = trackerURL;
this.rootDataDir = rootDir != null ? new File(rootDir) : null; // null only for FetchAndAdd extension
savedUploaded = 0;
stopped = true;
id = generateID();
@@ -556,6 +559,7 @@ public class Snark
_log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient");
activity = "Collecting pieces";
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
coordinator.setUploaded(savedUploaded);
if (_peerCoordinatorSet != null) {
// multitorrent
_peerCoordinatorSet.add(coordinator);
@@ -619,7 +623,7 @@ public class Snark
pc.halt();
Storage st = storage;
if (st != null) {
boolean changed = storage.isChanged();
boolean changed = storage.isChanged() || getUploaded() != savedUploaded;
try {
storage.close();
} catch (IOException ioe) {
@@ -773,7 +777,7 @@ public class Snark
PeerCoordinator coord = coordinator;
if (coord != null)
return coord.getUploaded();
return 0;
return savedUploaded;
}
/**

View File

@@ -92,6 +92,7 @@ public class SnarkManager implements CompleteListener {
private static final String PROP_META_BITFIELD = "bitfield";
private static final String PROP_META_PRIORITY = "priority";
private static final String PROP_META_PRESERVE_NAMES = "preserveFileNames";
private static final String PROP_META_UPLOADED = "uploaded";
//private static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
//private static final String PROP_META_PRIORITY_SUFFIX = ".priority";
private static final String PROP_META_MAGNET_PREFIX = "i2psnark.magnet.";
@@ -128,6 +129,9 @@ public class SnarkManager implements CompleteListener {
/**
* "name", "announceURL=websiteURL" pairs
* '=' in announceURL must be escaped as ,
*
* Please use host name, not b32 or full dest, in announce URL. Ensure in default hosts.txt.
* Please use host name, not b32 or full dest, in website URL. Ensure in default hosts.txt.
*/
private static final String DEFAULT_TRACKERS[] = {
// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/"
@@ -1357,7 +1361,7 @@ public class SnarkManager implements CompleteListener {
return false;
}
// so addTorrent won't recheck
saveTorrentStatus(metainfo, bitfield, null, baseFile, true); // no file priorities
saveTorrentStatus(metainfo, bitfield, null, baseFile, true, 0); // no file priorities
try {
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
// hold the lock for a long time
@@ -1522,6 +1526,21 @@ public class SnarkManager implements CompleteListener {
Properties config = getConfig(snark);
return Boolean.parseBoolean(config.getProperty(PROP_META_PRESERVE_NAMES));
}
/**
* Get setting for a torrent from the config file.
* @return setting, 0 if not found
* @since 0.9.15
*/
public long getSavedUploaded(Snark snark) {
Properties config = getConfig(snark);
if (config != null) {
try {
return Long.parseLong(config.getProperty(PROP_META_UPLOADED));
} catch (NumberFormatException nfe) {}
}
return 0;
}
/**
* Save the completion status of a torrent and other data in the config file
@@ -1535,7 +1554,8 @@ public class SnarkManager implements CompleteListener {
if (meta == null || storage == null)
return;
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
storage.getBase(), storage.getPreserveFileNames());
storage.getBase(), storage.getPreserveFileNames(),
snark.getUploaded());
}
/**
@@ -1550,14 +1570,14 @@ public class SnarkManager implements CompleteListener {
* @param base may be null
*/
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
File base, boolean preserveNames) {
File base, boolean preserveNames, long uploaded) {
synchronized (_configLock) {
locked_saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames);
locked_saveTorrentStatus(metainfo, bitfield, priorities, base, preserveNames, uploaded);
}
}
private void locked_saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities,
File base, boolean preserveNames) {
File base, boolean preserveNames, long uploaded) {
byte[] ih = metainfo.getInfoHash();
String bfs;
if (bitfield.complete()) {
@@ -1570,6 +1590,7 @@ public class SnarkManager implements CompleteListener {
config.setProperty(PROP_META_STAMP, Long.toString(System.currentTimeMillis()));
config.setProperty(PROP_META_BITFIELD, bfs);
config.setProperty(PROP_META_PRESERVE_NAMES, Boolean.toString(preserveNames));
config.setProperty(PROP_META_UPLOADED, Long.toString(uploaded));
if (base != null)
config.setProperty(PROP_META_BASE, base.getAbsolutePath());
@@ -1826,7 +1847,7 @@ public class SnarkManager implements CompleteListener {
Storage storage = snark.getStorage();
if (meta != null && storage != null)
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(),
storage.getBase(), storage.getPreserveFileNames());
storage.getBase(), storage.getPreserveFileNames(), snark.getUploaded());
}
/**
@@ -1849,7 +1870,7 @@ public class SnarkManager implements CompleteListener {
return null;
}
saveTorrentStatus(meta, storage.getBitField(), null,
storage.getBase(), storage.getPreserveFileNames()); // no file priorities
storage.getBase(), storage.getPreserveFileNames(), 0);
// temp for addMessage() in case canonical throws
String name = storage.getBaseName();
try {

View File

@@ -316,15 +316,34 @@ public class Storage
}
/**
* Get index to pass to remaining(), getPriority(), setPriority()
*
* @param file non-canonical path (non-directory)
* @return internal index of file; -1 if unknown file
* @since 0.9.15
*/
public int indexOf(File file) {
for (int i = 0; i < _torrentFiles.size(); i++) {
File f = _torrentFiles.get(i).RAFfile;
if (f.equals(file))
return i;
}
return -1;
}
/**
* @param fileIndex as obtained from indexOf
* @return number of bytes remaining; -1 if unknown file
* @since 0.7.14
*/
public long remaining(File file) {
public long remaining(int fileIndex) {
if (fileIndex < 0 || fileIndex >= _torrentFiles.size())
return -1;
long bytes = 0;
for (TorrentFile tf : _torrentFiles) {
File f = tf.RAFfile;
if (f.equals(file)) {
for (int i = 0; i < _torrentFiles.size(); i++) {
TorrentFile tf = _torrentFiles.get(i);
if (i == fileIndex) {
File f = tf.RAFfile;
if (complete())
return 0;
int psz = piece_size;
@@ -350,37 +369,30 @@ public class Storage
}
/**
* @param file non-canonical path (non-directory)
* @param fileIndex as obtained from indexOf
* @since 0.8.1
*/
public int getPriority(File file) {
public int getPriority(int fileIndex) {
if (complete() || metainfo.getFiles() == null)
return 0;
for (TorrentFile tf : _torrentFiles) {
File f = tf.RAFfile;
if (f.equals(file))
return tf.priority;
}
return 0;
if (fileIndex < 0 || fileIndex >= _torrentFiles.size())
return 0;
return _torrentFiles.get(fileIndex).priority;
}
/**
* Must call Snark.updatePiecePriorities()
* (which calls getPiecePriorities()) after calling this.
* @param file non-canonical path (non-directory)
* @param fileIndex as obtained from indexOf
* @param pri default 0; <0 to disable
* @since 0.8.1
*/
public void setPriority(File file, int pri) {
public void setPriority(int fileIndex, int pri) {
if (complete() || metainfo.getFiles() == null)
return;
for (TorrentFile tf : _torrentFiles) {
File f = tf.RAFfile;
if (f.equals(file)) {
tf.priority = pri;
return;
}
}
if (fileIndex < 0 || fileIndex >= _torrentFiles.size())
return;
_torrentFiles.get(fileIndex).priority = pri;
}
/**

View File

@@ -72,6 +72,8 @@ public class TrackerClient implements Runnable {
private static final String STOPPED_EVENT = "stopped";
private static final String NOT_REGISTERED = "torrent not registered"; //bytemonsoon
private static final String NOT_REGISTERED_2 = "torrent not found"; // diftracker
private static final String NOT_REGISTERED_3 = "torrent unauthorised"; // vuze
private static final String ERROR_GOT_HTML = "received html"; // fake return
/** this is our equivalent to router.utorrent.com for bootstrap */
private static final String DEFAULT_BACKUP_TRACKER = "http://tracker.welterde.i2p/a";
@@ -577,14 +579,20 @@ public class TrackerClient implements Runnable {
if (tr.isPrimary)
snark.setTrackerProblems(tr.trackerProblems);
String tplc = tr.trackerProblems.toLowerCase(Locale.US);
if (tplc.startsWith(NOT_REGISTERED) || tplc.startsWith(NOT_REGISTERED_2)) {
if (tplc.startsWith(NOT_REGISTERED) || tplc.startsWith(NOT_REGISTERED_2) ||
tplc.startsWith(NOT_REGISTERED_3) || tplc.startsWith(ERROR_GOT_HTML)) {
// Give a guy some time to register it if using opentrackers too
//if (trckrs.size() == 1) {
// stop = true;
// snark.stopTorrent();
//} else { // hopefully each on the opentrackers list is really open
if (tr.registerFails++ > MAX_REGISTER_FAILS ||
!completed || // no use retrying if we aren't seeding
tplc.startsWith(ERROR_GOT_HTML) || // fake msg from doRequest()
(!tr.isPrimary && tr.registerFails > MAX_REGISTER_FAILS / 2))
if (_log.shouldLog(Log.WARN))
_log.warn("Not longer announcing to " + tr.announce + " : " +
tr.trackerProblems + " after " + tr.registerFails + " failures");
tr.stop = true;
//
}
@@ -797,10 +805,15 @@ public class TrackerClient implements Runnable {
tr.lastRequestTime = System.currentTimeMillis();
// Don't wait for a response to stopped when shutting down
boolean fast = _fastUnannounce && event.equals(STOPPED_EVENT);
byte[] fetched = _util.get(s, true, fast ? -1 : 0, small ? 128 : 1024, small ? 1024 : 8*1024);
if (fetched == null) {
throw new IOException("Error fetching " + s);
}
byte[] fetched = _util.get(s, true, fast ? -1 : 0, small ? 128 : 1024, small ? 1024 : 32*1024);
if (fetched == null)
throw new IOException("Error fetching");
if (fetched.length == 0)
throw new IOException("No data");
// The HTML check only works if we didn't exceed the maxium fetch size specified in get(),
// otherwise we already threw an IOE.
if (fetched[0] == '<')
throw new IOException(ERROR_GOT_HTML);
InputStream in = new ByteArrayInputStream(fetched);

View File

@@ -295,6 +295,10 @@ class UpdateRunner implements UpdateTask, CompleteListener {
return _smgr.getSavedPreserveNamesSetting(snark);
}
public long getSavedUploaded(Snark snark) {
return _smgr.getSavedUploaded(snark);
}
//////// end CompleteListener methods
private static String linkify(String url) {

View File

@@ -25,8 +25,10 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.i2p.data.Base32;
import net.i2p.data.Base64;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.util.Log;
import org.klomp.snark.I2PSnarkUtil;
@@ -498,7 +500,7 @@ public class I2PSnarkServlet extends BasicServlet {
out.write(_("RX"));
out.write("\">");
out.write("</th>\n<th align=\"right\">");
if (_manager.util().connected() && !snarks.isEmpty()) {
if (!snarks.isEmpty()) {
out.write("<img border=\"0\" src=\"" + _imgPath + "head_tx.png\" title=\"");
out.write(_("Uploaded"));
out.write("\" alt=\"");
@@ -1430,8 +1432,7 @@ public class I2PSnarkServlet extends BasicServlet {
out.write("</td><td class=\"snarkTorrentName\"");
if (isMultiFile) {
// link on the whole td
String jsec = encodedBaseName.replace("'", "\\'");
out.write(" onclick=\"document.location='" + jsec + "/';\">");
out.write(" onclick=\"document.location='" + encodedBaseName + "/';\">");
} else {
out.write('>');
}
@@ -1465,15 +1466,15 @@ public class I2PSnarkServlet extends BasicServlet {
// out.write("??"); // no meta size yet
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentUploaded\">");
if(isRunning && isValid)
if (isValid && uploaded > 0)
out.write(formatSize(uploaded));
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
if(isRunning && needed > 0)
if (isRunning && needed > 0)
out.write(formatSize(downBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
if(isRunning && isValid)
if (isRunning && isValid)
out.write(formatSize(upBps) + "ps");
out.write("</td>\n\t");
out.write("<td align=\"center\" class=\"snarkTorrentAction\">");
@@ -1717,8 +1718,10 @@ public class I2PSnarkServlet extends BasicServlet {
}
/**
* Start of anchor only, caller must add anchor text or img and close anchor
* @return string or null
* Generate link to details page if we know it supports it.
* Start of anchor only, caller must add anchor text or img and close anchor.
*
* @return string or null if unknown tracker
* @since 0.8.4
*/
private String getTrackerLinkUrl(String announce, byte[] infohash) {
@@ -1745,8 +1748,8 @@ public class I2PSnarkServlet extends BasicServlet {
}
/**
* Full anchor with img
* @return string or null
* Full link to details page with img
* @return string or null if details page unsupported
* @since 0.8.4
*/
private String getTrackerLink(String announce, byte[] infohash) {
@@ -1762,7 +1765,7 @@ public class I2PSnarkServlet extends BasicServlet {
}
/**
* Full anchor with shortened URL as anchor text
* Full anchor to home page or details page with shortened host name as anchor text
* @return string, non-null
* @since 0.9.5
*/
@@ -1771,14 +1774,37 @@ public class I2PSnarkServlet extends BasicServlet {
String trackerLinkUrl = getTrackerLinkUrl(announce, infohash);
if (announce.startsWith("http://"))
announce = announce.substring(7);
// strip path
int slsh = announce.indexOf('/');
if (slsh > 0)
announce = announce.substring(0, slsh);
if (trackerLinkUrl != null)
if (trackerLinkUrl != null) {
buf.append(trackerLinkUrl);
else
// TODO encode
buf.append("<a href=\"http://").append(urlEncode(announce)).append("/\">");
} else {
// browsers don't like a full b64 dest, so convert it to b32
String host = announce;
if (host.length() >= 516) {
int colon = announce.indexOf(':');
String port = "";
if (colon > 0) {
port = host.substring(colon);
host = host.substring(0, colon);
}
if (host.endsWith(".i2p"))
host = host.substring(0, host.length() - 4);
byte[] b = Base64.decode(host);
if (b != null) {
Hash h = _context.sha().calculateHash(b);
// should we add the port back or strip it?
host = Base32.encode(h.getData()) + ".b32.i2p" + port;
}
}
buf.append("<a href=\"http://").append(urlEncode(host)).append("/\">");
}
// strip port
int colon = announce.indexOf(':');
if (colon > 0)
announce = announce.substring(0, colon);
if (announce.length() > 67)
announce = DataHelper.escapeHTML(announce.substring(0, 40)) + "&hellip;" +
DataHelper.escapeHTML(announce.substring(announce.length() - 8));
@@ -2673,6 +2699,7 @@ public class I2PSnarkServlet extends BasicServlet {
boolean complete = false;
String status = "";
long length = item.length();
int fileIndex = -1;
int priority = 0;
if (item.isDirectory()) {
complete = true;
@@ -2684,8 +2711,9 @@ public class I2PSnarkServlet extends BasicServlet {
status = toImg("cancel") + ' ' + _("Torrent not found?");
} else {
Storage storage = snark.getStorage();
fileIndex = storage.indexOf(item);
long remaining = storage.remaining(item);
long remaining = storage.remaining(fileIndex);
if (remaining < 0) {
complete = true;
status = toImg("cancel") + ' ' + _("File not found in torrent?");
@@ -2693,7 +2721,7 @@ public class I2PSnarkServlet extends BasicServlet {
complete = true;
status = toImg("tick") + ' ' + _("Complete");
} else {
priority = storage.getPriority(item);
priority = storage.getPriority(fileIndex);
if (priority < 0)
status = toImg("cancel");
else if (priority == 0)
@@ -2745,17 +2773,17 @@ public class I2PSnarkServlet extends BasicServlet {
if (showPriority) {
buf.append("<td class=\"priority\">");
if ((!complete) && (!item.isDirectory())) {
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(item).append("\" ");
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prihigh\" value=\"5\" name=\"pri.").append(fileIndex).append("\" ");
if (priority > 0)
buf.append("checked=\"checked\"");
buf.append('>').append(_("High"));
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(item).append("\" ");
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"prinorm\" value=\"0\" name=\"pri.").append(fileIndex).append("\" ");
if (priority == 0)
buf.append("checked=\"checked\"");
buf.append('>').append(_("Normal"));
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(item).append("\" ");
buf.append("\n<input type=\"radio\" onclick=\"priorityclicked();\" class=\"priskip\" value=\"-9\" name=\"pri.").append(fileIndex).append("\" ");
if (priority < 0)
buf.append("checked=\"checked\"");
buf.append('>').append(_("Skip"));
@@ -2857,10 +2885,10 @@ public class I2PSnarkServlet extends BasicServlet {
String key = entry.getKey();
if (key.startsWith("pri.")) {
try {
File file = new File(key.substring(4));
int fileIndex = Integer.parseInt(key.substring(4));
String val = entry.getValue()[0]; // jetty arrays
int pri = Integer.parseInt(val);
storage.setPriority(file, pri);
storage.setPriority(fileIndex, pri);
//System.err.println("Priority now " + pri + " for " + file);
} catch (Throwable t) { t.printStackTrace(); }
}

View File

@@ -84,6 +84,7 @@ class URIUtil
case '<':
case '>':
case ' ':
case ':':
buf=new StringBuilder(path.length()*2);
break loop;
default:
@@ -139,6 +140,9 @@ class URIUtil
case 0x7f:
buf.append("%7F");
continue;
case ':':
buf.append("%3A");
continue;
default:
if (c <= 0x1f) // includes negative
toHex(c,buf);
@@ -183,6 +187,9 @@ class URIUtil
case ' ':
buf.append("%20");
continue;
case ':':
buf.append("%3A");
continue;
default:
if (c <= 0x1f || (c >= 0x7f && c <= 0x9f) || Character.isSpaceChar(c))
toHex(c,buf);

View File

@@ -182,6 +182,10 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
if (getTunnel() != tunnel)
return;
setupPostThrottle();
Properties props = tunnel.getClientOptions();
// see TunnelController.setSessionOptions()
String spoofHost = props.getProperty(TunnelController.PROP_SPOOFED_HOST);
_spoofHost = (spoofHost != null && spoofHost.trim().length() > 0) ? spoofHost.trim() : null;
super.optionsUpdated(tunnel);
}

View File

@@ -16,6 +16,7 @@ import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.util.Map;
import java.util.Properties;
@@ -50,8 +51,8 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
protected final Object slock = new Object();
protected final Object sslLock = new Object();
protected final InetAddress remoteHost;
protected final int remotePort;
protected InetAddress remoteHost;
protected int remotePort;
private final boolean _usePool;
protected final Logging l;
private I2PSSLSocketFactory _sslFactory;
@@ -265,6 +266,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
* Copy input stream to a byte array, so we can retry
* @since 0.7.10
*/
/****
private static ByteArrayInputStream copyOfInputStream(InputStream is) throws IOException {
byte[] buf = new byte[128];
ByteArrayOutputStream os = new ByteArrayOutputStream(768);
@@ -279,6 +281,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
}
return new ByteArrayInputStream(os.toByteArray());
}
****/
/**
* Start running the I2PTunnelServer.
@@ -348,6 +351,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
/**
* Update the I2PSocketManager.
* And since 0.9.15, the target host and port.
*
* @since 0.9.1
*/
@@ -357,6 +361,27 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable {
return;
Properties props = tunnel.getClientOptions();
sockMgr.setDefaultOptions(sockMgr.buildOptions(props));
// see TunnelController.setSessionOptions()
String h = props.getProperty(TunnelController.PROP_TARGET_HOST);
if (h != null) {
try {
remoteHost = InetAddress.getByName(h);
} catch (UnknownHostException uhe) {
l.log("Unknown host: " + h);
}
}
String p = props.getProperty(TunnelController.PROP_TARGET_PORT);
if (p != null) {
try {
int port = Integer.parseInt(p);
if (port > 0 && port <= 65535)
remotePort = port;
else
l.log("Bad port: " + port);
} catch (NumberFormatException nfe) {
l.log("Bad port: " + p);
}
}
buildSocketMap(props);
}

View File

@@ -487,6 +487,17 @@ public class TunnelController implements Logging {
String proxies = getProxyList();
if (proxies != null)
opts.setProperty(PROP_PROXIES, proxies);
// Ditto spoof host. Since 0.9.15.
String spoofhost = getSpoofedHost();
if (spoofhost != null)
opts.setProperty(PROP_SPOOFED_HOST, spoofhost);
// Ditto target host/port. Since 0.9.15.
String targethost = getTargetHost();
if (targethost != null)
opts.setProperty(PROP_TARGET_HOST, targethost);
String targetport = getTargetPort();
if (targetport != null)
opts.setProperty(PROP_TARGET_PORT, targetport);
_tunnel.setClientOptions(opts);
}

View File

@@ -258,6 +258,7 @@ public class IndexBean {
// give the messages a chance to make it to the window
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
// and give them something to look at in any case
// FIXME name will be HTML escaped twice
return _("Starting tunnel") + ' ' + getTunnelName(_tunnel) + "...";
}
@@ -271,6 +272,7 @@ public class IndexBean {
// give the messages a chance to make it to the window
try { Thread.sleep(1000); } catch (InterruptedException ie) {}
// and give them something to look at in any case
// FIXME name will be HTML escaped twice
return _("Stopping tunnel") + ' ' + getTunnelName(_tunnel) + "...";
}
@@ -352,6 +354,7 @@ public class IndexBean {
List<String> msgs = doSave();
if (ksMsg != null)
msgs.add(ksMsg);
// FIXME name will be HTML escaped twice
return getMessages(msgs);
}
@@ -402,7 +405,8 @@ public class IndexBean {
name = Long.toString(_context.clock().now());
}
}
name = "i2ptunnel-deleted-" + name.replace(' ', '_') + '-' + _context.clock().now() + "-privkeys.dat";
name = name.replace(' ', '_').replace(':', '_').replace("..", "_").replace('/', '_').replace('\\', '_');
name = "i2ptunnel-deleted-" + name + '-' + _context.clock().now() + "-privkeys.dat";
File backupDir = new SecureFile(_context.getConfigDir(), TunnelController.KEY_BACKUP_DIR);
File to;
if (backupDir.isDirectory() || backupDir.mkdir())
@@ -451,13 +455,11 @@ public class IndexBean {
}
public boolean allowCSS() {
String css = _context.getProperty(PROP_CSS_DISABLED);
return (css == null);
return !_context.getBooleanProperty(PROP_CSS_DISABLED);
}
public boolean allowJS() {
String js = _context.getProperty(PROP_JS_DISABLED);
return (js == null);
return !_context.getBooleanProperty(PROP_JS_DISABLED);
}
public int getTunnelCount() {
@@ -727,8 +729,9 @@ public class IndexBean {
_name = (name != null ? name.trim() : null);
}
/** one line description */
public void setDescription(String description) {
_description = (description != null ? description.trim() : null);
public void setNofilter_description(String description) {
// '#' will blow up DataHelper.storeProps()
_description = (description != null ? description.replace('#', ' ').trim() : null);
}
/** I2CP host the router is on, ignored when in router context */
public void setClientHost(String host) {

View File

@@ -79,7 +79,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<label for="description" accesskey="e">
<%=intl._("Description")%>:(<span class="accessKey">E</span>)
</label>
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
<input type="text" size="60" maxlength="80" name="nofilter_description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
</div>
<div class="subdivider">
@@ -341,6 +341,23 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<div class="subdivider">
<hr />
</div>
<div id="optionsField" class="rowItem">
<label for="reduce" accesskey="c">
<%=intl._("Delay tunnel open until required")%>(<span class="accessKey">D</span>):
</label>
</div>
<div id="portField" class="rowItem">
<label for="access" accesskey="c">
<%=intl._("Enable")%>:
</label>
<input value="1" type="checkbox" id="startOnLoad" name="delayOpen" title="Delay Tunnel Open"<%=(editBean.getDelayOpen(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
</div>
<% } // !streamrclient %>
<div class="subdivider">
<hr />
</div>
<div id="optionsField" class="rowItem">
<label for="reduce" accesskey="d">
@@ -405,23 +422,6 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<hr />
</div>
<div id="optionsField" class="rowItem">
<label for="reduce" accesskey="c">
<%=intl._("Delay tunnel open until required")%>(<span class="accessKey">D</span>):
</label>
</div>
<div id="portField" class="rowItem">
<label for="access" accesskey="c">
<%=intl._("Enable")%>:
</label>
<input value="1" type="checkbox" id="startOnLoad" name="delayOpen" title="Delay Tunnel Open"<%=(editBean.getDelayOpen(curTunnel) ? " checked=\"checked\"" : "")%> class="tickbox" />
</div>
<% } // !streamrclient %>
<div class="subdivider">
<hr />
</div>
<% if ("client".equals(tunnelType) || "ircclient".equals(tunnelType) || "socksirctunnel".equals(tunnelType) || "sockstunnel".equals(tunnelType)) { %>
<div id="optionsField" class="rowItem">
<label for="privKeyFile" accesskey="k">

View File

@@ -79,7 +79,7 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<label for="description" accesskey="e">
<%=intl._("Description")%>(<span class="accessKey">e</span>):
</label>
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
<input type="text" size="60" maxlength="80" name="nofilter_description" id="description" title="Tunnel Description" value="<%=editBean.getTunnelDescription(curTunnel)%>" class="freetext" />
</div>
<div id="startupField" class="rowItem">
<label for="startOnLoad" accesskey="a">

View File

@@ -233,11 +233,11 @@
<label for="description" accesskey="e">
<%=intl._("Description")%>:(<span class="accessKey">E</span>)
</label>
<input type="text" size="60" maxlength="80" name="description" id="description" title="Tunnel Description" value="<%=(!"null".equals(request.getParameter("description")) ? net.i2p.data.DataHelper.stripHTML(request.getParameter("description")) : "" ) %>" class="freetext" />
<input type="text" size="60" maxlength="80" name="nofilter_description" id="description" title="Tunnel Description" value="<%=(!"null".equals(request.getParameter("description")) ? net.i2p.data.DataHelper.stripHTML(request.getParameter("description")) : "" ) %>" class="freetext" />
</div><%
} else {
%><input type="hidden" name="name" value="<%=net.i2p.data.DataHelper.stripHTML(request.getParameter("name"))%>" />
<input type="hidden" name="description" value="<%=net.i2p.data.DataHelper.stripHTML(request.getParameter("description"))%>" /><%
<input type="hidden" name="nofilter_description" value="<%=net.i2p.data.DataHelper.stripHTML(request.getParameter("description"))%>" /><%
} /* curPage 3 */
/* End page 3 */ %>
@@ -484,7 +484,7 @@
<input type="hidden" name="tunnelBackupQuantity" value="0" />
<input type="hidden" name="clientHost" value="internal" />
<input type="hidden" name="clientport" value="internal" />
<input type="hidden" name="customOptions" value="" />
<input type="hidden" name="nofilter_customOptions" value="" />
<%
if (!"streamrclient".equals(tunnelType)) {
@@ -501,9 +501,9 @@
}
if ("httpclient".equals(tunnelType) || "connectclient".equals(tunnelType) || "sockstunnel".equals(tunnelType) || "socksirctunnel".equals(tunnelType)) {
%><input type="hidden" name="proxyUsername" value="" />
<input type="hidden" name="proxyPassword" value="" />
<input type="hidden" name="nofilter_proxyPassword" value="" />
<input type="hidden" name="outproxyUsername" value="" />
<input type="hidden" name="outproxyPassword" value="" /><%
<input type="hidden" name="nofilter_outproxyPassword" value="" /><%
}
if ("httpclient".equals(tunnelType)) {
%><input type="hidden" name="jumpList" value="http://i2host.i2p/cgi-bin/i2hostjump?

View File

@@ -158,6 +158,8 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
// right at instantiation if the news is already indicating a new version
Checker c = new NewsHandler(_context, this);
register(c, NEWS, HTTP, 0);
// TODO
//register(c, NEWS_SU3, HTTP, 0);
register(c, ROUTER_SIGNED, HTTP, 0); // news is an update checker for the router
Updater u = new UpdateHandler(_context, this);
register(u, ROUTER_SIGNED, HTTP, 0);
@@ -734,9 +736,9 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
UpdateType type, String id,
Map<UpdateMethod, List<URI>> sourceMap,
String newVersion, String minVersion) {
if (type == NEWS) {
if (type == NEWS || type == NEWS_SU3) {
// shortcut
notifyInstalled(NEWS, "", newVersion);
notifyInstalled(type, "", newVersion);
return true;
}
UpdateItem ui = new UpdateItem(type, id);
@@ -806,6 +808,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
String msg = null;
switch (type) {
case NEWS:
case NEWS_SU3:
break;
case ROUTER_UNSIGNED:
@@ -900,6 +903,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
String msg = null;
switch (task.getType()) {
case NEWS:
case NEWS_SU3:
case ROUTER_SIGNED:
case ROUTER_SIGNED_SU3:
case ROUTER_UNSIGNED:
@@ -1009,6 +1013,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
switch (task.getType()) {
case TYPE_DUMMY:
case NEWS:
case NEWS_SU3:
rv = true;
break;
@@ -1132,6 +1137,7 @@ public class ConsoleUpdateManager implements UpdateManager, RouterApp {
switch (type) {
case NEWS:
case NEWS_SU3:
// handled in NewsHandler
break;

View File

@@ -124,6 +124,7 @@ class NewsFetcher extends UpdateRunner {
* Parse the installed (not the temp) news file for the latest version.
* TODO: Real XML parsing
* TODO: Check minVersion, use backup URLs specified
* TODO: SU3
*/
void checkForUpdates() {
FileInputStream in = null;

View File

@@ -29,6 +29,7 @@ class NewsHandler extends UpdateHandler implements Checker {
* @since 0.7.14 not configurable
*/
private static final String BACKUP_NEWS_URL = "http://avviiexdngd32ccoy4kuckvc3mkf53ycvzbz6vz75vzhv4tbpk5a.b32.i2p/news.xml";
private static final String BACKUP_NEWS_URL_SU3 = "http://avviiexdngd32ccoy4kuckvc3mkf53ycvzbz6vz75vzhv4tbpk5a.b32.i2p/news.su3";
public NewsHandler(RouterContext ctx, ConsoleUpdateManager mgr) {
super(ctx, mgr);
@@ -41,14 +42,17 @@ class NewsHandler extends UpdateHandler implements Checker {
*/
public UpdateTask check(UpdateType type, UpdateMethod method,
String id, String currentVersion, long maxTime) {
if ((type != ROUTER_SIGNED && type != NEWS) ||
if ((type != ROUTER_SIGNED && type != NEWS && type != NEWS_SU3) ||
method != HTTP)
return null;
List<URI> updateSources = new ArrayList<URI>(2);
try {
// TODO SU3
updateSources.add(new URI(ConfigUpdateHelper.getNewsURL(_context)));
} catch (URISyntaxException use) {}
try {
// TODO
//updateSources.add(new URI(BACKUP_NEWS_URL_SU3));
updateSources.add(new URI(BACKUP_NEWS_URL));
} catch (URISyntaxException use) {}
UpdateRunner update = new NewsFetcher(_context, _mgr, updateSources);

View File

@@ -59,7 +59,7 @@ public class ConfigClientsHandler extends FormHandler {
}
if (_action.equals(_("Install Plugin"))) {
if (pluginsEnabled &&
(_context.getBooleanProperty(ConfigClientsHelper.PROP_ENABLE_PLUGIN_INSTALL) ||
(_context.getBooleanPropertyDefaultTrue(ConfigClientsHelper.PROP_ENABLE_PLUGIN_INSTALL) ||
isAdvanced()))
installPlugin();
else

View File

@@ -39,7 +39,12 @@ public class ConfigClientsHelper extends HelperBase {
/** @since 0.9.14.1 */
public boolean isPluginInstallEnabled() {
return PluginStarter.pluginsEnabled(_context) &&
(_context.getBooleanProperty(PROP_ENABLE_PLUGIN_INSTALL) || isAdvanced());
(_context.getBooleanPropertyDefaultTrue(PROP_ENABLE_PLUGIN_INSTALL) || isAdvanced());
}
/** @since 0.9.15 */
public boolean isPluginUpdateEnabled() {
return !PluginStarter.getPlugins().isEmpty();
}
/** @since 0.8.3 */

View File

@@ -32,6 +32,7 @@ public class ConfigUpdateHandler extends FormHandler {
// public static final String DEFAULT_NEWS_URL = "http://dev.i2p.net/cgi-bin/cvsweb.cgi/i2p/news.xml?rev=HEAD";
public static final String OLD_DEFAULT_NEWS_URL = "http://complication.i2p/news.xml";
public static final String DEFAULT_NEWS_URL = "http://echelon.i2p/i2p/news.xml";
public static final String DEFAULT_NEWS_URL_SU3 = "http://echelon.i2p/i2p/news.su3";
public static final String PROP_REFRESH_FREQUENCY = "router.newsRefreshFrequency";
public static final long DEFAULT_REFRESH_FREQ = 36*60*60*1000l;
public static final String DEFAULT_REFRESH_FREQUENCY = Long.toString(DEFAULT_REFRESH_FREQ);

View File

@@ -32,6 +32,7 @@ public class ConfigUpdateHelper extends HelperBase {
/** hack to replace the old news location with the new one, even if they have saved
the update page at some point */
public static String getNewsURL(I2PAppContext ctx) {
// TODO SU3
String url = ctx.getProperty(ConfigUpdateHandler.PROP_NEWS_URL);
if (url != null && !url.equals(ConfigUpdateHandler.OLD_DEFAULT_NEWS_URL))
return url;

View File

@@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.List;
import net.i2p.I2PAppContext;
import net.i2p.crypto.SigType;
import net.i2p.util.FileUtil;
import net.i2p.util.VersionComparator;
@@ -29,6 +30,17 @@ public class LogsHelper extends HelperBase {
return Server.getVersion();
}
/** @since 0.9.15 */
public String getUnavailableCrypto() {
StringBuilder buf = new StringBuilder(128);
for (SigType t : SigType.values()) {
if (!t.isAvailable()) {
buf.append("<b>Crypto:</b> ").append(t.toString()).append(" unavailable<br>");
}
}
return buf.toString();
}
/**
* Does not call logManager.flush(); call getCriticalLogs() first to flush
*/

View File

@@ -105,7 +105,10 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<input type="submit" name="action" class="accept" value="<%=intl._("Save WebApp Configuration")%>" />
</div></form></div>
<% if (clientshelper.showPlugins()) { %>
<%
if (clientshelper.showPlugins()) {
if (clientshelper.isPluginUpdateEnabled()) {
%>
<h3><a name="pconfig"></a><%=intl._("Plugin Configuration")%></h3><p>
<%=intl._("The plugins listed below are started by the webConsole client.")%>
</p><div class="wideload">
@@ -116,25 +119,47 @@ input.default { width: 1px; height: 1px; visibility: hidden; }
<input type="submit" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
<input type="submit" name="action" class="accept" value="<%=intl._("Save Plugin Configuration")%>" />
</div></form></div>
<% if (clientshelper.isPluginInstallEnabled()) { %>
<%
} // pluginUpdateEnabled
if (clientshelper.isPluginInstallEnabled()) {
%>
<h3><a name="plugin"></a><%=intl._("Plugin Installation")%></h3><p>
<%=intl._("Look for available plugins on {0}.", "<a href=\"http://plugins.i2p\">plugins.i2p</a>")%>
<%=intl._("To install a plugin, enter the download URL:")%>
</p><div class="wideload">
</p>
<%
} // pluginInstallEnabled
if (clientshelper.isPluginInstallEnabled() || clientshelper.isPluginUpdateEnabled()) {
%>
<div class="wideload">
<form action="configclients" method="POST">
<input type="hidden" name="nonce" value="<%=pageNonce%>" >
<%
if (clientshelper.isPluginInstallEnabled()) {
%>
<p>
<input type="text" size="60" name="pluginURL" >
</p><hr><div class="formaction">
<input type="submit" name="action" class="default" value="<%=intl._("Install Plugin")%>" />
<input type="submit" class="cancel" name="foo" value="<%=intl._("Cancel")%>" />
<input type="submit" name="action" class="download" value="<%=intl._("Install Plugin")%>" />
</div><hr><div class="formaction">
<input type="submit" name="action" class="reload" value="<%=intl._("Update All Installed Plugins")%>" />
</div></form></div>
</div>
<%
} // pluginInstallEnabled
} // showPlugins
} // pluginInstallEnabled
%>
</div>
<%
if (clientshelper.isPluginUpdateEnabled()) {
%>
<hr><div class="formaction">
<input type="submit" name="action" class="reload" value="<%=intl._("Update All Installed Plugins")%>" />
</div>
<%
} // pluginUpdateEnabled
%>
</form></div>
<%
} // pluginInstallEnabled || pluginUpdateEnabled
} // showPlugins
%>
</div></div></body></html>

View File

@@ -60,9 +60,10 @@
<p>
<b>I2P version:</b> <%=net.i2p.router.RouterVersion.FULL_VERSION%><br>
<b>Java version:</b> <%=System.getProperty("java.vendor")%> <%=System.getProperty("java.version")%> (<%=System.getProperty("java.runtime.name")%> <%=System.getProperty("java.runtime.version")%>)<br>
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
<jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" />
<jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute(\"i2p.contextId\")%>" />
<jsp:getProperty name="logsHelper" property="unavailableCrypto" />
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
<b>Server version:</b> <jsp:getProperty name="logsHelper" property="jettyVersion" /><br>
<b>Servlet version:</b> <%=getServletInfo()%><br>
<b>Platform:</b> <%=System.getProperty("os.name")%> <%=System.getProperty("os.arch")%> <%=System.getProperty("os.version")%><br>

View File

@@ -24,16 +24,18 @@
<p>
<b>I2P version:</b> <%=net.i2p.router.RouterVersion.FULL_VERSION%><br>
<b>Java version:</b> <%=System.getProperty("java.vendor")%> <%=System.getProperty("java.version")%> (<%=System.getProperty("java.runtime.name")%> <%=System.getProperty("java.runtime.version")%>)<br>
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
<jsp:useBean class="net.i2p.router.web.LogsHelper" id="logsHelper" scope="request" />
<jsp:setProperty name="logsHelper" property="contextId" value="<%=(String)session.getAttribute(\"i2p.contextId\")%>" />
<jsp:getProperty name="logsHelper" property="unavailableCrypto" />
<b>Wrapper version:</b> <%=System.getProperty("wrapper.version", "none")%><br>
<b>Server version:</b> <jsp:getProperty name="logsHelper" property="jettyVersion" /><br>
<b>Servlet version:</b> <%=getServletInfo()%><br>
<b>Platform:</b> <%=System.getProperty("os.name")%> <%=System.getProperty("os.arch")%> <%=System.getProperty("os.version")%><br>
<b>Processor:</b> <%=net.i2p.util.NativeBigInteger.cpuModel()%> (<%=net.i2p.util.NativeBigInteger.cpuType()%>)<br>
<b>Jbigi:</b> <%=net.i2p.util.NativeBigInteger.loadStatus()%><br>
<b>Encoding:</b> <%=System.getProperty("file.encoding")%><br>
<b>Charset:</b> <%=java.nio.charset.Charset.defaultCharset().name()%></p>
<b>Charset:</b> <%=java.nio.charset.Charset.defaultCharset().name()%><br>
</p>
<p><%=intl._("Note that system information, log timestamps, and log messages may provide clues to your location; please review everything you include in a bug report.")%></p>
<h3><%=intl._("Critical Logs")%></h3><a name="criticallogs"> </a>
<jsp:getProperty name="logsHelper" property="criticalLogs" />

View File

@@ -13,6 +13,7 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Signature;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.util.Log;
/**
@@ -314,10 +315,16 @@ class Packet {
private void setFlags(int flags) { _flags = flags; }
/** the signature on the packet (only included if the flag for it is set)
/**
* The signature on the packet (only included if the flag for it is set)
*
* Warning, may be typed wrong on incoming packets for EdDSA
* before verifySignature() is called.
*
* @return signature on the packet if the flag for signatures is set
*/
public Signature getOptionalSignature() { return _optionSignature; }
public void setOptionalSignature(Signature sig) {
setFlag(FLAG_SIGNATURE_INCLUDED, sig != null);
_optionSignature = sig;
@@ -327,6 +334,7 @@ class Packet {
* @return the sending Destination
*/
public Destination getOptionalFrom() { return _optionFrom; }
public void setOptionalFrom(Destination from) {
setFlag(FLAG_FROM_INCLUDED, from != null);
if (from == null) throw new RuntimeException("from is null!?");
@@ -340,6 +348,7 @@ class Packet {
* @return How long the sender wants the recipient to wait before sending any more data in ms.
*/
public int getOptionalDelay() { return _optionDelay; }
public void setOptionalDelay(int delayMs) {
if (delayMs > MAX_DELAY_REQUEST)
_optionDelay = MAX_DELAY_REQUEST;
@@ -507,20 +516,21 @@ class Packet {
* @throws IllegalStateException
*/
private int writtenSize() {
int size = 0;
size += 4; // _sendStreamId.length;
size += 4; // _receiveStreamId.length;
size += 4; // sequenceNum
size += 4; // ackThrough
//int size = 0;
//size += 4; // _sendStreamId.length;
//size += 4; // _receiveStreamId.length;
//size += 4; // sequenceNum
//size += 4; // ackThrough
// size++; // nacks length
//size++; // resendDelay
//size += 2; // flags
//size += 2; // option size
int size = 22;
if (_nacks != null) {
size++; // nacks length
// if max win is ever > 255, limit to 255
size += 4 * _nacks.length;
} else {
size++; // nacks length
}
size++; // resendDelay
size += 2; // flags
if (isFlagSet(FLAG_DELAY_REQUESTED))
size += 2;
@@ -531,8 +541,6 @@ class Packet {
if (isFlagSet(FLAG_SIGNATURE_INCLUDED))
size += _optionSignature.length();
size += 2; // option size
if (_payload != null) {
size += _payload.getValid();
}
@@ -632,6 +640,9 @@ class Packet {
// super cheat for now, look for correct type,
// assume no more options. If we add to the options
// we will have to ask the manager.
// We will get this wrong for Ed25519, same length as P256...
// See verifySignature() below where we will recast the signature to
// the correct type if necessary
int siglen = payloadBegin - cur;
SigType type = null;
for (SigType t : SigType.values()) {
@@ -677,12 +688,27 @@ class Packet {
if (buffer == null)
buffer = new byte[size];
int written = writePacket(buffer, 0, from.getSigningPublicKey().getType().getSigLen());
SigningPublicKey spk = from.getSigningPublicKey();
SigType type = spk.getType();
if (type == null) {
Log l = ctx.logManager().getLog(Packet.class);
if (l.shouldLog(Log.WARN))
l.warn("Unknown sig type in " + from + " cannot verify " + toString());
return false;
}
int written = writePacket(buffer, 0, type.getSigLen());
if (written != size) {
ctx.logManager().getLog(Packet.class).error("Written " + written + " size " + size + " for " + toString(), new Exception("moo"));
return false;
}
boolean ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, from.getSigningPublicKey());
// Fixup of signature if we guessed wrong on the type in readPacket(), which could happen
// on a close or reset packet where we have a signature without a FROM
if (type != _optionSignature.getType() &&
type.getSigLen() == _optionSignature.length())
_optionSignature = new Signature(type, _optionSignature.getData());
boolean ok = ctx.dsa().verifySignature(_optionSignature, buffer, 0, size, spk);
if (!ok) {
Log l = ctx.logManager().getLog(Packet.class);
if (l.shouldLog(Log.WARN))

View File

@@ -91,3 +91,9 @@ javac.version=1.6
# Optional properties used in tests to enable additional tools.
#with.cobertura=/PATH/TO/cobertura.jar
#with.clover=/PATH/TO/clover.jar
### Bundle router infos ###
# Set to bundle router infos from your local I2P install in the package
#bundle.routerInfos=true
#bundle.routerInfos.count=200
#bundle.routerInfos.i2pConfigDir=/PATH/TO/.i2p

View File

@@ -960,7 +960,7 @@
<copy file="installer/lib/wrapper/all/wrapper.jar" todir="pkg-temp/lib" />
</target>
<target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates">
<target name="preppkg-base" depends="build, preplicenses, prepConsoleDocs, prepthemeupdates, prepCertificates, prepRouterInfos">
<!-- if updater200 was run previously, it left *.pack files in pkg-temp -->
<!-- Also remove deletelist.txt used for updater only -->
<delete>
@@ -1017,6 +1017,9 @@
<fileset dir="installer/resources/icons/flags/" includes="cn.png de.png es.png fr.png ir.png it.png jp.png nl.png ru.png se.png us.png" />
</copy>
<copy file="installer/resources/themes/console/images/favicon.ico" tofile="pkg-temp/eepsite/docroot/favicon.ico" />
<copy todir="pkg-temp/docs/icons/flags" >
<fileset dir="installer/resources/icons/flags" />
</copy>
</target>
<target name="preplicenses">
@@ -1051,6 +1054,26 @@
</copy>
</target>
<condition property="no.bundle.routerInfos">
<isfalse value="${bundle.routerInfos}" />
</condition>
<target name="prepRouterInfos" depends="buildrouter" unless="no.bundle.routerInfos">
<mkdir dir="pkg-temp/netDb" />
<java classname="net.i2p.router.networkdb.kademlia.PersistentDataStore" fork="true" failonerror="true">
<classpath>
<pathelement location="build/i2p.jar" />
<pathelement location="build/router.jar" />
</classpath>
<arg value="-i" />
<arg value="${bundle.routerInfos.i2pConfigDir}" />
<arg value="-o" />
<arg value="pkg-temp/netDb" />
<arg value="-c" />
<arg value="${bundle.routerInfos.count}" />
</java>
</target>
<!-- this is no longer required, izpack 4.3.0 supports headless installs with java -jar i2pinstall.exe -console -->
<!-- and this is no longer used by the SlackBuild -->
<target name="tarball" depends="preppkg">
@@ -1237,11 +1260,6 @@
<copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
<copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
<copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
<!--
<copy todir="pkg-temp/docs/icons/flags" >
<fileset dir="installer/resources/icons/flags" />
</copy>
-->
</target>
<!-- All jetty jars required for update.

View File

@@ -42,6 +42,7 @@ import java.security.interfaces.ECKey;
import java.security.interfaces.RSAKey;
import net.i2p.I2PAppContext;
import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAKey;
import net.i2p.data.Hash;
import net.i2p.data.Signature;
@@ -517,7 +518,7 @@ public class DSAEngine {
java.security.Signature jsig;
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(type.getDigestInstance());
jsig = new EdDSAEngine(type.getDigestInstance());
else
jsig = java.security.Signature.getInstance(type.getAlgorithmName());
PublicKey pubKey = SigUtil.toJavaKey(verifyingKey);
@@ -566,7 +567,7 @@ public class DSAEngine {
String algo = getRawAlgo(type);
java.security.Signature jsig;
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
jsig = new EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
else
jsig = java.security.Signature.getInstance(algo);
jsig.initVerify(pubKey);
@@ -608,7 +609,7 @@ public class DSAEngine {
java.security.Signature jsig;
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(type.getDigestInstance());
jsig = new EdDSAEngine(type.getDigestInstance());
else
jsig = java.security.Signature.getInstance(type.getAlgorithmName());
PrivateKey privKey = SigUtil.toJavaKey(privateKey);
@@ -651,7 +652,7 @@ public class DSAEngine {
java.security.Signature jsig;
if (type.getBaseAlgorithm() == SigAlgo.EdDSA)
jsig = new net.i2p.crypto.eddsa.EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
jsig = new EdDSAEngine(); // Ignore algo, EdDSAKey includes a hash specification.
else
jsig = java.security.Signature.getInstance(algo);
jsig.initSign(privKey, _context.random());

View File

@@ -123,6 +123,7 @@ class ECConstants {
Gy= 07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811
*/
/*
private static final ECParms PARM_P192 = new ECParms(
// P N Seed B Gx Gy
"6277101735386680763835789423207666416083908700390324961279",
@@ -132,6 +133,7 @@ class ECConstants {
"188da80e b03090f6 7cbf20eb 43a18800 f4ff0afd 82ff1012",
"07192b95 ffc8da78 631011ed 6b24cdd5 73f977a1 1e794811"
);
*/
/*
@@ -318,17 +320,17 @@ class ECConstants {
// standard curve names
// first is OpenJDK 6/7
// second is BC
public static final ECParameterSpec P192_SPEC = genSpec("secp192r1", "P-192", PARM_P192);
//public static final ECParameterSpec P192_SPEC = genSpec("secp192r1", "P-192", PARM_P192);
public static final ECParameterSpec P256_SPEC = genSpec("secp256r1", "P-256", PARM_P256);
public static final ECParameterSpec P384_SPEC = genSpec("secp384r1", "P-384", PARM_P384);
public static final ECParameterSpec P521_SPEC = genSpec("secp521r1", "P-521", PARM_P521);
// Koblitz
public static final ECParameterSpec K163_SPEC = genSpec("sect163k1", "K-163", null);
public static final ECParameterSpec K233_SPEC = genSpec("sect233k1", "K-233", null);
public static final ECParameterSpec K283_SPEC = genSpec("sect283k1", "K-283", null);
public static final ECParameterSpec K409_SPEC = genSpec("sect409k1", "K-409", null);
public static final ECParameterSpec K571_SPEC = genSpec("sect571k1", "K-571", null);
//public static final ECParameterSpec K163_SPEC = genSpec("sect163k1", "K-163", null);
//public static final ECParameterSpec K233_SPEC = genSpec("sect233k1", "K-233", null);
//public static final ECParameterSpec K283_SPEC = genSpec("sect283k1", "K-283", null);
//public static final ECParameterSpec K409_SPEC = genSpec("sect409k1", "K-409", null);
//public static final ECParameterSpec K571_SPEC = genSpec("sect571k1", "K-571", null);
}

View File

@@ -67,12 +67,16 @@ public class SU3File {
private static final int VERSION_OFFSET = 40; // Signature.SIGNATURE_BYTES; avoid early ctx init
public static final int TYPE_ZIP = 0;
/** @since 0.9.15 */
public static final int TYPE_XML = 1;
/** @since 0.9.15 */
public static final int TYPE_HTML = 2;
public static final int CONTENT_UNKNOWN = 0;
public static final int CONTENT_ROUTER = 1;
public static final int CONTENT_PLUGIN = 2;
public static final int CONTENT_RESEED = 3;
/** @since 0.9.15 */
public static final int CONTENT_NEWS = 4;
private enum ContentType {

View File

@@ -95,6 +95,7 @@ public enum SigType {
private final SigAlgo base;
private final String digestName, algoName, since;
private final AlgorithmParameterSpec params;
private final boolean isAvail;
SigType(int cod, int pubLen, int privLen, int hLen, int sLen, SigAlgo baseAlgo,
String mdName, String aName, AlgorithmParameterSpec pSpec, String supportedSince) {
@@ -108,6 +109,7 @@ public enum SigType {
algoName = aName;
params = pSpec;
since = supportedSince;
isAvail = x_isAvailable();
}
/** the unique identifier for this type */
@@ -180,6 +182,10 @@ public enum SigType {
* @return true if supported in this JVM
*/
public boolean isAvailable() {
return isAvail;
}
private boolean x_isAvailable() {
if (DSA_SHA1 == this)
return true;
try {

View File

@@ -16,6 +16,7 @@ import net.i2p.crypto.eddsa.math.GroupElement;
import net.i2p.crypto.eddsa.math.ScalarOps;
/**
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -4,6 +4,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
/**
* Common interface for all EdDSA keys.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -8,6 +8,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
/**
* An EdDSA private key.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -8,6 +8,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
/**
* An EdDSA public key.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -12,6 +12,7 @@ import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
/**
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -17,6 +17,8 @@ import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
/**
* Default strength is 256
*
* @since 0.9.15
*/
public class KeyPairGenerator extends KeyPairGeneratorSpi {
private static final int DEFAULT_STRENGTH = 256;

View File

@@ -1,6 +1,10 @@
package net.i2p.crypto.eddsa;
/**
* Basic utilities for eddsa.
* Not for external use, not maintained as a public API.
*
* @since 0.9.15
* @author str4d
*
*/
@@ -18,6 +22,18 @@ public class Utils {
return (result ^ 0x01) & 0x01;
}
/**
* Constant-time byte[] comparison.
* @return 1 if b and c are equal, 0 otherwise.
*/
public static int equal(byte[] b, byte[] c) {
int result = 0;
for (int i = 0; i < 32; i++) {
result |= b[i] ^ c[i];
}
return ~equal(result, 0) & 0x01;
}
/**
* Constant-time determine if byte is negative.
* @param b the byte to check.
@@ -34,7 +50,7 @@ public class Utils {
* @return 0 or 1, the value of the i'th bit in h
*/
public static int bit(byte[] h, int i) {
return (h[i/8] >> (i%8)) & 1;
return (h[i >> 3] >> (i & 7)) & 1;
}
/**
@@ -51,4 +67,22 @@ public class Utils {
}
return data;
}
/**
* Converts bytes to a hex string.
* @param raw the byte[] to be converted.
* @return the hex representation as a string.
*/
public static String bytesToHex(byte[] raw) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder(2 * raw.length);
for (final byte b : raw) {
hex.append(Character.forDigit((b & 0xF0) >> 4, 16))
.append(Character.forDigit((b & 0x0F), 16));
}
return hex.toString();
}
}

View File

@@ -5,6 +5,8 @@ import java.io.Serializable;
/**
* A twisted Edwards curve.
* Points on the curve satisfy -x^2 + y^2 = 1 + d x^2y^2
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -3,6 +3,8 @@ package net.i2p.crypto.eddsa.math;
/**
* Common interface for all (b-1)-bit encodings of elements
* of EdDSA finite fields.
*
* @since 0.9.15
* @author str4d
*
*/
@@ -22,7 +24,7 @@ public abstract class Encoding {
/**
* Decode a FieldElement from its (b-1)-bit encoding.
* The highest bit is masked out.
* @param val the (b-1)-bit encoding of a FieldElement.
* @param in the (b-1)-bit encoding of a FieldElement.
* @return the FieldElement represented by 'val'.
*/
public abstract FieldElement decode(byte[] in);
@@ -33,7 +35,7 @@ public abstract class Encoding {
* than the (b-1)-bit encoding of -x. If q is an odd prime and the encoding
* is the little-endian representation of {0, 1,..., q-1} then the negative
* elements of F_q are {1, 3, 5,..., q-2}.
* @return
* @return true if negative
*/
public abstract boolean isNegative(FieldElement x);
}

View File

@@ -4,6 +4,8 @@ import java.io.Serializable;
/**
* An EdDSA finite field. Includes several pre-computed values.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -1,5 +1,10 @@
package net.i2p.crypto.eddsa.math;
/**
*
* @since 0.9.15
*
*/
public abstract class FieldElement {
protected final Field f;

View File

@@ -6,6 +6,8 @@ import net.i2p.crypto.eddsa.Utils;
/**
* A point (x,y) on an EdDSA curve.
*
* @since 0.9.15
* @author str4d
*
*/
@@ -489,7 +491,7 @@ public class GroupElement implements Serializable {
*
* @param pos = i/2 for i in {0, 2, 4,..., 62}
* @param b = r_i
* @return
* @return the GroupElement
*/
GroupElement select(int pos, int b) {
// Is r_i negative?
@@ -522,7 +524,7 @@ public class GroupElement implements Serializable {
* Preconditions: (TODO: Check this applies here)
* a[31] <= 127
* @param a = a[0]+256*a[1]+...+256^31 a[31]
* @return
* @return the GroupElement
*/
public GroupElement scalarMultiply(byte[] a) {
GroupElement t;
@@ -603,7 +605,7 @@ public class GroupElement implements Serializable {
* @param A in P3 representation.
* @param a = a[0]+256*a[1]+...+256^31 a[31]
* @param b = b[0]+256*b[1]+...+256^31 b[31]
* @return
* @return the GroupElement
*/
public GroupElement doubleScalarMultiplyVariableTime(GroupElement A, byte[] a, byte[] b) {
byte[] aslide = slide(a);
@@ -645,7 +647,6 @@ public class GroupElement implements Serializable {
/**
* Verify that a point is on its curve.
* @param P The point to check.
* @return true if the point lies on its curve.
*/
public boolean isOnCurve() {

View File

@@ -1,5 +1,10 @@
package net.i2p.crypto.eddsa.math;
/**
*
* @since 0.9.15
*
*/
public interface ScalarOps {
/**
* Reduce the given scalar mod l.

View File

@@ -65,7 +65,7 @@ public class BigIntegerLittleEndianEncoding extends Encoding implements Serializ
* than the (b-1)-bit encoding of -x. If q is an odd prime and the encoding
* is the little-endian representation of {0, 1,..., q-1} then the negative
* elements of F_q are {1, 3, 5,..., q-2}.
* @return
* @return true if negative
*/
public boolean isNegative(FieldElement x) {
return ((BigIntegerFieldElement)x).bi.testBit(0);

View File

@@ -0,0 +1,6 @@
<html><body>
<p>
Low-level, non-optimized implementation using BigIntegers for any curve.
Unused. See the <a href="../ed25519/package-summary.html">ed25519</a> implementation for Curve 25519.
</p>
</body></html>

View File

@@ -1,8 +1,8 @@
package net.i2p.crypto.eddsa.math.ed25519;
import net.i2p.crypto.eddsa.Utils;
import net.i2p.crypto.eddsa.math.Field;
import net.i2p.crypto.eddsa.math.FieldElement;
import net.i2p.data.DataHelper;
/**
* An element t, entries t[0]...t[9], represents the integer
@@ -26,11 +26,7 @@ public class Ed25519FieldElement extends FieldElement {
public boolean isNonZero() {
byte[] s = toByteArray();
int result = 0;
for (int i = 0; i < 32; i++) {
result |= s[i] ^ zero[i];
}
return result != 0;
return Utils.equal(s, zero) == 1;
}
/**
@@ -959,13 +955,11 @@ public class Ed25519FieldElement extends FieldElement {
if (!(obj instanceof Ed25519FieldElement))
return false;
Ed25519FieldElement fe = (Ed25519FieldElement) obj;
// XXX why does direct byte[] comparison fail?
// TODO should this be constant time?
return DataHelper.toString(toByteArray()).equals(DataHelper.toString(fe.toByteArray()));
return 1==Utils.equal(toByteArray(), fe.toByteArray());
}
@Override
public String toString() {
return "[Ed25519FieldElement val="+DataHelper.toString(toByteArray())+"]";
return "[Ed25519FieldElement val="+Utils.bytesToHex(toByteArray())+"]";
}
}

View File

@@ -0,0 +1,6 @@
<html><body>
<p>
Low-level, optimized implementation using Radix 2^51 for Curve 25519.
See the <a href="../bigint/package-summary.html">bigint</a> implementation for other curves.
</p>
</body></html>

View File

@@ -0,0 +1,9 @@
<html><body>
<p>
Data structures that definie curves and fields, and
the mathematical operaions on them.
</p><p>
Low-level implementation is in <a href="bigint/package-summary.html">bigint</a> for any curve using BigIntegers,
and in <a href="ed25519/package-summary.html">ed25519</a> for Curve 25519 using Radix 2^51.
</p>
</body></html>

View File

@@ -0,0 +1,11 @@
<html><body>
<p>
Java implementation of EdDSA, a digital signature scheme using
a variant of elliptic curve cryptography based on Twisted Edwards curves.
</p><p>
Contains a generic implementation for any curve using BigIntegers,
and an optimized implementation for Curve 25519 using Radix 2^51.
</p><p>
Since 0.9.15.
</p>
</body></html>

View File

@@ -5,6 +5,8 @@ import java.security.spec.AlgorithmParameterSpec;
/**
* Implementation of AlgorithmParameterSpec that holds the name of a named
* EdDSA curve specification.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -6,6 +6,8 @@ import net.i2p.crypto.eddsa.math.ScalarOps;
/**
* EdDSA Curve specification that can also be referred to by name.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -10,6 +10,8 @@ import net.i2p.crypto.eddsa.math.ed25519.Ed25519ScalarOps;
/**
* The named EdDSA curves.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -12,6 +12,8 @@ import java.io.Serializable;
/**
* Parameter specification for an EdDSA algorithm.
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -8,6 +8,8 @@ import java.util.Arrays;
import net.i2p.crypto.eddsa.math.GroupElement;
/**
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -5,6 +5,8 @@ import java.security.spec.KeySpec;
import net.i2p.crypto.eddsa.math.GroupElement;
/**
*
* @since 0.9.15
* @author str4d
*
*/

View File

@@ -0,0 +1,6 @@
<html><body>
<p>
Specifications for curves and keys, and a table for named curves,
initially containing only the 25519 curve "ed25519-sha-512".
</p>
</body></html>

View File

@@ -0,0 +1,11 @@
<html><body>
<p>
I2P implementation of java.security.Provider for EdDSA.
</p><p>
This should only be required when
using runtime registration of the provider with the
<code>Security.addProvider()</code> mechanism.
</p><p>
Since 0.9.15. Other I2P algorithms may be added later.
</p>
</body></html>

View File

@@ -104,7 +104,8 @@ public class Destination extends KeysAndCert {
}
/**
* deprecated, used only by Packet.java in streaming
* Deprecated, used only by Packet.java in streaming.
* Broken for sig types P521 and RSA before 0.9.15
* @return the written length (NOT the new offset)
*/
public int writeBytes(byte target[], int offset) {
@@ -115,8 +116,9 @@ public class Destination extends KeysAndCert {
System.arraycopy(_padding, 0, target, cur, _padding.length);
cur += _padding.length;
}
System.arraycopy(_signingKey.getData(), 0, target, cur, _signingKey.length());
cur += _signingKey.length();
int spkTrunc = Math.min(SigningPublicKey.KEYSIZE_BYTES, _signingKey.length());
System.arraycopy(_signingKey.getData(), 0, target, cur, spkTrunc);
cur += spkTrunc;
cur += _certificate.writeBytes(target, cur);
return cur - offset;
}

View File

@@ -81,7 +81,9 @@ public abstract class SimpleDataStructure extends DataStructureImpl {
int length = length();
_data = new byte[length];
int read = read(in, _data);
if (read != length) throw new DataFormatException("Not enough bytes to read the data");
if (read != length)
throw new DataFormatException("EOF reading " + getClass().getSimpleName() +
", read: " + read + ", required: " + length);
}
public void writeBytes(OutputStream out) throws DataFormatException, IOException {

View File

@@ -23,5 +23,7 @@ public enum UpdateType {
/** unused */
ADDRESSBOOK,
/** @since 0.9.9 */
ROUTER_SIGNED_SU3
ROUTER_SIGNED_SU3,
/** @since 0.9.15 */
NEWS_SU3
}

View File

@@ -475,7 +475,7 @@ public class NativeBigInteger extends BigInteger {
}
if (!_nativeOk) {
warn("Native BigInteger library jbigi not loaded - using pure Java - " +
"poor performance may result - see http://www.i2p2.i2p/jbigi for help");
"poor performance may result - see http://i2p-projekt.i2p/jbigi for help");
}
} catch(Exception e) {
warn("Native BigInteger library jbigi not loaded, using pure java", e);

View File

@@ -26,6 +26,7 @@ public abstract class SystemVersion {
private static final boolean _oneDotSix;
private static final boolean _oneDotSeven;
private static final boolean _oneDotEight;
private static final int _androidSDK;
static {
@@ -60,9 +61,11 @@ public abstract class SystemVersion {
if (_isAndroid) {
_oneDotSix = _androidSDK >= 9;
_oneDotSeven = _androidSDK >= 19;
_oneDotEight = false;
} else {
_oneDotSix = VersionComparator.comp(System.getProperty("java.version"), "1.6") >= 0;
_oneDotSeven = VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
_oneDotSeven = _oneDotSix && VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
_oneDotEight = _oneDotSeven && VersionComparator.comp(System.getProperty("java.version"), "1.8") >= 0;
}
}
@@ -127,6 +130,15 @@ public abstract class SystemVersion {
return _oneDotSeven;
}
/**
*
* @return true if Java 1.8 or higher, false for Android.
* @since 0.9.15
*/
public static boolean isJava8() {
return _oneDotEight;
}
/**
* This isn't always correct.
* http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit

View File

@@ -1,3 +1,36 @@
2014-09-09 zzz
* i2psnark: Escape fixes
2014-08-31 zzz
* Build: Add support for bundling router infos in the package
* I2PTunnel: Allow changing of spoof host and target host/port without
restarting server tunnel
2014-08-30 zzz
* Console:
- Re-enable plugin installation by default
- Don't show configuration section or update-all button if no plugins installed
- Show unavailable crypto on /logs
* Router: Log warnings for unavailable crypto at startup
* RouterInfo: Backport fix for verification of EdDSA RI sig type
2014-08-28 zzz
* Streaming: Fix verify of Ed25519 signatures in CLOSE packets
2014-08-27 zzz
* i2psnark:
- Persist uploaded count (tickets #1034, #1298)
- Don't retry announce if we get back HTML
- Recognize Vuze tracker rejections
- Don't retry rejected announces unless seeding
- Better UI handling of announces with ports or full destination
* NetDB: Don't abort initialization on an unsupported RI sig type
* Streaming: Fix P521 and RSA sig types
2014-08-23 zzz
* Console, i2psnark, i2ptunnel: Escape fixes and cleanups
* SSU: Drop peer tests as Bob from unestablished Alices
2014-08-22 zzz
* SigTypes:
- Add isSupportedSince(), use in floodfill selection

View File

@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFhTCCA22gAwIBAgIERiD+VDANBgkqhkiG9w0BAQ0FADBzMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEcMBoGA1UEAwwTenp6LXBsdWdpbkBt
YWlsLmkycDAeFw0xNDA4MDcyMTA0NDlaFw0yNDA4MDYyMTA0NDlaMHMxCzAJBgNV
BAYTAlhYMQswCQYDVQQIEwJYWDELMAkGA1UEBxMCWFgxHjAcBgNVBAoTFUkyUCBB
bm9ueW1vdXMgTmV0d29yazEMMAoGA1UECxMDSTJQMRwwGgYDVQQDDBN6enotcGx1
Z2luQG1haWwuaTJwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAzWRY
ZFGmPO3lOfD9vu5LFxmZchqEiT+QYyTU1FllIlppgb3dkAo7Tn8R1QcwyKkoJkYI
oFdUCYwUOhUmbKv5j6oBTmLlav/MQi2nM7dHfBVP3ubzZP7Z/zKGQUf1Ze7136Yh
l6Lfbl/wN3O7IIGs6NksSiq/hnDrAmZAQwfc7/dahPh4gxPRuK9Bg7NFPJyQ07vJ
FQC1I2uWb49WL/rzJnR20fSeJa/LJ5JnKnWG6RjbTKHp6wN2S0d389BkJvUCEmeT
o5JdV1xcrB4GY/z0gfmS8haZYeW3ySPKuaEOpZGrwLFaKnZGITegMrnVTTZD8RAk
SqvJC8+X8pdFN41I9tkwAK/FTtrNxVubPLfvzgQ2Z8WFtLPFWkbEYn58AnKWj59X
Zs1delvTF1vJHYSY6ZMmymnOBWmRSofXpByBzBCXVKMWZ8ah7BJKLkzGd2/XYeY/
mIRm+SghTjojUg2F3G26W/z67HoSWMunwor0ur2A/r8HMKWqhSzNdEOx9zzX7ihf
W3tUbI/E7BDWLs0sd6gmGMSYbxkrB2pM21X9UmpthDazo6CTC+nrNYRjSpDisOiV
gnu1fPmbfoa61pRoWAQOHVN+D5mDKeJW+WConOxRKuLY/aymeXwSKBcLLkYHasc/
ooJwSofj/SYooGR9aVJO2oEKYbpLu4fFduHIrrMCAwEAAaMhMB8wHQYDVR0OBBYE
FADW2hreviSWGPa+xSDnNpUO+ih2MA0GCSqGSIb3DQEBDQUAA4ICAQBePI57drix
BLUXhB4rAeyCUaA3hp40gzz5oQKijQF8Z+aP3j74NuCUMuPF0f62mPdq4Yrm/QM4
bdKTHtoOuvQyEtnsfRj241CppdzTeVtCMRcBmDUeejE0BjRYtmHOpV7Ylyf3olX+
IddPrkKshN+zy0TiNhwWrKG44C2JkmSqFQRicCm34+0dxINBUqv/+srmriBFesdg
74Z9EPpXRA1xpB0ud4GTq5NQDPby9mm6tXMrziomLtuG66emW7dtisQcmn59Te6E
8OSZrbRzTOshsyqsbyMXnEfLUMRu94WHQ+yJTQSXwAKeXZGfSuTMiiyGJ3bSEDwy
dCA7RW9QF58a6wVlW5s8xLZ+JxVx8QkyCkCsu7mFB6XJh3t8YZTMUC1EwH0Zy8y0
JQeAw9A+I/XILoRhtOISM0vPrw9/TrKkKg8FGPAIE+fSTt6y7X5BWBqIE38u0wi7
MyQZjmAhVz9nBkX6iggY9js/7Ix4LkCk6ERQoQxA0RWXcPX9LzBmisxL3nb86eYo
o9f2fFtK9ErU7ZiYkb32U8/Jd205rrqWOxBhvQAcOqPsxVH5USi1I2gs912NVkXB
dbb9dlEDIwiP+6E0EtEW/PodF8hzptbg8fjhu2G7l3f/ZLgBOvnyTJFHrgpRX7ce
rK4SWkfGugRmgkD8S2Us0V1llpclJ6Baiw==
-----END CERTIFICATE-----

View File

@@ -1,4 +1,4 @@
-----BEGIN CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFVjCCAz6gAwIBAgIEU71jgDANBgkqhkiG9w0BAQ0FADBtMQswCQYDVQQGEwJY
WDELMAkGA1UECBMCWFgxCzAJBgNVBAcTAlhYMR4wHAYDVQQKExVJMlAgQW5vbnlt
b3VzIE5ldHdvcmsxDDAKBgNVBAsTA0kyUDEWMBQGA1UEAwwNc3dhdEBtYWlsLmky

View File

@@ -1,23 +1,23 @@
-----BEGIN CERTIFICATE-----
MIIDvjCCAyegAwIBAgICZhcwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCVVMx
DTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5vbmUxDTAL
BgNVBAsMBG5vbmUxFTATBgNVBAMMDGkycC5tb29vLmNvbTETMBEGCSqGSIb3DQEJ
ARYEbm9uZTAeFw0xMTEwMjMyMTM2NDFaFw0xOTEwMjMyMTM2NDFaMGYxCzAJBgNV
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQKDARub25lMQ0wCwYDVQQLDARu
b25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkqhkiG9w0BCQEWBG5vbmUw
ggGPMA0GCSqGSIb3DQEBAQUAA4IBfAAwggF3AoIBbgMG1O7HRVa7UoiKbQTmKy5m
x79Na8vjD3etcOwfc4TSenQFvn+GbAWkJwKpM8uvOcgj1CxNeHWdSaeTFH1OwJsw
vl3leJ7clMdo3hpQDhPeGzBLyOiWwFHVn15YKa9xcM7S9Op5Q6rKBHUyyx1vGSz+
/NBmkktpI6rcGFfP3ISRL0auR+db+adWv4TS6W8YiwQIVZNbSlKP6FNO9Mv1kxQZ
KoHPn8vT/LtAh1fcI6ryBuy3F5oHfbGumIwsS5dpowryFxQzwg5vtMA7AMCMKyXv
hP/W6OuaaEP5MCIxkWjQs35gOYa8eF1dLoy3AD9yVVhoNrA8Bc5FnVFJ32Qv7agy
qRY85cXBA6hT/Qzs/wWwp7WrrnZuifaSv/u/Ayi5vX42/bf86PSM2IRNIESoA98A
NFz4U2KGq9s1K2JbkQmnFy8IU0w7CMq6PvNEm/uNjSk6OE1rcCXML+EuX0zmXy8d
PjRbLzC9csSg2CqMtQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUdjuOczdG
hUpYzH0UXqKrOleT8GkwHwYDVR0jBBgwFoAU+SKWC49cM5sCodv89AFin3pkS0Yw
DQYJKoZIhvcNAQEFBQADgYEAKYyWlDIStjjbn/ZzVScKR174I8whTbdqrX/vp9dr
2hMv5m4F+aswX4Jr58WneKg2LvRaL6xEhoL7OAQ6aB/7xVSpDjIrrBLZd513NAam
X6bOPYJ6IH7Vw9ClFY3AlfzsNlgRMXno7rySKKzhg24kusNwKDH2yCphZy4BgjMn
y6A=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDvjCCAyegAwIBAgICZhcwDQYJKoZIhvcNAQEFBQAwdTELMAkGA1UEBhMCVVMx
DTALBgNVBAgMBG5vbmUxDTALBgNVBAcMBG5vbmUxDTALBgNVBAoMBG5vbmUxDTAL
BgNVBAsMBG5vbmUxFTATBgNVBAMMDGkycC5tb29vLmNvbTETMBEGCSqGSIb3DQEJ
ARYEbm9uZTAeFw0xMTEwMjMyMTM2NDFaFw0xOTEwMjMyMTM2NDFaMGYxCzAJBgNV
BAYTAlVTMQ0wCwYDVQQIDARub25lMQ0wCwYDVQQKDARub25lMQ0wCwYDVQQLDARu
b25lMRUwEwYDVQQDDAxpMnAubW9vby5jb20xEzARBgkqhkiG9w0BCQEWBG5vbmUw
ggGPMA0GCSqGSIb3DQEBAQUAA4IBfAAwggF3AoIBbgMG1O7HRVa7UoiKbQTmKy5m
x79Na8vjD3etcOwfc4TSenQFvn+GbAWkJwKpM8uvOcgj1CxNeHWdSaeTFH1OwJsw
vl3leJ7clMdo3hpQDhPeGzBLyOiWwFHVn15YKa9xcM7S9Op5Q6rKBHUyyx1vGSz+
/NBmkktpI6rcGFfP3ISRL0auR+db+adWv4TS6W8YiwQIVZNbSlKP6FNO9Mv1kxQZ
KoHPn8vT/LtAh1fcI6ryBuy3F5oHfbGumIwsS5dpowryFxQzwg5vtMA7AMCMKyXv
hP/W6OuaaEP5MCIxkWjQs35gOYa8eF1dLoy3AD9yVVhoNrA8Bc5FnVFJ32Qv7agy
qRY85cXBA6hT/Qzs/wWwp7WrrnZuifaSv/u/Ayi5vX42/bf86PSM2IRNIESoA98A
NFz4U2KGq9s1K2JbkQmnFy8IU0w7CMq6PvNEm/uNjSk6OE1rcCXML+EuX0zmXy8d
PjRbLzC9csSg2CqMtQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUdjuOczdG
hUpYzH0UXqKrOleT8GkwHwYDVR0jBBgwFoAU+SKWC49cM5sCodv89AFin3pkS0Yw
DQYJKoZIhvcNAQEFBQADgYEAKYyWlDIStjjbn/ZzVScKR174I8whTbdqrX/vp9dr
2hMv5m4F+aswX4Jr58WneKg2LvRaL6xEhoL7OAQ6aB/7xVSpDjIrrBLZd513NAam
X6bOPYJ6IH7Vw9ClFY3AlfzsNlgRMXno7rySKKzhg24kusNwKDH2yCphZy4BgjMn
y6A=
-----END CERTIFICATE-----

View File

@@ -1,20 +1,20 @@
-----BEGIN CERTIFICATE-----
MIIDRDCCAiwCCQDCm/Zrmali9zANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJB
VTETMBEGA1UECBMKU29tZS1TdGF0ZTELMAkGA1UEBxMCSEgxDDAKBgNVBAoTA0ky
UDEPMA0GA1UECxMGcmVzZWVkMRQwEgYDVQQDEwtyZXNlZWQuaW5mbzAeFw0xMjEw
MjcxODU3NDNaFw0xNjEyMDUxODU3NDNaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI
EwpTb21lLVN0YXRlMQswCQYDVQQHEwJISDEMMAoGA1UEChMDSTJQMQ8wDQYDVQQL
EwZyZXNlZWQxFDASBgNVBAMTC3Jlc2VlZC5pbmZvMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAt9nz0iUvjdX4Hkhfk0FbBOeEP4i/FG3V4VrEdQfcviSF
XgzGYeRtGsvrFWP/5+6bcGnOkIy/jrKJfij3AjKJh8gTzqiNNNnV8VcHwFSNp+hZ
D4BM+UHPACV1Pjd3HQe6f0+LvcTs3HQgIkNkwUyqRuXOm/5Mk6SWSu1740aSwHCj
Kk0x1FByzI0YBvXCPX6TVk6sJqKkQyLzK0CSGSeqUq8GvGCq+jT9k62Su7ooxCwi
GzxaFjMdVYxuI8cuT5Cni+SUw1Ia8vhESnIy6slwzk37xNI80VuMvRT6rD2KcXDH
mK7ml1qL0rJWoF5AE+x/nen4V41mouv1W9rk3wTlTQIDAQABMA0GCSqGSIb3DQEB
BQUAA4IBAQAr6RBviBDW4bnPDTcdtstTDdaYX9yzoh+zzeGB0dUR26GKoOjpSItb
B9nrsW1eJ2wbblfGBUoXhcmNByKHXXHejMhmurHjdei2BuLbTsknN8DPKXu5UF9z
cg4cKQkxgzXOcNYlaF4+sfwFXDHJ4we/8vduVgkyo8R66543/Sh/nIMvq2slRT4w
wIBOVcMb2XxlbdwHW9XALAz9sto+4GH9GAC24f8ngluOpHijMnOOIo4dHibQ5hM9
KcDpHezP0ugMTAxS2NmtVahwAqa2IjpqR7aEQ2wLvxQzDqrXo93L93+b2FKRUQXH
Duud/n/w0kVV3DaIGikOsJayoanR+9HD
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDRDCCAiwCCQDCm/Zrmali9zANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJB
VTETMBEGA1UECBMKU29tZS1TdGF0ZTELMAkGA1UEBxMCSEgxDDAKBgNVBAoTA0ky
UDEPMA0GA1UECxMGcmVzZWVkMRQwEgYDVQQDEwtyZXNlZWQuaW5mbzAeFw0xMjEw
MjcxODU3NDNaFw0xNjEyMDUxODU3NDNaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI
EwpTb21lLVN0YXRlMQswCQYDVQQHEwJISDEMMAoGA1UEChMDSTJQMQ8wDQYDVQQL
EwZyZXNlZWQxFDASBgNVBAMTC3Jlc2VlZC5pbmZvMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAt9nz0iUvjdX4Hkhfk0FbBOeEP4i/FG3V4VrEdQfcviSF
XgzGYeRtGsvrFWP/5+6bcGnOkIy/jrKJfij3AjKJh8gTzqiNNNnV8VcHwFSNp+hZ
D4BM+UHPACV1Pjd3HQe6f0+LvcTs3HQgIkNkwUyqRuXOm/5Mk6SWSu1740aSwHCj
Kk0x1FByzI0YBvXCPX6TVk6sJqKkQyLzK0CSGSeqUq8GvGCq+jT9k62Su7ooxCwi
GzxaFjMdVYxuI8cuT5Cni+SUw1Ia8vhESnIy6slwzk37xNI80VuMvRT6rD2KcXDH
mK7ml1qL0rJWoF5AE+x/nen4V41mouv1W9rk3wTlTQIDAQABMA0GCSqGSIb3DQEB
BQUAA4IBAQAr6RBviBDW4bnPDTcdtstTDdaYX9yzoh+zzeGB0dUR26GKoOjpSItb
B9nrsW1eJ2wbblfGBUoXhcmNByKHXXHejMhmurHjdei2BuLbTsknN8DPKXu5UF9z
cg4cKQkxgzXOcNYlaF4+sfwFXDHJ4we/8vduVgkyo8R66543/Sh/nIMvq2slRT4w
wIBOVcMb2XxlbdwHW9XALAz9sto+4GH9GAC24f8ngluOpHijMnOOIo4dHibQ5hM9
KcDpHezP0ugMTAxS2NmtVahwAqa2IjpqR7aEQ2wLvxQzDqrXo93L93+b2FKRUQXH
Duud/n/w0kVV3DaIGikOsJayoanR+9HD
-----END CERTIFICATE-----

View File

@@ -10,7 +10,7 @@
<h1>I2P Anonymous Webserver</h1>
<div class="langbar">
<!-- Some of these languages listed here are yet to be translated -->
<a href="index.html"><img src="lib/us.png" title="English" alt="English"></a
<a href="index.html"><img src="lib/us.png" title="English" alt="English"></a>
<a href="index_zh.html"><img src="lib/cn.png" title="中文" alt="中文"></a>
<a href="index_de.html"><img src="lib/de.png" title="Deutsch" alt="Deutsch"></a>
<a href="index_es.html"><img src="lib/es.png" title="Español" alt="Español"></a>

View File

@@ -314,6 +314,7 @@ public class Router implements RouterClock.ClockShiftListener {
if (f.exists())
SecureFileOutputStream.setPerms(f);
}
CryptoChecker.warnUnavailableCrypto(_context);
_routerInfo = null;
_higherVersionSeen = false;

View File

@@ -18,10 +18,10 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 9;
public final static long BUILD = 16;
/** for example "-test" */
public final static String EXTRA = "";
public final static String EXTRA = "-rc";
public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
public static void main(String args[]) {
System.out.println("I2P Router version: " + FULL_VERSION);

View File

@@ -0,0 +1,249 @@
package net.i2p.router.networkdb.kademlia;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import gnu.getopt.Getopt;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
import net.i2p.data.RouterAddress;
import net.i2p.data.RouterInfo;
import net.i2p.router.transport.BadCountries;
import net.i2p.router.transport.GeoIP;
import net.i2p.util.FileUtil;
/**
* Copy a random selection of 'count' router infos from configDir/netDb
* to 'toDir'. Skip your own router info, and old, hidden, unreachable, and
* introduced routers, and those from bad countries.
*
* Used in the build process.
*
* @since 0.9.15
*
*/
public class BundleRouterInfos {
/**
* Usage: PersistentDataStore -i configDir -o toDir -c count
*
* Copy a random selection of 'count' router infos from configDir/netDb
* to 'toDir'. Skip your own router info, and old, hidden, unreachable, and
* introduced routers, and those from bad countries.
*
* @since 0.9.15
*/
public static void main(String[] args) {
Getopt g = new Getopt("PersistentDataStore", args, "i:o:c:");
String in = System.getProperty("user.home") + "/.i2p";
String out = "netDb";
int count = 200;
boolean error = false;
int c;
while ((c = g.getopt()) != -1) {
switch (c) {
case 'i':
in = g.getOptarg();
break;
case 'o':
out = g.getOptarg();
break;
case 'c':
String scount = g.getOptarg();
try {
count = Integer.parseInt(scount);
} catch (NumberFormatException nfe) {
error = true;
}
break;
case '?':
case ':':
default:
error = true;
}
}
if (error) {
usage();
System.exit(1);
}
Properties props = new Properties();
props.setProperty(GeoIP.PROP_GEOIP_DIR, System.getProperty("user.dir") + "/installer/resources");
GeoIP geoIP = new GeoIP(new I2PAppContext(props));
File confDir = new File(in);
File dbDir = new File(confDir, "netDb");
if (!dbDir.exists()) {
System.out.println("NetDB directory " + dbDir + " does not exist");
System.exit(1);
}
File myFile = new File(confDir, "router.info");
File toDir = new File(out);
toDir.mkdirs();
InputStream fis = null;
Hash me = null;
try {
fis = new BufferedInputStream(new FileInputStream(myFile));
RouterInfo ri = new RouterInfo();
ri.readBytes(fis, true); // true = verify sig on read
me = ri.getIdentity().getHash();
} catch (Exception e) {
//System.out.println("Can't determine our identity");
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
}
int routerCount = 0;
List<File> toRead = new ArrayList<File>(2048);
for (int j = 0; j < PersistentDataStore.B64.length(); j++) {
File subdir = new File(dbDir, PersistentDataStore.DIR_PREFIX + PersistentDataStore.B64.charAt(j));
File[] files = subdir.listFiles(PersistentDataStore.RouterInfoFilter.getInstance());
if (files == null)
continue;
routerCount += files.length;
for (int i = 0; i < files.length; i++) {
toRead.add(files[i]);
}
}
if (toRead.isEmpty()) {
System.out.println("No files to copy in " + dbDir);
System.exit(1);
}
Collections.shuffle(toRead);
int copied = 0;
long tooOld = System.currentTimeMillis() - 7*24*60*60*1000L;
Map<String, String> ipMap = new HashMap<String, String>(count);
for (File file : toRead) {
if (copied >= count)
break;
Hash key = PersistentDataStore.getRouterInfoHash(file.getName());
if (key == null) {
System.out.println("Skipping bad " + file);
continue;
}
if (key.equals(me)) {
System.out.println("Skipping my RI");
continue;
}
fis = null;
try {
fis = new BufferedInputStream(new FileInputStream(file));
RouterInfo ri = new RouterInfo();
ri.readBytes(fis, true); // true = verify sig on read
try { fis.close(); } catch (IOException ioe) {}
fis = null;
if (ri.getPublished() < tooOld) {
System.out.println("Skipping too old " + key);
continue;
}
if (ri.getCapabilities().contains("U")) {
System.out.println("Skipping unreachable " + key);
continue;
}
if (ri.getCapabilities().contains("K")) {
System.out.println("Skipping slow " + key);
continue;
}
Collection<RouterAddress> addrs = ri.getAddresses();
if (addrs.isEmpty()) {
System.out.println("Skipping hidden " + key);
continue;
}
boolean hasIntro = false;
boolean hasIPv4 = false;
boolean dupIP = false;
for (RouterAddress addr : addrs) {
if ("SSU".equals(addr.getTransportStyle()) && addr.getOption("ihost0") != null) {
hasIntro = true;
break;
}
String host = addr.getHost();
if (host != null && host.contains(".")) {
hasIPv4 = true;
geoIP.add(host);
String old = ipMap.put(host, file.getName());
if (old != null && !old.equals(file.getName())) {
dupIP = true;
break;
}
}
}
if (dupIP) {
System.out.println("Skipping dup IP " + key);
continue;
}
if (hasIntro) {
System.out.println("Skipping introduced " + key);
continue;
}
if (!hasIPv4) {
System.out.println("Skipping IPv6-only " + key);
continue;
}
File toFile = new File(toDir, file.getName());
// We could call ri.write() to avoid simultaneous change by the router
boolean ok = FileUtil.copy(file, toFile, true, true);
if (ok)
copied++;
else
System.out.println("Failed copy of " + file + " to " + toDir);
} catch (Exception e) {
System.out.println("Skipping bad " + file);
} finally {
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
}
}
if (copied > 0) {
// now do all the geoip lookups, and delete any bad countries
geoIP.blockingLookup();
for (Map.Entry<String, String> e : ipMap.entrySet()) {
String co = geoIP.get(e.getKey());
if (co != null) {
if (BadCountries.contains(co)) {
String name = e.getValue();
File toFile = new File(toDir, name);
if (toFile.delete()) {
String full = geoIP.fullName(co);
if (full == null)
full = co;
System.out.println("Skipping " + full + ": " + name);
copied--;
}
}
}
}
}
if (copied > 0) {
System.out.println("Copied " + copied + " router info files to " + toDir);
} else {
System.out.println("Failed to copy any files to " + toDir);
System.exit(1);
}
}
private static void usage() {
System.err.println("Usage: PersistentDataStore [-i $HOME/.i2p] [-o netDb/] [-c 200]");
}
}

View File

@@ -54,8 +54,8 @@ class PersistentDataStore extends TransientDataStore {
private final static int READ_DELAY = 2*60*1000;
private static final String PROP_FLAT = "router.networkDatabase.flat";
private static final String DIR_PREFIX = "r";
private static final String B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~";
static final String DIR_PREFIX = "r";
static final String B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-~";
/**
* @param dbDir relative path
@@ -614,7 +614,7 @@ class PersistentDataStore extends TransientDataStore {
return DIR_PREFIX + b64.charAt(0) + File.separatorChar + ROUTERINFO_PREFIX + b64 + ROUTERINFO_SUFFIX;
}
private static Hash getRouterInfoHash(String filename) {
static Hash getRouterInfoHash(String filename) {
return getHash(filename, ROUTERINFO_PREFIX, ROUTERINFO_SUFFIX);
}
@@ -651,7 +651,7 @@ class PersistentDataStore extends TransientDataStore {
}
}
private final static class RouterInfoFilter implements FilenameFilter {
static class RouterInfoFilter implements FilenameFilter {
private static final FilenameFilter _instance = new RouterInfoFilter();
public static final FilenameFilter getInstance() { return _instance; }
public boolean accept(File dir, String name) {

View File

@@ -74,8 +74,7 @@ public class Reseeder {
"http://reseed.i2p-projekt.de/" + "," +
//"http://euve5653.vserver.de/netDb/" + "," +
"http://cowpuncher.drollette.com/netdb/" + "," +
//Temp disabled (#1351)
//"http://i2p.mooo.com/netDb/" + "," +
"http://i2p.mooo.com/netDb/" + "," +
"http://193.150.121.66/netDb/" + "," +
"http://netdb.i2p2.no/" + "," +
"http://reseed.info/" + "," +
@@ -93,8 +92,7 @@ public class Reseeder {
"https://reseed.i2p-projekt.de/" + "," +
//"https://euve5653.vserver.de/netDb/" + "," +
"https://cowpuncher.drollette.com/netdb/" + "," +
//Temp disabled (#1351)
//"https://i2p.mooo.com/netDb/" + "," +
"https://i2p.mooo.com/netDb/" + "," +
"https://193.150.121.66/netDb/" + "," +
"https://netdb.i2p2.no/" + "," +
"https://reseed.info/" + "," +

View File

@@ -271,6 +271,8 @@ public class WorkingDir {
// We don't currently have a default addressbook/ in the base distribution,
// but distros might put one in
"addressbook,eepsite," +
// 0.9.15 support bundled router infos
"netDb," +
// base install - files
// We don't currently have a default router.config, logger.config, susimail.config, or webapps.config in the base distribution,
// but distros might put one in

View File

@@ -0,0 +1,101 @@
package net.i2p.router.tasks;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import net.i2p.crypto.SigType;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
import net.i2p.util.SystemVersion;
/**
* Warn about unavailable crypto to router and wrapper logs
*
* @since 0.9.15
*/
public class CryptoChecker {
private static String JRE6 = "http://www.oracle.com/technetwork/java/javase/downloads/index.html";
// these two are US-only and can change?
//private static String JRE7 = "http://www.oracle.com/technetwork/java/javase/documentation/java-se-7-doc-download-435117.html";
//private static String JRE8 = "http://www.oracle.com/technetwork/java/javase/documentation/jdk8-doc-downloads-2133158.html";
/**
* @param ctx if null, logs only to System.out (called from main)
*/
public static void warnUnavailableCrypto(RouterContext ctx) {
if (SystemVersion.isAndroid())
return;
boolean unavail = false;
Log log = null;
for (SigType t : SigType.values()) {
if (!t.isAvailable()) {
if (!unavail) {
unavail = true;
if (ctx != null)
log = ctx.logManager().getLog(CryptoChecker.class);
}
String s = "Crypto " + t + " is not available";
if (log != null)
log.logAlways(log.WARN, s);
System.out.println("Warning: " + s);
}
}
if (unavail) {
if (!SystemVersion.isJava7()) {
String s = "Java version: " + System.getProperty("java.version") + " Please consider upgrading to Java 7";
if (log != null)
log.logAlways(log.WARN, s);
System.out.println(s);
}
if (!isUnlimited()) {
String s = "Please consider installing the Java Cryptography Unlimited Strength Jurisdiction Policy Files from ";
//if (SystemVersion.isJava8())
// s += JRE8;
//else if (SystemVersion.isJava7())
// s += JRE7;
//else
s += JRE6;
if (log != null)
log.logAlways(log.WARN, s);
System.out.println(s);
}
String s = "This crypto will be required in a future release";
if (log != null)
log.logAlways(log.WARN, s);
System.out.println("Warning: " + s);
} else if (ctx == null) {
// called from main()
System.out.println("All crypto available");
}
}
/**
* Copied from CryptixAESEngine
*/
private static boolean isUnlimited() {
try {
if (Cipher.getMaxAllowedKeyLength("AES") < 256)
return false;
} catch (NoSuchAlgorithmException e) {
return false;
} catch (NoSuchMethodError e) {
// JamVM, gij
try {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
} catch (GeneralSecurityException gse) {
return false;
}
}
return true;
}
public static void main(String[] args) {
warnUnavailableCrypto(null);
}
}

View File

@@ -9,7 +9,7 @@ import java.util.Set;
* Maintain a list of bad places.
* @since 0.8.13
*/
abstract class BadCountries {
public abstract class BadCountries {
private static final Set<String> _countries;

View File

@@ -16,6 +16,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import net.i2p.I2PAppContext;
import net.i2p.data.Hash;
import net.i2p.router.Router;
import net.i2p.router.RouterContext;
@@ -38,11 +39,9 @@ import net.i2p.util.Log;
*
* @author zzz
*/
class GeoIP {
public class GeoIP {
private final Log _log;
// change to test with main()
//private final I2PAppContext _context;
private final RouterContext _context;
private final I2PAppContext _context;
private final Map<String, String> _codeToName;
/** code to itself to prevent String proliferation */
private final Map<String, String> _codeCache;
@@ -56,8 +55,10 @@ class GeoIP {
private final AtomicBoolean _lock;
private int _lookupRunCount;
//public GeoIP(I2PAppContext context) {
public GeoIP(RouterContext context) {
/**
* @param context RouterContext in production, I2PAppContext for testing only
*/
public GeoIP(I2PAppContext context) {
_context = context;
_log = context.logManager().getLog(GeoIP.class);
_codeToName = new ConcurrentHashMap<String, String>(512);
@@ -71,6 +72,7 @@ class GeoIP {
}
static final String PROP_GEOIP_ENABLED = "routerconsole.geoip.enable";
public static final String PROP_GEOIP_DIR = "geoip.dir";
static final String GEOIP_DIR_DEFAULT = "geoip";
static final String GEOIP_FILE_DEFAULT = "geoip.txt";
static final String COUNTRY_FILE_DEFAULT = "countries.txt";
@@ -187,7 +189,10 @@ class GeoIP {
*
*/
private void readCountryFile() {
File geoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
String geoDir = _context.getProperty(PROP_GEOIP_DIR, GEOIP_DIR_DEFAULT);
File geoFile = new File(geoDir);
if (!geoFile.isAbsolute())
geoFile = new File(_context.getBaseDir(), geoDir);
geoFile = new File(geoFile, COUNTRY_FILE_DEFAULT);
if (!geoFile.exists()) {
if (_log.shouldLog(Log.WARN))
@@ -246,7 +251,10 @@ class GeoIP {
*
*/
private String[] readGeoIPFile(Long[] search) {
File geoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
String geoDir = _context.getProperty(PROP_GEOIP_DIR, GEOIP_DIR_DEFAULT);
File geoFile = new File(geoDir);
if (!geoFile.isAbsolute())
geoFile = new File(_context.getBaseDir(), geoDir);
geoFile = new File(geoFile, GEOIP_FILE_DEFAULT);
if (!geoFile.exists()) {
if (_log.shouldLog(Log.WARN))
@@ -300,24 +308,28 @@ class GeoIP {
/**
* Put our country code in the config, where others (such as Timestamper) can get it,
* and it will be there next time at startup.
*
* Does nothing in I2PAppContext
*/
private void updateOurCountry() {
/**** comment out to test with main() */
String oldCountry = _context.router().getConfigSetting(PROP_IP_COUNTRY);
Hash ourHash = _context.routerHash();
if (! (_context instanceof RouterContext))
return;
RouterContext ctx = (RouterContext) _context;
String oldCountry = ctx.router().getConfigSetting(PROP_IP_COUNTRY);
Hash ourHash = ctx.routerHash();
// we should always have a RouterInfo by now, but we had one report of an NPE here
if (ourHash == null)
return;
String country = _context.commSystem().getCountry(ourHash);
String country = ctx.commSystem().getCountry(ourHash);
if (country != null && !country.equals(oldCountry)) {
_context.router().saveConfig(PROP_IP_COUNTRY, country);
if (_context.commSystem().isInBadCountry() && _context.getProperty(Router.PROP_HIDDEN_HIDDEN) == null) {
ctx.router().saveConfig(PROP_IP_COUNTRY, country);
if (ctx.commSystem().isInBadCountry() && ctx.getProperty(Router.PROP_HIDDEN_HIDDEN) == null) {
String name = fullName(country);
if (name == null)
name = country;
_log.logAlways(Log.WARN, "Setting hidden mode to protect you in " + name +
", you may override on the network configuration page");
_context.router().rebuildRouterInfo();
ctx.router().rebuildRouterInfo();
}
}
/****/

View File

@@ -292,7 +292,14 @@ public class ControlPoint implements HTTPRequestListener
DeviceList devList = new DeviceList();
int nRoots = devNodeList.size();
for (int n=0; n<nRoots; n++) {
Node rootNode = devNodeList.getNode(n);
// AIOOB was thrown from here, maybe would be better to
// copy the list before traversal?
Node rootNode;
try {
rootNode = devNodeList.getNode(n);
} catch (ArrayIndexOutOfBoundsException aioob) {
break;
}
Device dev = getDevice(rootNode);
if (dev == null)
continue;

View File

@@ -164,6 +164,14 @@ do
else
compute_dates
fi
if grep '\s$' $i > /dev/null 2>&1; then
echo "********* Trailing whitespace found in file $i *********"
FAIL=1
fi
if grep '^\s' $i > /dev/null 2>&1; then
echo "********* Leading whitespace found in file $i *********"
FAIL=1
fi
done
if [ -n "$FAIL" ]; then