merge of '4d8cced5819f256dd03cd1a845bcb08fe8de9319'

and '76cdc242b9b68e5fef39dfe67cf27baf29872f2f'
This commit is contained in:
meeh
2018-04-29 18:51:38 +00:00
35 changed files with 971 additions and 99 deletions

View File

@@ -202,7 +202,6 @@
<fileset dir="build/obj" includes="**/standalone/*.class" />
<zipfileset src="build/i2psnark.jar" />
<zipfileset src="../../../core/java/build/i2p.jar" />
<zipfileset src="../../jetty/jettylib/commons-logging.jar" />
<!-- without this we get a warning about 'no JSP support' but that's it
<zipfileset src="../../jetty/jettylib/jasper-runtime.jar" />
-->

View File

@@ -56,7 +56,7 @@
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
destdir="./build/obj"
includeAntRuntime="false"
classpath="../../../core/java/build/i2p.jar:build/i2ptunnel.jar:../../jetty/jettylib/jetty-i2p.jar:../../jetty/jettylib/jetty-xml.jar" >
classpath="../../../core/java/build/i2p.jar:build/i2ptunnel.jar:../../jetty/jettylib/jetty-i2p.jar:../../jetty/jettylib/jetty-util.jar:../../jetty/jettylib/jetty-xml.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>
@@ -318,7 +318,6 @@
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
<pathelement location="../../jetty/jettylib/jasper-el.jar" />
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
<pathelement location="../../jetty/jettylib/commons-el.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
<pathelement location="${ant.home}/lib/ant.jar" />
@@ -353,8 +352,8 @@
<pathelement location="../../jetty/jettylib/tomcat-util.jar" />
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
<pathelement location="../../jetty/jettylib/commons-el.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
<pathelement location="build/i2ptunnel.jar" />
<pathelement location="build/temp-beans.jar" />
<pathelement location="../../../core/java/build/i2p.jar" />

View File

