* SSLEepGet, Reseeder:
- Implement additional CA loading - Provide facility to reuse SSL state for speed - Provide facility to store previously untrusted certificates - Add SSL reseed hosts, prefer them by default - Reseed message cleanup * build.xml: - Add www.cacert.org cert to the installer and updater so SSL on a.netdb.i2p2.de and c.netdb.i2p2.de will work - Cleanup, fix distclean error in older ants.
This commit is contained in:
@ -29,6 +29,8 @@ import net.i2p.util.Translate;
|
||||
* specified below unless the I2P configuration property "i2p.reseedURL" is
|
||||
* set. It always writes to ./netDb/, so don't mess with that.
|
||||
*
|
||||
* This is somewhat complicated by trying to log to three places - the console,
|
||||
* the router log, and the wrapper log.
|
||||
*/
|
||||
public class Reseeder {
|
||||
private static ReseedRunner _reseedRunner;
|
||||
@ -40,12 +42,25 @@ public class Reseeder {
|
||||
|
||||
private static final String DEFAULT_SEED_URL =
|
||||
"http://a.netdb.i2p2.de/,http://b.netdb.i2p2.de/,http://c.netdb.i2p2.de/," +
|
||||
"http://reseed.i2p-projekt.de/,http://i2pbote.net/netDb/,http://r31453.ovh.net/static_media/netDb/";
|
||||
"http://reseed.i2p-projekt.de/,http://www.i2pbote.net/netDb/,http://r31453.ovh.net/static_media/netDb/";
|
||||
|
||||
/** @since 0.8.2 */
|
||||
private static final String DEFAULT_SSL_SEED_URL =
|
||||
"https://a.netdb.i2p2.de/,https://c.netdb.i2p2.de/," +
|
||||
"https://www.i2pbote.net/netDb/";
|
||||
|
||||
private static final String PROP_INPROGRESS = "net.i2p.router.web.ReseedHandler.reseedInProgress";
|
||||
/** the console shows this message while reseedInProgress == false */
|
||||
private static final String PROP_ERROR = "net.i2p.router.web.ReseedHandler.errorMessage";
|
||||
/** the console shows this message while reseedInProgress == true */
|
||||
private static final String PROP_STATUS = "net.i2p.router.web.ReseedHandler.statusMessage";
|
||||
public static final String PROP_PROXY_HOST = "router.reseedProxyHost";
|
||||
public static final String PROP_PROXY_PORT = "router.reseedProxyPort";
|
||||
/** @since 0.8.2 */
|
||||
public static final String PROP_PROXY_ENABLE = "router.reseedProxyEnable";
|
||||
/** @since 0.8.2 */
|
||||
public static final String PROP_SSL_DISABLE = "router.reseedSSLDisable";
|
||||
|
||||
private static final String RESEED_TIPS =
|
||||
_x("Ensure that nothing blocks outbound HTTP, check <a target=\"_top\" href=\"logs.jsp\">logs</a> " +
|
||||
"and if nothing helps, read the <a target=\"_top\" href=\"http://www.i2p2.de/faq.html\">FAQ</a> about reseeding manually.");
|
||||
@ -63,7 +78,6 @@ public class Reseeder {
|
||||
if (_reseedRunner.isRunning()) {
|
||||
return;
|
||||
} else {
|
||||
System.setProperty(PROP_INPROGRESS, "true");
|
||||
// set to daemon so it doesn't hang a shutdown
|
||||
Thread reseed = new I2PAppThread(_reseedRunner, "Reseed", true);
|
||||
reseed.start();
|
||||
@ -76,20 +90,46 @@ public class Reseeder {
|
||||
private boolean _isRunning;
|
||||
private String _proxyHost;
|
||||
private int _proxyPort;
|
||||
private SSLEepGet.SSLState _sslState;
|
||||
|
||||
public ReseedRunner() {
|
||||
_isRunning = false;
|
||||
System.clearProperty(PROP_ERROR);
|
||||
System.setProperty(PROP_STATUS, _("Reseeding"));
|
||||
System.setProperty(PROP_INPROGRESS, "true");
|
||||
}
|
||||
public boolean isRunning() { return _isRunning; }
|
||||
|
||||
/*
|
||||
* Do it.
|
||||
* We update PROP_ERROR here.
|
||||
*/
|
||||
public void run() {
|
||||
_isRunning = true;
|
||||
_proxyHost = _context.getProperty(PROP_PROXY_HOST);
|
||||
_proxyPort = _context.getProperty(PROP_PROXY_PORT, -1);
|
||||
_sslState = null; // start fresh
|
||||
if (_context.getBooleanProperty(PROP_PROXY_ENABLE)) {
|
||||
_proxyHost = _context.getProperty(PROP_PROXY_HOST);
|
||||
_proxyPort = _context.getProperty(PROP_PROXY_PORT, -1);
|
||||
}
|
||||
System.out.println("Reseed start");
|
||||
reseed(false);
|
||||
System.out.println("Reseed complete");
|
||||
int total = reseed(false);
|
||||
if (total >= 50) {
|
||||
System.out.println("Reseed complete, " + total + " received");
|
||||
System.clearProperty(PROP_ERROR);
|
||||
} else if (total > 0) {
|
||||
System.out.println("Reseed complete, only " + total + " received");
|
||||
System.setProperty(PROP_ERROR, ngettext("Reseed fetched only 1 router.",
|
||||
"Reseed fetched only {0} routers.", total));
|
||||
} else {
|
||||
System.out.println("Reseed failed, check network connection");
|
||||
System.out.println(
|
||||
"Ensure that nothing blocks outbound HTTP, check the logs, " +
|
||||
"and if nothing helps, read the FAQ about reseeding manually.");
|
||||
System.setProperty(PROP_ERROR, _("Reseed failed.") + ' ' + _(RESEED_TIPS));
|
||||
}
|
||||
System.setProperty(PROP_INPROGRESS, "false");
|
||||
System.clearProperty(PROP_STATUS);
|
||||
_sslState = null; // don't hold ref
|
||||
_isRunning = false;
|
||||
}
|
||||
|
||||
@ -112,16 +152,56 @@ public class Reseeder {
|
||||
* the routerInfo-*.dat files from the specified URL (or the default) and
|
||||
* save them into this router's netDb dir.
|
||||
*
|
||||
* - If list specified in the properties, use it randomly, without regard to http/https
|
||||
* - If SSL not disabled, use the https randomly then
|
||||
* the http randomly
|
||||
* - Otherwise just the http randomly.
|
||||
*
|
||||
* @param echoStatus apparently always false
|
||||
* @return count of routerinfos successfully fetched
|
||||
*/
|
||||
private void reseed(boolean echoStatus) {
|
||||
List URLList = new ArrayList();
|
||||
String URLs = _context.getProperty("i2p.reseedURL", DEFAULT_SEED_URL);
|
||||
private int reseed(boolean echoStatus) {
|
||||
List<String> URLList = new ArrayList();
|
||||
String URLs = _context.getProperty("i2p.reseedURL");
|
||||
boolean defaulted = URLs == null;
|
||||
boolean SSLDisable = _context.getBooleanProperty(PROP_SSL_DISABLE);
|
||||
if (defaulted) {
|
||||
if (SSLDisable)
|
||||
URLs = DEFAULT_SEED_URL;
|
||||
else
|
||||
URLs = DEFAULT_SSL_SEED_URL;
|
||||
}
|
||||
StringTokenizer tok = new StringTokenizer(URLs, " ,");
|
||||
while (tok.hasMoreTokens())
|
||||
URLList.add(tok.nextToken().trim());
|
||||
Collections.shuffle(URLList);
|
||||
for (int i = 0; i < URLList.size() && _isRunning; i++)
|
||||
reseedOne((String) URLList.get(i), echoStatus);
|
||||
if (defaulted && !SSLDisable) {
|
||||
// put the non-SSL at the end of the SSL
|
||||
List<String> URLList2 = new ArrayList();
|
||||
tok = new StringTokenizer(DEFAULT_SSL_SEED_URL, " ,");
|
||||
while (tok.hasMoreTokens())
|
||||
URLList2.add(tok.nextToken().trim());
|
||||
Collections.shuffle(URLList2);
|
||||
URLList.addAll(URLList2);
|
||||
}
|
||||
int total = 0;
|
||||
for (int i = 0; i < URLList.size() && _isRunning; i++) {
|
||||
String url = URLList.get(i);
|
||||
int dl = reseedOne(url, echoStatus);
|
||||
if (dl > 0) {
|
||||
total += dl;
|
||||
// remove alternate version if we haven't tried it yet
|
||||
String alt;
|
||||
if (url.startsWith("http://"))
|
||||
alt = url.replace("http://", "https://");
|
||||
else
|
||||
alt = url.replace("https://", "http://");
|
||||
int idx = URLList.indexOf(alt);
|
||||
if (idx > i)
|
||||
URLList.remove(i);
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -138,22 +218,23 @@ public class Reseeder {
|
||||
*
|
||||
* Jetty directory listings are not compatible, as they look like
|
||||
* HREF="/full/path/to/routerInfo-...
|
||||
*
|
||||
* We update PROP_STATUS here.
|
||||
*
|
||||
* @param echoStatus apparently always false
|
||||
* @return count of routerinfos successfully fetched
|
||||
**/
|
||||
private void reseedOne(String seedURL, boolean echoStatus) {
|
||||
|
||||
private int reseedOne(String seedURL, boolean echoStatus) {
|
||||
try {
|
||||
System.setProperty(PROP_ERROR, "");
|
||||
System.setProperty(PROP_STATUS, _("Reseeding: fetching seed URL."));
|
||||
System.err.println("Reseed from " + seedURL);
|
||||
System.err.println("Reseeding from " + seedURL);
|
||||
URL dir = new URL(seedURL);
|
||||
byte contentRaw[] = readURL(dir);
|
||||
if (contentRaw == null) {
|
||||
System.setProperty(PROP_ERROR,
|
||||
_("Last reseed failed fully (failed reading seed URL).") + ' ' +
|
||||
_(RESEED_TIPS));
|
||||
// Logging deprecated here since attemptFailed() provides better info
|
||||
_log.debug("Failed reading seed URL: " + seedURL);
|
||||
return;
|
||||
_log.warn("Failed reading seed URL: " + seedURL);
|
||||
System.err.println("Reseed got no router infos from " + seedURL);
|
||||
return 0;
|
||||
}
|
||||
String content = new String(contentRaw);
|
||||
Set<String> urls = new HashSet(1024);
|
||||
@ -173,11 +254,9 @@ public class Reseeder {
|
||||
cur = end + 1;
|
||||
}
|
||||
if (total <= 0) {
|
||||
_log.error("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
|
||||
System.setProperty(PROP_ERROR,
|
||||
_("Last reseed failed fully (no routerInfo URLs at seed URL).") + ' ' +
|
||||
_(RESEED_TIPS));
|
||||
return;
|
||||
_log.warn("Read " + contentRaw.length + " bytes from seed " + seedURL + ", but found no routerInfo URLs.");
|
||||
System.err.println("Reseed got no router infos from " + seedURL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<String> urlList = new ArrayList(urls);
|
||||
@ -201,32 +280,18 @@ public class Reseeder {
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
System.err.println("Reseed got " + fetched + " router infos from " + seedURL);
|
||||
|
||||
int failPercent = 100 * errors / total;
|
||||
|
||||
// Less than 10% of failures is considered success,
|
||||
// because some routerInfos will always fail.
|
||||
if ((failPercent >= 10) && (failPercent < 90)) {
|
||||
System.setProperty(PROP_ERROR,
|
||||
_("Last reseed failed partly ({0}% of {1}).", failPercent, total) + ' ' +
|
||||
_(RESEED_TIPS));
|
||||
}
|
||||
if (failPercent >= 90) {
|
||||
System.setProperty(PROP_ERROR,
|
||||
_("Last reseed failed ({0}% of {1}).", failPercent, total) + ' ' +
|
||||
_(RESEED_TIPS));
|
||||
}
|
||||
System.err.println("Reseed got " + fetched + " router infos from " + seedURL + " with " + errors + " errors");
|
||||
|
||||
if (fetched > 0)
|
||||
_context.netDb().rescan();
|
||||
// Don't go on to the next URL if we have enough
|
||||
if (fetched >= 100)
|
||||
_isRunning = false;
|
||||
return fetched;
|
||||
} catch (Throwable t) {
|
||||
System.setProperty(PROP_ERROR,
|
||||
_("Last reseed failed fully (exception caught).") + ' ' +
|
||||
_(RESEED_TIPS));
|
||||
_log.error("Error reseeding", t);
|
||||
_log.warn("Error reseeding", t);
|
||||
System.err.println("Reseed got no router infos from " + seedURL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,8 +313,17 @@ public class Reseeder {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
|
||||
|
||||
EepGet get;
|
||||
if (url.toString().startsWith("https")) {
|
||||
get = new SSLEepGet(I2PAppContext.getGlobalContext(), baos, url.toString());
|
||||
boolean ssl = url.toString().startsWith("https");
|
||||
if (ssl) {
|
||||
SSLEepGet sslget;
|
||||
if (_sslState == null) {
|
||||
sslget = new SSLEepGet(I2PAppContext.getGlobalContext(), baos, url.toString());
|
||||
// save state for next time
|
||||
_sslState = sslget.getSSLState();
|
||||
} else {
|
||||
sslget = new SSLEepGet(I2PAppContext.getGlobalContext(), baos, url.toString(), _sslState);
|
||||
}
|
||||
get = sslget;
|
||||
} else {
|
||||
// Do a (probably) non-proxied eepget into our ByteArrayOutputStream with 0 retries
|
||||
boolean shouldProxy = _proxyHost != null && _proxyHost.length() > 0 && _proxyPort > 0;
|
||||
@ -257,7 +331,9 @@ public class Reseeder {
|
||||
null, baos, url.toString(), false, null, null);
|
||||
}
|
||||
get.addStatusListener(ReseedRunner.this);
|
||||
if (get.fetch()) return baos.toByteArray(); else return null;
|
||||
if (get.fetch())
|
||||
return baos.toByteArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
private void writeSeed(String name, byte data[]) throws Exception {
|
||||
@ -295,6 +371,11 @@ public class Reseeder {
|
||||
return Translate.getString(s, o, o2, _context, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
/** translate */
|
||||
private String ngettext(String s, String p, int n) {
|
||||
return Translate.getString(n, s, p, _context, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
/******
|
||||
public static void main(String args[]) {
|
||||
if ( (args != null) && (args.length == 1) && (!Boolean.valueOf(args[0]).booleanValue()) ) {
|
||||
|
Reference in New Issue
Block a user