@@ -774,7 +774,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn
"<a href=\"" + conflictURL + "\">").getBytes("UTF-8"));
out.write(_t("Conflicting address helper destination").getBytes("UTF-8"));
out.write(("</a></th></tr>\n").getBytes("UTF-8"));
if (_context.portMapper().getPort(PortMapper.SVC_IMAGEGEN) > 0) {
if (_context.portMapper().isRegistered(PortMapper.SVC_IMAGEGEN)) {
out.write(("<tr><td align=\"center\">" +
"<a href=\"" + trustedURL + "\">" +
"<img src=\"" +

View File

@@ -544,8 +544,8 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
char[] buf = new char[512];
StringBuilder out = new StringBuilder(2048);
try {
boolean hasSusiDNS = ctx.portMapper().getPort(PortMapper.SVC_SUSIDNS) > 0;
boolean hasI2PTunnel = ctx.portMapper().getPort(PortMapper.SVC_I2PTUNNEL) > 0;
boolean hasSusiDNS = ctx.portMapper().isRegistered(PortMapper.SVC_SUSIDNS);
boolean hasI2PTunnel = ctx.portMapper().isRegistered(PortMapper.SVC_I2PTUNNEL);
if (hasSusiDNS && hasI2PTunnel) {
reader = new TranslateReader(ctx, BUNDLE_NAME, new FileInputStream(file));
} else {
@@ -821,11 +821,12 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem
private static String getFooter() {
// The css is hiding this div for now, but we'll keep it here anyway
// Tag the strings below for translation if we unhide it.
StringBuilder buf = new StringBuilder(128);
buf.append("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ")
.append(new Date().toString())
.append("</i></div>\n</body>\n</html>\n");
return buf.toString();
//StringBuilder buf = new StringBuilder(128);
//buf.append("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ")
// .append(new Date().toString())
// .append("</i></div>\n</body>\n</html>\n");
//return buf.toString();
return "</body>\n</html>\n";
}
/**

View File

@@ -45,8 +45,8 @@ public class TunnelControllerGroup implements ClientApp {
private final List<TunnelController> _controllers;
private final ReadWriteLock _controllersLock;
// locking: this
private boolean _controllersLoaded;
private final Object _controllersLoadedLock = new Object();
private final String _configFile;
private static final String REGISTERED_NAME = "i2ptunnel";
@@ -155,7 +155,7 @@ public class TunnelControllerGroup implements ClientApp {
} catch (IllegalArgumentException iae) {
if (DEFAULT_CONFIG_FILE.equals(_configFile) && !_context.isRouterContext()) {
// for i2ptunnel command line
synchronized (_controllersLoadedLock) {
synchronized (this) {
_controllersLoaded = true;
}
_log.logAlways(Log.WARN, "Not in router context and no preconfigured tunnels");
@@ -263,10 +263,8 @@ public class TunnelControllerGroup implements ClientApp {
* @throws IllegalArgumentException if unable to load from file
*/
public synchronized void loadControllers(String configFile) {
synchronized (_controllersLoadedLock) {
if (_controllersLoaded)
return;
}
if (_controllersLoaded)
return;
Properties cfg = loadConfig(configFile);
int i = 0;
@@ -284,9 +282,7 @@ public class TunnelControllerGroup implements ClientApp {
_controllersLock.writeLock().unlock();
}
synchronized (_controllersLoadedLock) {
_controllersLoaded = true;
}
_controllersLoaded = true;
if (i > 0) {
if (_log.shouldLog(Log.INFO))
_log.info(i + " controllers loaded from " + configFile);
@@ -346,10 +342,8 @@ public class TunnelControllerGroup implements ClientApp {
*
*/
public synchronized void unloadControllers() {
synchronized (_controllersLoadedLock) {
if (!_controllersLoaded)
return;
}
if (!_controllersLoaded)
return;
_controllersLock.writeLock().lock();
try {
@@ -359,9 +353,7 @@ public class TunnelControllerGroup implements ClientApp {
_controllersLock.writeLock().unlock();
}
synchronized (_controllersLoadedLock) {
_controllersLoaded = false;
}
_controllersLoaded = false;
if (_log.shouldLog(Log.INFO))
_log.info("All controllers stopped and unloaded");
}
@@ -577,7 +569,7 @@ public class TunnelControllerGroup implements ClientApp {
* @throws IllegalArgumentException if unable to load config from file
*/
public List<TunnelController> getControllers() {
synchronized (_controllersLoadedLock) {
synchronized (this) {
if (!_controllersLoaded)
loadControllers(_configFile);
}

View File

@@ -217,7 +217,7 @@ public abstract class LocalHTTPServer {
"<div class=logo>\n" +
"<a href=\"" + conURL + "\" title=\"" + _t("Router Console") + "\"><img src=\"http://proxy.i2p/themes/console/images/i2plogo.png\" alt=\"I2P Router Console\" border=\"0\"></a><hr>\n" +
"<a href=\"" + conURL + "config\">" + _t("Configuration") + "</a> <a href=\"" + conURL + "help.jsp\">" + _t("Help") + "</a>").getBytes("UTF-8"));
if (pm.getPort(PortMapper.SVC_SUSIDNS) > 0)
if (pm.isRegistered(PortMapper.SVC_SUSIDNS))
out.write((" <a href=\"" + conURL + "susidns/index\">" + _t("Addressbook") + "</a>\n").getBytes("UTF-8"));
out.write(("</div>" +
"<div class=warning id=warning>\n" +

View File

@@ -134,8 +134,11 @@ public class IndexBean {
}
}
/** do we know this nonce? @since 0.8.1 */
private static boolean haveNonce(String nonce) {
/**
* do we know this nonce?
* @since 0.8.1 public since 0.9.35
*/
public static boolean haveNonce(String nonce) {
synchronized (_nonces) {
return _nonces.contains(nonce);
}

View File

@@ -0,0 +1,60 @@
package net.i2p.i2ptunnel.web;
import java.util.ArrayList;
import java.util.List;
/**
* Helper class for ssl.jsp
*
* @since 0.9.35
*/
public class SSLHelper {
/**
* Adapted from LoadClientAppsJob
* @return param args non-null
* @return non-null
*/
public static List<String> parseArgs(String args) {
List<String> argList = new ArrayList<String>(4);
StringBuilder buf = new StringBuilder(32);
boolean isQuoted = false;
for (int j = 0; j < args.length(); j++) {
char c = args.charAt(j);
switch (c) {
case '\'':
case '"':
if (isQuoted) {
String str = buf.toString().trim();
if (str.length() > 0)
argList.add(str);
buf.setLength(0);
}
isQuoted = !isQuoted;
break;
case ' ':
case '\t':
// whitespace - if we're in a quoted section, keep this as part of the quote,
// otherwise use it as a delim
if (isQuoted) {
buf.append(c);
} else {
String str = buf.toString().trim();
if (str.length() > 0)
argList.add(str);
buf.setLength(0);
}
break;
default:
buf.append(c);
break;
}
}
if (buf.length() > 0) {
String str = buf.toString().trim();
if (str.length() > 0)
argList.add(str);
}
return argList;
}
}

578
apps/i2ptunnel/jsp/ssl.jsp Normal file
View File

@@ -0,0 +1,578 @@
<%
// NOTE: Do the header carefully so there is no whitespace before the <?xml... line
response.setHeader("X-Frame-Options", "SAMEORIGIN");
response.setHeader("Content-Security-Policy", "default-src 'self'; style-src 'self' 'unsafe-inline'");
response.setHeader("X-XSS-Protection", "1; mode=block");
response.setHeader("X-Content-Type-Options", "nosniff");
response.setHeader("Referrer-Policy", "no-referrer");
response.setHeader("Accept-Ranges", "none");
%><%@page pageEncoding="UTF-8"
%><%@page contentType="text/html" import="java.io.File,java.io.IOException,net.i2p.crypto.KeyStoreUtil,net.i2p.data.DataHelper,net.i2p.jetty.JettyXmlConfigurationParser"
%><%@page
%><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<%
/* right now using EditBean instead of IndexBean for getSpoofedHost() */
/* but might want to POST to it anyway ??? */
%>
<jsp:useBean class="net.i2p.i2ptunnel.web.EditBean" id="editBean" scope="request" />
<jsp:useBean class="net.i2p.i2ptunnel.ui.Messages" id="intl" scope="request" />
<%
String tun = request.getParameter("tunnel");
int curTunnel = -1;
if (tun != null) {
try {
curTunnel = Integer.parseInt(tun);
} catch (NumberFormatException nfe) {
curTunnel = -1;
}
}
%>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><%=intl._t("Hidden Services Manager")%> - <%=intl._t("SSL Helper")%></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="/themes/console/images/favicon.ico" type="image/x-icon" rel="shortcut icon" />
<% if (editBean.allowCSS()) {
%><link rel="icon" href="<%=editBean.getTheme()%>images/favicon.ico" />
<link href="<%=editBean.getTheme()%>i2ptunnel.css?<%=net.i2p.CoreVersion.VERSION%>" rel="stylesheet" type="text/css" />
<% }
%>
<style type='text/css'>
input.default { width: 1px; height: 1px; visibility: hidden; }
</style>
</head>
<body id="tunnelSSL">
<%
net.i2p.I2PAppContext ctx = net.i2p.I2PAppContext.getGlobalContext();
if (!ctx.isRouterContext()) {
%>Unsupported in app context<%
} else if (editBean.isInitialized()) {
%>
<div class="panel" id="ssl">
<%
String tunnelTypeName;
String tunnelType;
boolean valid = false;
if (curTunnel >= 0) {
tunnelTypeName = editBean.getTunnelType(curTunnel);
tunnelType = editBean.getInternalType(curTunnel);
%><h2><%=intl._t("SSL Wizard")%> (<%=editBean.getTunnelName(curTunnel)%>)</h2><%
} else {
tunnelTypeName = "new";
tunnelType = "new";
%><h2>Fail</h2><p>Tunnel not found</p><%
}
// set a bunch of variables for the current configuration
String b64 = editBean.getDestinationBase64(curTunnel);
String b32 = editBean.getDestHashBase32(curTunnel);
// todo
String altb32 = editBean.getAltDestHashBase32(curTunnel);
String name = editBean.getSpoofedHost(curTunnel);
String targetHost = editBean.getTargetHost(curTunnel);
if (targetHost != null && targetHost.indexOf(':') >= 0)
targetHost = '[' + targetHost + ']';
String targetPort = editBean.getTargetPort(curTunnel);
int intPort = 0;
try {
intPort = Integer.parseInt(targetPort);
} catch (NumberFormatException nfe) {}
String clientTgt = targetHost + ':' + targetPort;
boolean sslToTarget = editBean.isSSLEnabled(curTunnel);
String targetLink = clientTgt;
boolean shouldLinkify = true;
if (shouldLinkify) {
String url = "://" + clientTgt + "\">" + clientTgt + "</a>";
if (sslToTarget)
targetLink = "<a href=\"https" + url;
else
targetLink = "<a href=\"http" + url;
}
net.i2p.util.PortMapper pm = ctx.portMapper();
int jettyPort = pm.getPort(net.i2p.util.PortMapper.SVC_EEPSITE);
int jettySSLPort = pm.getPort(net.i2p.util.PortMapper.SVC_HTTPS_EEPSITE);
if (name == null || name.equals(""))
name = editBean.getTunnelName(curTunnel);
if (!"new".equals(tunnelType)) {
// POST handling
String action = request.getParameter("action");
if (action != null) {
String nonce = request.getParameter("nonce");
String newpw = request.getParameter("nofilter_keyPassword");
String kspw = request.getParameter("nofilter_obfKeyStorePassword");
String appNum = request.getParameter("clientAppNumber");
String ksPath = request.getParameter("nofilter_ksPath");
String jettySSLConfigPath = request.getParameter("nofilter_jettySSLFile");
if (newpw != null) {
newpw = newpw.trim();
if (newpw.length() <= 0)
newpw = null;
}
if (kspw != null) {
kspw = JettyXmlConfigurationParser.deobfuscate(kspw);
} else {
kspw = net.i2p.crypto.KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
}
if (!editBean.haveNonce(nonce)) {
out.println(intl._t("Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit.")
+ ' ' +
intl._t("If the problem persists, verify that you have cookies enabled in your browser."));
} else if (!action.equals("Generate")) {
out.println("Unknown form action");
} else if (newpw == null) {
out.println("Password required");
} else if (appNum == null || ksPath == null || jettySSLConfigPath == null) {
out.println("Missing parameters");
} else if (b32.length() <= 0) {
out.println("No destination set - start tunnel first");
} else if (name == null || !name.endsWith(".i2p")) {
out.println("No hostname set - go back and configure");
} else {
boolean ok = true;
// generate selfsigned cert
java.util.Set<String> altNames = new java.util.HashSet<String>(4);
altNames.add(b32);
altNames.add(name);
if (!name.startsWith("www."))
altNames.add("www." + name);
if (altb32 != null && altb32.length() > 0)
altNames.add(altb32);
File ks = new File(ksPath);
try {
Object[] rv = net.i2p.crypto.KeyStoreUtil.createKeysAndCRL(ks, kspw, "eepsite", name, altNames, b32,
3652, "EC", 256, newpw);
out.println("Created selfsigned cert");
// save cert
java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) rv[2];
File f = new net.i2p.util.SecureFile(ctx.getConfigDir(), "certificates");
if (!f.exists())
f.mkdir();
f = new net.i2p.util.SecureFile(f, "eepsite");
if (!f.exists())
f.mkdir();
f = new net.i2p.util.SecureFile(f, b32 + ".crt");
if (f.exists()) {
File fb = new File(f.getParentFile(), b32 + ".crt-" + System.currentTimeMillis() + ".bkup");
net.i2p.util.FileUtil.copy(f, fb, false, true);
}
ok = net.i2p.crypto.CertUtil.saveCert(cert, f);
out.println("selfsigned cert stored");
} catch (IOException ioe) {
ioe.printStackTrace();
ok = false;
} catch (java.security.GeneralSecurityException gse) {
gse.printStackTrace();
ok = false;
}
// rewrite jetty-ssl.xml
if (ok) {
String obf = JettyXmlConfigurationParser.obfuscate(newpw);
String obfkspw = JettyXmlConfigurationParser.obfuscate(kspw);
File f = new File(jettySSLConfigPath);
try {
org.eclipse.jetty.xml.XmlParser.Node root;
root = JettyXmlConfigurationParser.parse(f);
JettyXmlConfigurationParser.setValue(root, "KeyStorePassword", obfkspw);
JettyXmlConfigurationParser.setValue(root, "KeyManagerPassword", obf);
JettyXmlConfigurationParser.setValue(root, "TrustStorePassword", obf);
File fb = new File(jettySSLConfigPath + ".bkup");
if (fb.exists())
fb = new File(jettySSLConfigPath + '-' + System.currentTimeMillis() + ".bkup");
ok = net.i2p.util.FileUtil.copy(f, fb, false, true);
if (ok) {
java.io.Writer w = null;
try {
w = new java.io.OutputStreamWriter(new net.i2p.util.SecureFileOutputStream(f), "UTF-8");
w.write("<!-- Modified by SSL Wizard -->\n");
JettyXmlConfigurationParser.write(root, w);
out.println("Jetty configuration updated");
} catch (IOException ioe) {
ioe.printStackTrace();
ok = false;
} finally {
if (w != null) try { w.close(); } catch (IOException ioe2) {}
}
}
} catch (org.xml.sax.SAXException saxe) {
saxe.printStackTrace();
out.println(DataHelper.escapeHTML(saxe.getMessage()));
ok = false;
}
}
// rewrite clients.config
boolean isSSLEnabled = Boolean.parseBoolean(request.getParameter("isSSLEnabled"));
if (ok && !isSSLEnabled) {
File f = new File(ctx.getConfigDir(), "clients.config");
java.util.Properties p = new net.i2p.util.OrderedProperties();
try {
DataHelper.loadProps(p, f);
String k = "clientApp." + appNum + ".args";
String v = p.getProperty(k);
if (v == null) {
ok = false;
} else {
v += " \"" + jettySSLConfigPath + '"';
p.setProperty(k, v);
DataHelper.storeProps(p, f);
out.println("Jetty SSL enabled");
}
} catch (IOException ioe) {
ioe.printStackTrace();
ok = false;
}
}
// stop and restart jetty
// stop tunnel
if (ok) {
}
// rewrite i2ptunnel.config
if (ok) {
}
// restart tunnel
if (ok) {
}
if (ok) {
out.println(intl. _t("Configuration changes saved"));
}
}
}
%>
<form method="post" action="ssl" accept-charset="UTF-8">
<input type="hidden" name="tunnel" value="<%=curTunnel%>" />
<input type="hidden" name="nonce" value="<%=net.i2p.i2ptunnel.web.IndexBean.getNextNonce()%>" />
<input type="hidden" name="type" value="<%=tunnelType%>" />
<input type="submit" class="default" name="action" value="Save changes" />
<table>
<tr><td colspan="4" class="infohelp"><%=intl._t("Experts only!")%> Beta!</td></tr>
<tr><td colspan="4"><b><%=intl._t("Tunnel name")%>:</b> <%=editBean.getTunnelName(curTunnel)%></td></tr>
<%
if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) {
%>
<tr><td colspan="4"><b><%=intl._t("Website name")%>:</b> <%=editBean.getSpoofedHost(curTunnel)%></td></tr>
<%
}
if (b64 == null || b64.length() < 516) {
%><tr><td class="infohelp"><%=intl._t("Local destination is not available. Start the tunnel.")%></td></tr><%
} else if (name == null || name.equals("") || name.contains(" ") || !name.endsWith(".i2p")) {
if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) {
%><tr><td class="infohelp"><%=intl._t("To enable registration verification, edit tunnel and set name (or website name) to a valid host name ending in '.i2p'")%></td></tr><%
} else {
%><tr><td class="infohelp"><%=intl._t("To enable registration verification, edit tunnel and set name to a valid host name ending in '.i2p'")%></td></tr><%
}
} else {
valid = true;
%>
<tr><td colspan="4"><b><%=intl._t("Base 32")%>:</b> <%=b32%></td></tr>
<%
if (altb32 != null && altb32.length() > 0) {
%>
<tr><td><%=intl._t("Alt Base 32")%>: <%=altb32%></td></tr>
<%
} // altb32
%>
<tr><th colspan="4"><%=intl._t("Incoming I2P Port Routing")%></th></tr>
<tr><th><%=intl._t("Route From I2P Port")%></th><th><%=intl._t("With Virtual Host")%></th><th><%=intl._t("Via SSL?")%></th><th><%=intl._t("To Server Host:Port")%></th></tr>
<tr><td><%=intl._t("Default")%></td><td><%=name%></td><td><%=sslToTarget%></td><td><%=targetLink%></td></tr>
<%
// build tables for vhost and targets
java.util.TreeSet<Integer> ports = new java.util.TreeSet<Integer>();
java.util.Map<Integer, String> tgts = new java.util.HashMap<Integer, String>(4);
java.util.Map<Integer, String> spoofs = new java.util.HashMap<Integer, String>(4);
String custom = editBean.getCustomOptions(curTunnel);
String[] opts = DataHelper.split(custom, "[, ]");
for (int i = 0; i < opts.length; i++) {
String opt = opts[i];
boolean isTgt = false;
if (opt.startsWith("targetForPort.")) {
opt = opt.substring("targetForPort.".length());
isTgt = true;
} else if (opt.startsWith("spoofedHost.")) {
opt = opt.substring("spoofedHost.".length());
} else {
continue;
}
int eq = opt.indexOf('=');
if (eq <= 0)
continue;
int port;
try {
port = Integer.parseInt(opt.substring(0, eq));
} catch (NumberFormatException nfe) {
continue;
}
String tgt = opt.substring(eq + 1);
Integer iport = Integer.valueOf(port);
ports.add(iport);
if (isTgt)
tgts.put(iport, tgt);
else
spoofs.put(iport, tgt);
}
// output vhost and targets
for (Integer port : ports) {
boolean ssl = sslToTarget;
String spoof = spoofs.get(port);
if (spoof == null)
spoof = name;
// can't spoof for HTTPS
if (port.intValue() == 443) {
spoof = b32;
if (altb32 != null && altb32.length() > 0)
spoof += "<br />" + altb32;
ssl = true;
}
String tgt = tgts.get(port);
if (tgt != null) {
if (shouldLinkify) {
String url = "://" + tgt + "\">" + tgt + "</a>";
if (ssl)
tgt = "<a href=\"https" + url;
else
tgt = "<a href=\"http" + url;
}
} else {
tgt = targetLink;
}
%>
<tr><td><%=port%></td><td><%=spoof%></td><td><%=ssl%></td><td><%=tgt%></td></tr>
<%
}
%>
<tr><th colspan="4"><%=intl._t("Add Port Routing")%></th></tr>
<tr><td>
<input type="text" size="6" maxlength="5" id="i2pPort" name="i2pPort" title="<%=intl._t("Specify the port the server is running on")%>" value="" class="freetext port" placeholder="required" />
</td><td>
<input type="text" size="20" id="websiteName" name="spoofedHost" title="<%=intl._t("Website Hostname e.g. mysite.i2p")%>" value="<%=name%>" class="freetext" />
</td><td>
<input value="1" type="checkbox" name="useSSL" class="tickbox" />
</td><td>
<input type="text" size="20" name="targetHost" title="<%=intl._t("Hostname or IP address of the target server")%>" value="<%=targetHost%>" class="freetext host" /> :
<input type="text" size="6" maxlength="5" id="targetPort" name="targetPort" title="<%=intl._t("Specify the port the server is running on")%>" value="" class="freetext port" placeholder="required" />
</td></tr>
<tr><th colspan="4"><%=intl._t("Jetty Clients")%></th></tr>
<tr><th><%=intl._t("Client")%></th><th><%=intl._t("Configuration Files")%></th><th><%=intl._t("Enabled?")%></th><th><%=intl._t("SSL Enabled?")%></th><th><%=intl._t("KS Exists?")%></th><th><%=intl._t("KS Dflt PW?")%></th><th><%=intl._t("Privkey Dflt PW?")%></th></tr>
<%
// Now try to find the Jetty server in clients.config
File configDir = ctx.getConfigDir();
File clientsConfig = new File(configDir, "clients.config");
java.util.Properties clientProps = new java.util.Properties();
try {
DataHelper.loadProps(clientProps, clientsConfig);
for (int i = 0; i < 100; i++) {
String prop = "clientApp." + i + ".main";
String cls = clientProps.getProperty(prop);
if (cls == null)
break;
if (!cls.equals("net.i2p.jetty.JettyStart"))
continue;
prop = "clientApp." + i + ".args";
String clArgs = clientProps.getProperty(prop);
if (clArgs == null)
continue;
prop = "clientApp." + i + ".name";
String clName = clientProps.getProperty(prop);
if (clName == null)
clName = intl._t("I2P webserver (eepsite)");
prop = "clientApp." + i + ".startOnLoad";
String clStart = clientProps.getProperty(prop);
boolean start = true;
if (clStart != null)
start = Boolean.parseBoolean(clStart);
// sample args
// clientApp.3.args="/home/xxx/.i2p/eepsite/jetty.xml" "/home/xxx/.i2p/eepsite/jetty-ssl.xml" "/home/xxx/.i2p/eepsite/jetty-rewrite.xml"
boolean ssl = clArgs.contains("jetty-ssl.xml");
boolean jettySSLFileInArgs = false;
boolean jettySSLFileExists = false;
boolean jettySSLFilePWSet = false;
File jettyFile = null, jettySSLFile = null;
String ksPW = null, kmPW = null, tsPW = null;
String ksPath = null, tsPath = null;
String host = null, port = null;
String sslHost = null, sslPort = null;
String error = "";
java.util.List<String> argList = net.i2p.i2ptunnel.web.SSLHelper.parseArgs(clArgs);
for (String arg : argList) {
if (arg.endsWith("jetty.xml")) {
jettyFile = new File(arg);
if (!jettyFile.isAbsolute())
jettyFile = new File(ctx.getConfigDir(), arg);
} else if (arg.endsWith("jetty-ssl.xml")) {
jettySSLFile = new File(arg);
if (!jettySSLFile.isAbsolute())
jettySSLFile = new File(ctx.getConfigDir(), arg);
jettySSLFileInArgs = true;
}
} // for arg in argList
if (jettySSLFile == null && !argList.isEmpty()) {
String arg = argList.get(0);
File f = new File(arg);
if (!f.isAbsolute())
f = new File(ctx.getConfigDir(), arg);
File p = f.getParentFile();
if (p != null)
jettySSLFile = new File(p, "jetty-ssl.xml");
}
boolean ksDflt = false;
boolean kmDflt = false;
boolean tsDflt = false;
boolean ksExists = false;
if (jettyFile != null && jettyFile.exists()) {
try {
org.eclipse.jetty.xml.XmlParser.Node root;
root = JettyXmlConfigurationParser.parse(jettyFile);
host = JettyXmlConfigurationParser.getValue(root, "host");
port = JettyXmlConfigurationParser.getValue(root, "port");
} catch (org.xml.sax.SAXException saxe) {
saxe.printStackTrace();
error = DataHelper.escapeHTML(saxe.getMessage());
}
}
if (jettySSLFile.exists()) {
try {
org.eclipse.jetty.xml.XmlParser.Node root;
root = JettyXmlConfigurationParser.parse(jettySSLFile);
ksPW = JettyXmlConfigurationParser.getValue(root, "KeyStorePassword");
kmPW = JettyXmlConfigurationParser.getValue(root, "KeyManagerPassword");
tsPW = JettyXmlConfigurationParser.getValue(root, "TrustStorePassword");
ksPath = JettyXmlConfigurationParser.getValue(root, "KeyStorePath");
tsPath = JettyXmlConfigurationParser.getValue(root, "TrustStorePath");
sslHost = JettyXmlConfigurationParser.getValue(root, "host");
sslPort = JettyXmlConfigurationParser.getValue(root, "port");
// we can't proceed unless they are there
// tsPW may be null
File ksFile = null;
boolean tsIsKs = true;
boolean ksArgs = ksPW != null && kmPW != null && ksPath != null;
/** 2015+ installs */
final String DEFAULT_KSPW_1 = KeyStoreUtil.DEFAULT_KEYSTORE_PASSWORD;
final String DEFAULT_KMPW_1 = "myKeyPassword";
/** earlier */
final String DEFAULT_KSPW_2 = "OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4";
final String DEFAULT_KMPW_2 = "OBF:1u2u1wml1z7s1z7a1wnl1u2g";
if (ksArgs) {
jettySSLFileExists = true;
ksDflt = ksPW.equals(DEFAULT_KSPW_1) || ksPW.equals(DEFAULT_KSPW_2);
kmDflt = kmPW.equals(DEFAULT_KMPW_1) || kmPW.equals(DEFAULT_KMPW_2);
ksFile = new File(ksPath);
if (!ksFile.isAbsolute())
ksFile = new File(ctx.getConfigDir(), ksPath);
ksExists = ksFile.exists();
tsIsKs = tsPath == null || ksPath.equals(tsPath);
}
if (tsPW != null) {
tsDflt = tsPW.equals(DEFAULT_KSPW_1) || tsPW.equals(DEFAULT_KSPW_2);
}
} catch (org.xml.sax.SAXException saxe) {
saxe.printStackTrace();
error = DataHelper.escapeHTML(saxe.getMessage());
}
}
boolean canConfigure = jettySSLFileExists;
boolean isEnabled = canConfigure && jettySSLFileInArgs;
boolean isPWDefault = kmDflt || !ksExists;
// now start the output for this client
%>
<tr><td><%=DataHelper.escapeHTML(clName)%></td><td>
<%
for (String arg : argList) {
%><%=DataHelper.escapeHTML(arg)%><br /><%
}
%>
</td><td><%=start%></td><td><%=ssl%></td><td><%=ksExists%> <%=error%></td><td><%=ksDflt%></td><td><%=kmDflt%></td></tr>
<%
if (!canConfigure) {
%>
<tr><td colspan="7">Cannot configure, no Jetty SSL configuration template exists</td></tr>
<%
} else {
if (isEnabled) {
%>
<tr><td colspan="7">Jetty SSL is enabled</td></tr>
<%
} else {
%>
<tr><td colspan="7">Jetty SSL is not enabled</td></tr>
<%
} // isEnabled
if (isPWDefault) {
%>
<tr><td colspan="7">Jetty SSL cert passwords are the default</td></tr>
<%
} else {
%>
<tr><td colspan="7">Jetty SSL cert passwords are not the default</td></tr>
<%
} // isPWDefault
%>
<tr><td colspan="7"><b><%=intl._t("Password")%>:</b>
<input type="hidden" name="clientAppNumber" value="<%=i%>" />
<input type="hidden" name="isSSLEnabled" value="<%=isEnabled%>" />
<input type="hidden" name="nofilter_ksPath" value="<%=ksPath%>" />
<input type="hidden" name="nofilter_jettySSLFile" value="<%=jettySSLFile%>" />
<input type="password" name="nofilter_keyPassword" title="<%=intl._t("Set password required to access this service")%>" value="" class="freetext password" />
<%
if (ksPW != null) {
if (!ksPW.startsWith("OBF:"))
ksPW = JettyXmlConfigurationParser.obfuscate(ksPW);
%>
<input type="hidden" name="nofilter_obfKeyStorePassword" value="<%=ksPW%>" />
<%
}
%>
</td></tr>
<tr><td class="buttons" colspan="7">
<button id="controlSave" class="control" type="submit" name="action" value="Generate"><%=intl._t("Generate certificate")%></button>
</td></tr>
<%
} // canConfigure
} // for client
} catch (IOException ioe) { ioe.printStackTrace(); }
%>
<tr><td colspan="4">
<div class="displayText" tabindex="0" title="<%=intl._t("yyy")%>"></div>
</td></tr>
</table>
</form>
<%
} // valid b64 and name
} // !"new".equals(tunnelType)
if (!valid && curTunnel >= 0) {
%>
<table>
<tr><td><a href="edit?tunnel=<%=curTunnel%>"><%=intl._t("Go back and edit the tunnel")%></a></td></tr>
</table>
<%
} // !valid
%>
</div>
<%
} else {
%>
<div id="notReady"><%=intl._t("Tunnels are not initialized yet, please reload in two minutes.")%></div>
<%
} // isInitialized()
%>
</body>
</html>

View File

@@ -67,6 +67,11 @@
<url-pattern>/register</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>net.i2p.i2ptunnel.jsp.ssl_jsp</servlet-name>
<url-pattern>/ssl</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>net.i2p.servlet.ErrorServlet</servlet-name>
<url-pattern>/error</url-pattern>

View File

@@ -228,7 +228,7 @@
was set individually in wrapper.config, we rename and combine the jars as follows:
jasper.jar : jasper-runtime.jar
jasper-el.jar + el-api.jar : commons-el.jar
tomcat-juli.jar : Add to commons-logging.jar
tomcat-juli.jar : Add to jasper-runtime.jar
empty jar : jasper-compiler.jar
Also, take NOTICE and LICENSE out of each one, we bundle those separately.
@@ -340,7 +340,6 @@
destdir="./build/obj" >
<classpath>
<pathelement location="../../../core/java/build/i2p.jar" />
<pathelement location="./jettylib/commons-logging.jar" />
<pathelement location="./jettylib/org.mortbay.jetty.jar" />
<pathelement location="./jettylib/javax.servlet.jar" />
<pathelement location="./jettylib/jetty-http.jar" />
@@ -361,7 +360,7 @@
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
destdir="./build/obj"
includeAntRuntime="false"
classpath="../../core/java/build/i2p.jar:./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar:./jettylib/jetty-http.jar:./jettylib/jetty-io.jar:./jettylib/jetty-security.jar:./jettylib/jetty-servlet.jar:./jettylib/jetty-util.jar:./jettylib/jetty-xml.jar" >
classpath="../../core/java/build/i2p.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar:./jettylib/jetty-http.jar:./jettylib/jetty-io.jar:./jettylib/jetty-security.jar:./jettylib/jetty-servlet.jar:./jettylib/jetty-util.jar:./jettylib/jetty-xml.jar" >
<compilerarg line="${javac.compilerargs}" />
</javac>
</target>

View File

@@ -0,0 +1,206 @@
package net.i2p.jetty;
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
import java.io.IOException;
import java.io.File;
import java.io.Writer;
import java.net.URL;
import java.util.Locale;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.security.Password;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.eclipse.jetty.xml.XmlParser;
import org.eclipse.jetty.xml.XmlParser.Attribute;
import org.eclipse.jetty.xml.XmlParser.Node;
import org.xml.sax.SAXException;
/**
* Parses a Jetty XML configuration file.
* Copied from Jetty XmlConfiguration.java, where the parser is private.
*
* @since 0.9.35
*/
public class JettyXmlConfigurationParser
{
private static XmlParser initParser()
{
XmlParser parser = new XmlParser();
URL config60 = Loader.getResource(XmlConfiguration.class, "org/eclipse/jetty/xml/configure_6_0.dtd");
URL config76 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_7_6.dtd");
URL config90 = Loader.getResource(XmlConfiguration.class,"org/eclipse/jetty/xml/configure_9_0.dtd");
parser.redirectEntity("configure.dtd",config90);
parser.redirectEntity("configure_1_0.dtd",config60);
parser.redirectEntity("configure_1_1.dtd",config60);
parser.redirectEntity("configure_1_2.dtd",config60);
parser.redirectEntity("configure_1_3.dtd",config60);
parser.redirectEntity("configure_6_0.dtd",config60);
parser.redirectEntity("configure_7_6.dtd",config76);
parser.redirectEntity("configure_9_0.dtd",config90);
parser.redirectEntity("http://jetty.mortbay.org/configure.dtd",config90);
parser.redirectEntity("http://jetty.eclipse.org/configure.dtd",config90);
parser.redirectEntity("http://www.eclipse.org/jetty/configure.dtd",config90);
parser.redirectEntity("-//Mort Bay Consulting//DTD Configure//EN",config90);
parser.redirectEntity("-//Jetty//Configure//EN",config90);
return parser;
}
/**
* Reads and parses the XML configuration file.
*
* @param f an XML configuration file
* @throws IOException if the configuration could not be read
* @throws SAXException if the configuration could not be parsed
*/
public static XmlParser.Node parse(File f) throws SAXException, IOException {
// we don't expect to need this very often,
// so just make a new parser every time
return initParser().parse(f);
}
/**
* Recursively go through the entire tree starting at node.
* Return the value for the first node with the name set,
* e.g. [Set name="name"]value[/Set]
* @param name case insensitive
*/
public static String getValue(Node node, String name) {
String nameLC = name.toLowerCase(Locale.US);
for (Object o : node) {
if (!(o instanceof Node))
continue;
Node n = (Node) o;
String tag = n.getTag();
if (tag != null && "set".equals(tag.toLowerCase(Locale.US))) {
String aname = n.getAttribute("name");
if (aname != null && aname.toLowerCase(Locale.US).equals(nameLC))
return n.toString(false);
} else {
String rv = getValue(n, name);
if (rv != null)
return rv;
}
}
return null;
}
/**
* Recursively go through the entire tree starting at node.
* Return the value for the first node with the name set,
* e.g. [Set name="name"]value[/Set]
* @param name case insensitive
* @return success
*/
public static boolean setValue(Node node, String name, String value) {
String nameLC = name.toLowerCase(Locale.US);
for (Object o : node) {
if (!(o instanceof Node))
continue;
Node n = (Node) o;
String tag = n.getTag();
if (tag != null && "set".equals(tag.toLowerCase(Locale.US))) {
String aname = n.getAttribute("name");
if (aname != null && aname.toLowerCase(Locale.US).equals(nameLC)) {
// Node doesn't support set() or remove() but it does have clear()
n.clear();
// work around bug in XmlParser.Node.add(int, Object)
// where it will AIOOBE when calling add(String) after clear() after add(String)
// because the _lastString field isn't reset to false
// so we need to add a non-String object and then clear again.
n.add(Integer.valueOf(0));
n.clear();
n.add(value);
return true;
}
} else {
boolean rv = setValue(n, name, value);
if (rv)
return rv;
}
}
return false;
}
/**
* Write out the XML.
* Adapted from Node.toString().
* That synchronized method caused classpath issues when called from the webapp.
* Also add newlines here for readability.
*/
public static void write(Node node, Writer out) throws IOException {
out.write('<');
String tag = node.getTag();
out.write(tag);
Attribute[] attrs = node.getAttributes();
if (attrs != null) {
for (int i = 0; i < attrs.length; i++) {
out.write(' ');
out.write(attrs[i].getName());
out.write("=\"");
out.write(attrs[i].getValue());
out.write('"');
}
}
int size = node.size();
if (size > 0) {
out.write(">");
for (int i = 0; i < size; i++) {
Object o = node.get(i);
if (o == null)
continue;
if (o instanceof Node) {
write((Node) o, out);
} else {
out.write(o.toString());
}
}
out.write("</");
out.write(tag);
out.write(">\n");
} else {
out.write("/>\n");
}
}
/**
* Obfuscate a password for storage in the XML
* @return a string starting with "OBF:"
*/
public static String obfuscate(String s) {
if (s.startsWith("OBF:"))
return s;
return Password.obfuscate(s);
}
/**
* De-Obfuscate a password from the XML
* @param s a string starting with "OBF:"
*/
public static String deobfuscate(String s) {
if (!s.startsWith("OBF:"))
return s;
return Password.deobfuscate(s);
}
}

View File

@@ -149,6 +149,15 @@ public class ErrorServlet extends HttpServlet {
out.println("</div></body></html>");
out.close();
}
/**
* Needed if the errored page was a POST
* @since 0.9.35
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
/**
* Override for specific cases.

View File

@@ -214,7 +214,7 @@ public class I2PDefaultServlet extends DefaultServlet
String encodedBase = hrefEncodeURI(base);
DateFormat dfmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.UK);
DateFormat dfmt = new SimpleDateFormat(FORMAT, Locale.UK);
TimeZone utc = TimeZone.getTimeZone("GMT");
dfmt.setTimeZone(utc);
for (int i=0 ; i< ls.length ; i++)

View File

@@ -396,7 +396,6 @@
<pathelement location="../../jetty/jettylib/tomcat-util.jar" />
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
<pathelement location="../../jetty/jettylib/commons-el.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
<pathelement location="${ant.home}/lib/ant.jar" />
@@ -435,7 +434,6 @@
<pathelement location="../../jetty/jettylib/tomcat-util.jar" />
<pathelement location="../../jetty/jettylib/tomcat-util-scan.jar" />
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
<pathelement location="../../jetty/jettylib/commons-el.jar" />
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
<pathelement location="../../jetty/jettylib/jetty-util.jar" />

View File

@@ -175,7 +175,7 @@ public class ConfigUpdateHandler extends FormHandler {
int proxyPort = proxyPort(_context);
if (shouldProxy && proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT &&
proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) &&
_context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0) {
!_context.portMapper().isRegistered(PortMapper.SVC_HTTP_PROXY)) {
addFormError(_t("HTTP client proxy tunnel must be running"));
return;
}

View File

@@ -172,7 +172,7 @@ public class PluginStarter implements Runnable {
int proxyPort = ConfigUpdateHandler.proxyPort(ctx);
if (proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT &&
proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) &&
ctx.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0) {
!ctx.portMapper().isRegistered(PortMapper.SVC_HTTP_PROXY)) {
mgr.notifyComplete(null, Messages.getString("Plugin update check failed", ctx) +
" - " +
Messages.getString("HTTP client proxy tunnel must be running", ctx));

View File

@@ -53,6 +53,8 @@ public class WebAppStarter {
* Prior to 0.9.28, was not guaranteed to throw on failure.
* Not for routerconsole.war, it's started in RouterConsoleRunner.
*
* As of 0.9.34, the appName will be registered with the PortMapper.
*
* @throws Exception just about anything, caller would be wise to catch Throwable
* @since public since 0.9.33, was package private
*/
@@ -165,7 +167,12 @@ public class WebAppStarter {
} catch (IllegalStateException ise) {}
}
/** @since public since 0.9.33; was package private */
/**
* As of 0.9.34, the appName will be registered with the PortMapper,
* and PortMapper.isRegistered() will be more efficient than this.
*
* @since public since 0.9.33; was package private
*/
public static boolean isWebAppRunning(String appName) {
ContextHandler wac = getWebApp(appName);
if (wac == null)

View File

@@ -22,7 +22,7 @@ public class CertHelper extends HelperBase {
private static final String CONSOLE = "console/console.local.crt";
private static final String I2PTUNNEL_DIR = "i2ptunnel";
private static final String SAM_DIR = "sam";
private static final String EEPSITE = "eepsite/etc/keystore.ks";
private static final String EEPSITE_DIR = "eepsite";
public String getSummary() {
File dir = new File(_context.getConfigDir(), DIR);
@@ -31,9 +31,9 @@ public class CertHelper extends HelperBase {
_out.write(_t("Local SSL Certificates"));
_out.write("</h3>\n");
// console
output("Console", new File(dir, CONSOLE));
output(_t("Router Console"), new File(dir, CONSOLE));
// I2CP
output("I2CP", new File(dir, I2CP));
output(_t("I2CP"), new File(dir, I2CP));
// i2ptunnel clients
File tunnelDir = new File(_context.getConfigDir(), I2PTUNNEL_DIR);
@@ -58,13 +58,28 @@ public class CertHelper extends HelperBase {
if (tunnels != null) {
for (int i = 0; i < tunnels.length; i++) {
File f = tunnels[i];
output("SAM", f);
output(_t("SAM"), f);
hasTunnels = true;
}
}
if (!hasTunnels)
output(_t("SAM"), null);
// Eepsite
tunnelDir = new File(dir, EEPSITE_DIR);
hasTunnels = false;
tunnels = tunnelDir.listFiles(new FileSuffixFilter(".crt"));
if (tunnels != null) {
for (int i = 0; i < tunnels.length; i++) {
File f = tunnels[i];
String name = f.getName();
output(_t("Website") + ' ' + name.substring(0, name.length() - 4), f);
hasTunnels = true;
}
}
if (!hasTunnels)
output(_t("Website"), null);
// Family
_out.write("<h3>");
_out.write(_t("Local Router Family Certificate"));
@@ -80,19 +95,6 @@ public class CertHelper extends HelperBase {
_out.write("</p>\n");
}
// Eepsite
_out.write("<h3>");
_out.write(_t("Website"));
_out.write("</h3>\n");
File ks = new File(_context.getConfigDir(), EEPSITE);
if (ks.exists()) {
// TODO
} else {
_out.write("<p>");
_out.write(_t("none"));
_out.write("</p>\n");
}
// anything else? plugins?
} catch (IOException ioe) {

View File

@@ -577,7 +577,7 @@ public class ConfigClientsHandler extends FormHandler {
boolean rv = !
(proxyPort == ConfigUpdateHandler.DEFAULT_PROXY_PORT_INT &&
proxyHost.equals(ConfigUpdateHandler.DEFAULT_PROXY_HOST) &&
_context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) < 0);
!_context.portMapper().isRegistered(PortMapper.SVC_HTTP_PROXY));
if (!rv)
addFormError(_t("HTTP client proxy tunnel must be running"));
return rv;

View File

@@ -208,13 +208,13 @@ public class HomeHelper extends HelperBase {
url = app.url;
// check for disabled webapps and other things
if (url.equals("/dns")) {
if (pm.getPort("susidns") <= 0)
if (!pm.isRegistered("susidns"))
continue;
} else if (url.equals("/webmail")) {
if (pm.getPort("susimail") <= 0)
if (!pm.isRegistered("susimail"))
continue;
} else if (url.equals("/torrents")) {
if (pm.getPort("i2psnark") <= 0)
if (!pm.isRegistered("i2psnark"))
continue;
} else if (url.equals("/configplugins")) {
if (!PluginStarter.pluginsEnabled(_context))

View File

@@ -290,7 +290,7 @@ class NetDbRenderer {
medianCount = rapCount / 2;
}
boolean linkSusi = WebAppStarter.isWebAppRunning("susidns");
boolean linkSusi = _context.portMapper().isRegistered("susidns");
long now = _context.clock().now();
buf.append("<div class=\"leasesets_container\">");
for (LeaseSet ls : leases) {

View File

@@ -214,7 +214,7 @@ class SummaryBarRenderer {
"<hr class=\"b\"><table id=\"sb_services\"><tr><td>");
PortMapper pm = _context.portMapper();
if (pm.getPort(PortMapper.SVC_SUSIMAIL) > 0) {
if (pm.isRegistered(PortMapper.SVC_SUSIMAIL)) {
buf.append("<a href=\"/webmail\" target=\"_top\" title=\"")
.append(_t("Anonymous webmail client"))
.append("\">")
@@ -222,7 +222,7 @@ class SummaryBarRenderer {
.append("</a>\n");
}
if (pm.getPort(PortMapper.SVC_I2PSNARK) > 0) {
if (pm.isRegistered(PortMapper.SVC_I2PSNARK)) {
buf.append("<a href=\"/torrents\" target=\"_top\" title=\"")
.append(_t("Built-in anonymous BitTorrent Client"))
.append("\">")
@@ -269,7 +269,7 @@ class SummaryBarRenderer {
"<table id=\"sb_internals\"><tr><td>\n");
PortMapper pm = _context.portMapper();
if (pm.getPort(PortMapper.SVC_SUSIDNS) > 0) {
if (pm.isRegistered(PortMapper.SVC_SUSIDNS)) {
buf.append("<a href=\"/dns\" target=\"_top\" title=\"")
.append(_t("Manage your I2P hosts file here (I2P domain name resolution)"))
.append("\">")
@@ -291,7 +291,7 @@ class SummaryBarRenderer {
.append(nbsp(_t("Help")))
.append("</a>\n");
if (pm.getPort(PortMapper.SVC_I2PTUNNEL) > 0) {
if (pm.isRegistered(PortMapper.SVC_I2PTUNNEL)) {
buf.append("<a href=\"/i2ptunnelmgr\" target=\"_top\" title=\"")
.append(_t("Local Tunnels"))
.append("\">")

View File

@@ -558,7 +558,7 @@ public class SummaryHelper extends HelperBase {
List<Destination> clients = new ArrayList<Destination>(_context.clientManager().listClients());
StringBuilder buf = new StringBuilder(512);
boolean link = WebAppStarter.isWebAppRunning("i2ptunnel");
boolean link = _context.portMapper().isRegistered("i2ptunnel");
buf.append("<h3>");
if (link) {
buf.append("<a href=\"/i2ptunnelmgr\" target=\"_top\" title=\"")
@@ -898,7 +898,7 @@ public class SummaryHelper extends HelperBase {
if ((avail || unsignedAvail || devSU3Avail) &&
!NewsHelper.isUpdateInProgress() &&
!_context.router().gracefulShutdownInProgress() &&
_context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) > 0 && // assume using proxy for now
_context.portMapper().isRegistered(PortMapper.SVC_HTTP_PROXY) && // assume using proxy for now
getAction() == null &&
getUpdateNonce() == null) {
if (needSpace)

View File

@@ -814,7 +814,7 @@ class SybilRenderer {
buf.append("<a title=\"View extended router info\" class=\"viewfullentry\" href=\"netdb?r=")
.append(hash.substring(0, 6)).append("\" >[").append(_t("Full entry")).append("]</a></th><th>");
}
if (_context.portMapper().getPort("imagegen") > 0)
if (_context.portMapper().isRegistered("imagegen"))
buf.append("<img src=\"/imagegen/id?s=32&amp;c=" + hash.replace("=", "%3d") + "\" height=\"32\" width=\"32\"> ");
buf.append("</th></tr>\n<tr><td class=\"sybilinfo_params\" colspan=\"3\"><div class=\"sybilinfo_container\">");
if (us != null) {

View File

@@ -28,7 +28,6 @@
<pathelement location="lib/jstl.jar" />
<pathelement location="lib/standard.jar" />
<pathelement location="${lib}/jasper-runtime.jar" />
<pathelement location="${lib}/commons-logging.jar" />
<pathelement location="${lib}/jetty-util.jar" />
<pathelement location="${ant.home}/lib/ant.jar" />
<pathelement location="../../../core/java/build/i2p.jar" />

View File

@@ -438,6 +438,6 @@ public class NamingServiceBean extends AddressbookBean
* @since 0.9.34
*/
public boolean haveImagegen() {
return _context.portMapper().getPort("imagegen") > 0;
return _context.portMapper().isRegistered("imagegen");
}
}

View File

@@ -144,7 +144,7 @@ public class SubscriptionsBean extends BaseBean
// config reload and fetch.
*******/
if (content != null && content.length() > 2 &&
_context.portMapper().getPort(PortMapper.SVC_HTTP_PROXY) > 0) {
_context.portMapper().isRegistered(PortMapper.SVC_HTTP_PROXY)) {
message = _t("Subscriptions saved, updating addressbook from subscription sources now.");
// + "<img height=\"1\" width=\"1\" alt=\"\" " +
// "src=\"/addressbook/?wakeup=1&nonce=" + nonce + "\">";

View File

@@ -628,7 +628,11 @@ public class WebMail extends HttpServlet
type.equals("application/x-tar") || type.equals("application/x-bzip2") ||
type.equals("application/pdf") || type.equals("application/x-bittorrent") ||
type.equals("application/pgp-encrypted") ||
type.equals("application/pgp-signature"))) {
type.equals("application/pgp-signature") ||
(type.equals("application/octet-stream") &&
((mailPart.filename != null && mailPart.filename.endsWith(".asc")) ||
(mailPart.name != null && mailPart.name.endsWith(".asc"))))
)) {
out.println( "<a href=\"" + myself + '?' + RAW_ATTACHMENT + '=' +
mailPart.getID() +
"&amp;" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\">" +

View File

@@ -588,7 +588,7 @@
<jar destfile="./build/launchi2p.jar">
<manifest>
<attribute name="Main-Class" value="net.i2p.router.RouterLaunch" />
<attribute name="Class-Path" value="lib/i2p.jar lib/router.jar lib/jbigi.jar lib/BOB.jar lib/sam.jar lib/mstreaming.jar lib/streaming.jar lib/routerconsole.jar lib/i2ptunnel.jar lib/org.mortbay.jetty.jar lib/javax.servlet.jar lib/jasper-runtime.jar lib/commons-logging.jar lib/commons-el.jar lib/wrapper.jar lib/systray.jar lib/desktopgui.jar lib/i2psnark.jar lib/jrobin.jar lib/jstl.jar lib/standard.jar lib/jetty-continuation.jar lib/jetty-deploy.jar lib/jetty-http.jar lib/jetty-i2p.jar lib/jetty-io.jar lib/jetty-rewrite-handler.jar lib/jetty-security.jar lib/jetty-servlet.jar lib/jetty-servlets.jar lib/jetty-start.jar lib/jetty-util.jar lib/jetty-webapp.jar lib/jetty-xml.jar" />
<attribute name="Class-Path" value="lib/i2p.jar lib/router.jar lib/jbigi.jar lib/BOB.jar lib/sam.jar lib/mstreaming.jar lib/streaming.jar lib/routerconsole.jar lib/i2ptunnel.jar lib/org.mortbay.jetty.jar lib/javax.servlet.jar lib/jasper-runtime.jar lib/commons-el.jar lib/wrapper.jar lib/systray.jar lib/desktopgui.jar lib/i2psnark.jar lib/jrobin.jar lib/jstl.jar lib/standard.jar lib/jetty-continuation.jar lib/jetty-deploy.jar lib/jetty-http.jar lib/jetty-i2p.jar lib/jetty-io.jar lib/jetty-rewrite-handler.jar lib/jetty-security.jar lib/jetty-servlet.jar lib/jetty-servlets.jar lib/jetty-start.jar lib/jetty-util.jar lib/jetty-webapp.jar lib/jetty-xml.jar" />
<attribute name="Built-By" value="${build.built-by}" />
<attribute name="Build-Date" value="${build.timestamp}" />
<attribute name="Base-Revision" value="${workspace.version}" />
@@ -2011,7 +2011,7 @@
<arg value="-output"/>
<arg value="i2p.fba"/>
<arg value="-auxclasspath"/>
<arg value="build/commons-el.jar:build/commons-logging.jar:build/jasper-runtime.jar:build/javax.servlet.jar:build/org.mortbay.jetty.jar:apps/jrobin/jrobin-1.5.9.1.jar:installer/lib/wrapper/all/wrapper.jar:apps/susidns/src/lib/standard.jar:apps/susidns/src/lib/jstl.jar:apps/jrobin/jrobin-1.5.9.1.jar"/>
<arg value="build/commons-el.jar:build/jasper-runtime.jar:build/javax.servlet.jar:build/org.mortbay.jetty.jar:apps/jrobin/jrobin-1.5.9.1.jar:installer/lib/wrapper/all/wrapper.jar:apps/susidns/src/lib/standard.jar:apps/susidns/src/lib/jstl.jar:apps/jrobin/jrobin-1.5.9.1.jar"/>
<arg value="-sourcepath"/>
<arg value="apps/BOB/src/:apps/addressbook/java/src/:apps/i2psnark/java/src/:apps/i2ptunnel/java/src/:apps/ministreaming/java/src/:apps/routerconsole/java/src/:apps/sam/java/src/:apps/streaming/java/src/:apps/susidns/src/java/src/:apps/susimail/src/src/:apps/systray/java/src/:core/java/src/:router/java/src/:installer/java/src"/>
<!-- start of the files to be analyzed -->

View File

@@ -1,3 +1,7 @@
2018-04-27 zzz
* Tunnels: Fix and consolidate allow-zero-hop logic,
prevent zero-hop client tunnels when no active peers
2018-04-24 meeh
* Mac OS X launcher is still WIP, but:
- Building the I2P.app bundle is mostly done
@@ -6,6 +10,10 @@
* Added new entries to mtn-ignore so we avoid any PEBCAK with commiting build directories
* Added an SBT AutoPlugin named IconHelper to generate valid ICNS images for Mac OS X
2018-04-23 zzz
* Clock: Fix early NPE via DoH
* EepGet: Handle HTTP response line with no status text
2018-04-23 meeh
* Added launchers for Browser Bundle and Mac OS X

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 6;
public final static long BUILD = 7;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -79,7 +79,7 @@ public class TunnelPoolSettings {
private static final int DEFAULT_OB_EXPL_LENGTH_VARIANCE = 0;
//private static final int DEFAULT_OB_EXPL_LENGTH_VARIANCE = isSlow ? 0 : 1;
public static final boolean DEFAULT_ALLOW_ZERO_HOP = true;
public static final boolean DEFAULT_ALLOW_ZERO_HOP = false;
public static final int DEFAULT_IP_RESTRICTION = 2; // class B (/16)
private static final int MIN_PRIORITY = -25;
private static final int MAX_PRIORITY = 25;
@@ -161,16 +161,29 @@ public class TunnelPoolSettings {
/**
* If there are no tunnels to build with, will this pool allow 0 hop tunnels?
*
* Always true for exploratory.
* Generally true for client, but should probably be ignored...
* use getLength() + getLengthVariance() &gt; 0 instead.
* Prior to 0.9.35, generally true for client.
* As of 0.9.35, generally false for client, but true if
* getLength() + Math.min(getLengthVariance(), 0) &lt;= 0,
* OR if getLengthOverride() == 0
* OR if setAllowZeroHop(true) was called or set in properties.
*/
public boolean getAllowZeroHop() { return _allowZeroHop; }
public boolean getAllowZeroHop() {
return _allowZeroHop ||
_length + Math.min(_lengthVariance, 0) <= 0 ||
_lengthOverride == 0;
}
/**
* If there are no tunnels to build with, will this pool allow 0 hop tunnels?
* No effect on exploratory (always true)
*
* @param ok if true, getAllowZeroHop() will always return true
* if false, getAllowZeroHop will return as documented.
* @deprecated unused
*/
@Deprecated
public void setAllowZeroHop(boolean ok) {
if (!_isExploratory)
_allowZeroHop = ok;

View File

@@ -66,7 +66,7 @@ class BuildExecutor implements Runnable {
_context.statManager().createRequiredRateStat("tunnel.buildClientReject", "Response time for rejection (ms)", "Tunnels", new long[] { 10*60*1000, 60*60*1000 });
_context.statManager().createRequiredRateStat("tunnel.buildRequestTime", "Time to build a tunnel request (ms)", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildConfigTime", "Time to build a tunnel request (ms)", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildRequestZeroHopTime", "How long it takes to build a zero hop tunnel", "Tunnels", new long[] { 60*1000, 10*60*1000 });
//_context.statManager().createRateStat("tunnel.buildRequestZeroHopTime", "How long it takes to build a zero hop tunnel", "Tunnels", new long[] { 60*1000, 10*60*1000 });
//_context.statManager().createRateStat("tunnel.pendingRemaining", "How many inbound requests are pending after a pass (period is how long the pass takes)?", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildFailFirstHop", "How often we fail to build a OB tunnel because we can't contact the first hop", "Tunnels", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("tunnel.buildReplySlow", "Build reply late, but not too late", "Tunnels", new long[] { 10*60*1000 });
@@ -535,11 +535,10 @@ class BuildExecutor implements Runnable {
boolean ok = BuildRequestor.request(_context, pool, cfg, this);
if (!ok)
return;
long buildTime = System.currentTimeMillis() - beforeBuild;
if (cfg.getLength() <= 1)
_context.statManager().addRateData("tunnel.buildRequestZeroHopTime", buildTime, 0);
else
if (cfg.getLength() > 1) {
long buildTime = System.currentTimeMillis() - beforeBuild;
_context.statManager().addRateData("tunnel.buildRequestTime", buildTime, 0);
}
long id = cfg.getReplyMessageId();
if (id > 0) {
synchronized (_recentBuildIds) {

View File

@@ -176,8 +176,7 @@ public class TunnelPool {
TunnelInfo selectTunnel() { return selectTunnel(true); }
private TunnelInfo selectTunnel(boolean allowRecurseOnFail) {
boolean avoidZeroHop = getSettings().getLength() > 0 &&
getSettings().getLength() + getSettings().getLengthVariance() > 0;
boolean avoidZeroHop = !_settings.getAllowZeroHop();
long period = curPeriod();
synchronized (_tunnels) {
@@ -243,7 +242,7 @@ public class TunnelPool {
}
}
if (_alive && _settings.getAllowZeroHop())
if (_alive && !avoidZeroHop)
buildFallback();
if (allowRecurseOnFail)
return selectTunnel(false);
@@ -264,8 +263,7 @@ public class TunnelPool {
* @since 0.8.10
*/
TunnelInfo selectTunnel(Hash closestTo) {
boolean avoidZeroHop = getSettings().getLength() > 0 &&
getSettings().getLength() + getSettings().getLengthVariance() > 0;
boolean avoidZeroHop = !_settings.getAllowZeroHop();
TunnelInfo rv = null;
synchronized (_tunnels) {
if (!_tunnels.isEmpty()) {
@@ -659,13 +657,6 @@ public class TunnelPool {
return false;
if (_settings.getAllowZeroHop()) {
if ( (_settings.getLength() + _settings.getLengthVariance() > 0) &&
(!_settings.isExploratory()) &&
(_context.profileOrganizer().countActivePeers() > 0) ) {
// if it is a client tunnel pool and our variance doesn't allow 0 hop, prefer failure to
// 0 hop operation (unless our router is offline)
return false;
}
if (_log.shouldLog(Log.INFO))
_log.info(toString() + ": building a fallback tunnel (usable: " + usable + " needed: " + quantity + ")");
@@ -847,7 +838,7 @@ public class TunnelPool {
}
int wanted = getAdjustedTotalQuantity();
boolean allowZeroHop = ((getSettings().getLength() + getSettings().getLengthVariance()) <= 0);
boolean allowZeroHop = _settings.getAllowZeroHop();
/**
* This algorithm builds based on the previous average length of time it takes