Files
i2p.i2p/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java

1267 lines
43 KiB
Java

package net.i2p.i2ptunnel.web;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2005 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.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.Outproxy;
import net.i2p.data.Certificate;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.PrivateKeyFile;
import net.i2p.data.SessionKey;
import net.i2p.i2ptunnel.I2PTunnelClientBase;
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
import net.i2p.i2ptunnel.I2PTunnelHTTPServer;
import net.i2p.i2ptunnel.I2PTunnelServer;
import net.i2p.i2ptunnel.SSLClientUtil;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.i2ptunnel.ui.TunnelConfig;
import net.i2p.util.Addresses;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
import net.i2p.util.SecureFile;
/**
* Simple accessor for exposing tunnel info, but also an ugly form handler
*
* Warning - This class is not part of the i2ptunnel API,
* it has been moved from the jar to the war.
* Usage by classes outside of i2ptunnel.war is deprecated.
*/
public class IndexBean {
protected final I2PAppContext _context;
protected final Log _log;
protected final TunnelControllerGroup _group;
private final String _fatalError;
private String _action;
private int _tunnel;
//private long _prevNonce;
//private long _prevNonce2;
private String _curNonce;
//private long _nextNonce;
private TunnelConfig _config;
private boolean _removeConfirmed;
private int _hashCashValue;
private int _certType;
private String _certSigner;
public static final int RUNNING = 1;
public static final int STARTING = 2;
public static final int NOT_RUNNING = 3;
public static final int STANDBY = 4;
//static final String PROP_NONCE = IndexBean.class.getName() + ".nonce";
//static final String PROP_NONCE_OLD = PROP_NONCE + '2';
/** 3 wasn't enough for some browsers. They are reloading the page for some reason - maybe HEAD? @since 0.8.1 */
private static final int MAX_NONCES = 8;
/** store nonces in a static FIFO instead of in System Properties @since 0.8.1 */
private static final List<String> _nonces = new ArrayList<String>(MAX_NONCES + 1);
public static final String PROP_THEME_NAME = "routerconsole.theme";
public static final String DEFAULT_THEME = "light";
public static final String PROP_CSS_DISABLED = "routerconsole.css.disabled";
public static final String PROP_JS_DISABLED = "routerconsole.javascript.disabled";
private static final String PROP_PW_ENABLE = "routerconsole.auth.enable";
private static final String OPT = TunnelController.PFX_OPTION;
public IndexBean() {
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(IndexBean.class);
TunnelControllerGroup tcg;
String error;
try {
tcg = TunnelControllerGroup.getInstance();
error = tcg == null ? _("Tunnels are not initialized yet, please reload in two minutes.")
: null;
} catch (IllegalArgumentException iae) {
tcg = null;
error = iae.toString();
}
_group = tcg;
_fatalError = error;
_tunnel = -1;
_curNonce = "-1";
addNonce();
_config = new TunnelConfig();
}
/**
* @since 0.9.4
*/
public boolean isInitialized() {
return _group != null;
}
public static String getNextNonce() {
synchronized (_nonces) {
return _nonces.get(0);
}
}
public void setNonce(String nonce) {
if ( (nonce == null) || (nonce.trim().length() <= 0) ) return;
_curNonce = nonce;
}
/** add a random nonce to the head of the queue @since 0.8.1 */
private void addNonce() {
String nextNonce = Long.toString(_context.random().nextLong());
synchronized (_nonces) {
_nonces.add(0, nextNonce);
int sz = _nonces.size();
if (sz > MAX_NONCES)
_nonces.remove(sz - 1);
}
}
/** do we know this nonce? @since 0.8.1 */
private static boolean haveNonce(String nonce) {
synchronized (_nonces) {
return _nonces.contains(nonce);
}
}
public void setAction(String action) {
if ( (action == null) || (action.trim().length() <= 0) ) return;
_action = action;
}
public void setTunnel(String tunnel) {
if ( (tunnel == null) || (tunnel.trim().length() <= 0) ) return;
try {
_tunnel = Integer.parseInt(tunnel);
} catch (NumberFormatException nfe) {
_tunnel = -1;
}
}
private String processAction() {
if ( (_action == null) || (_action.trim().length() <= 0) || ("Cancel".equals(_action)))
return "";
if (_group == null)
return "Error - tunnels are not initialized yet";
// If passwords are turned on, all is assumed good
if (!_context.getBooleanProperty(PROP_PW_ENABLE) &&
!haveNonce(_curNonce))
return _("Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit.")
+ ' ' +
_("If the problem persists, verify that you have cookies enabled in your browser.");
if ("Stop all".equals(_action))
return stopAll();
else if ("Start all".equals(_action))
return startAll();
else if ("Restart all".equals(_action))
return restartAll();
else if ("Reload configuration".equals(_action))
return reloadConfig();
else if ("stop".equals(_action))
return stop();
else if ("start".equals(_action))
return start();
else if ("Save changes".equals(_action) || // IE workaround:
(_action.toLowerCase(Locale.US).indexOf("s</span>ave") >= 0))
return saveChanges();
else if ("Delete this proxy".equals(_action) || // IE workaround:
(_action.toLowerCase(Locale.US).indexOf("d</span>elete") >= 0))
return deleteTunnel();
else if ("Estimate".equals(_action))
return PrivateKeyFile.estimateHashCashTime(_hashCashValue);
else if ("Modify".equals(_action))
return modifyDestination();
else if ("Generate".equals(_action))
return generateNewEncryptionKey();
else
return "Action " + _action + " unknown";
}
private String stopAll() {
List<String> msgs = _group.stopAllControllers();
return getMessages(msgs);
}
private String startAll() {
List<String> msgs = _group.startAllControllers();
return getMessages(msgs);
}
private String restartAll() {
List<String> msgs = _group.restartAllControllers();
return getMessages(msgs);
}
private String reloadConfig() {
_group.reloadControllers();
return _("Configuration reloaded for all tunnels");
}
private String start() {
if (_tunnel < 0) return "Invalid tunnel";
List<TunnelController> controllers = _group.getControllers();
if (_tunnel >= controllers.size()) return "Invalid tunnel";
TunnelController controller = controllers.get(_tunnel);
controller.startTunnelBackground();
// 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) + "...";
}
private String stop() {
if (_tunnel < 0) return "Invalid tunnel";
List<TunnelController> controllers = _group.getControllers();
if (_tunnel >= controllers.size()) return "Invalid tunnel";
TunnelController controller = controllers.get(_tunnel);
controller.stopTunnel();
// 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) + "...";
}
private String saveChanges() {
// Get current tunnel controller
TunnelController cur = getController(_tunnel);
Properties config = getConfig();
String ksMsg = null;
String type = config.getProperty(TunnelController.PROP_TYPE);
if (TunnelController.TYPE_STD_CLIENT.equals(type) || TunnelController.TYPE_IRC_CLIENT.equals(type)) {
//
// If we switch to SSL, create the keystore here, so we can store the new properties.
// Down in I2PTunnelClientBase it's very hard to save the config.
//
if (Boolean.parseBoolean(config.getProperty(OPT + I2PTunnelClientBase.PROP_USE_SSL))) {
try {
boolean created = SSLClientUtil.verifyKeyStore(config, OPT);
if (created) {
// config now contains new keystore props
ksMsg = "Created new self-signed certificate for tunnel " + getTunnelName(_tunnel);
}
} catch (IOException ioe) {
ksMsg = "Failed to create new self-signed certificate for tunnel " +
getTunnelName(_tunnel) + ", check logs: " + ioe;
}
}
}
if (cur == null) {
// creating new
cur = new TunnelController(config, "", true);
_group.addController(cur);
if (cur.getStartOnLoad())
cur.startTunnelBackground();
} else {
cur.setConfig(config, "");
}
// Only modify other shared tunnels
// if the current tunnel is shared, and of supported type
if (Boolean.parseBoolean(cur.getSharedClient()) && isClient(cur.getType())) {
// all clients use the same I2CP session, and as such, use the same I2CP options
List<TunnelController> controllers = _group.getControllers();
for (int i = 0; i < controllers.size(); i++) {
TunnelController c = controllers.get(i);
// Current tunnel modified by user, skip
if (c == cur) continue;
// Only modify this non-current tunnel
// if it belongs to a shared destination, and is of supported type
if (Boolean.parseBoolean(c.getSharedClient()) && isClient(c.getType())) {
Properties cOpt = c.getConfig("");
_config.updateTunnelQuantities(config);
cOpt.setProperty("option.inbound.nickname", TunnelConfig.SHARED_CLIENT_NICKNAME);
cOpt.setProperty("option.outbound.nickname", TunnelConfig.SHARED_CLIENT_NICKNAME);
c.setConfig(cOpt, "");
}
}
}
List<String> msgs = doSave();
if (ksMsg != null)
msgs.add(ksMsg);
// FIXME name will be HTML escaped twice
return getMessages(msgs);
}
private List<String> doSave() {
List<String> rv = _group.clearAllMessages();
try {
_group.saveConfig();
rv.add(0, _("Configuration changes saved"));
} catch (IOException ioe) {
_log.error("Failed to save config file", ioe);
rv.add(0, _("Failed to save configuration") + ": " + ioe.toString());
}
return rv;
}
/**
* Stop the tunnel, delete from config,
* rename the private key file if in the default directory
*/
private String deleteTunnel() {
if (!_removeConfirmed)
return "Please confirm removal";
TunnelController cur = getController(_tunnel);
if (cur == null)
return "Invalid tunnel number";
List<String> msgs = _group.removeController(cur);
msgs.addAll(doSave());
// Rename private key file if it was a default name in
// the default directory, so it doesn't get reused when a new
// tunnel is created.
// Use configured file name if available, not the one from the form.
String pk = cur.getPrivKeyFile();
if (pk == null)
pk = _config.getPrivKeyFile();
if (pk != null && pk.startsWith("i2ptunnel") && pk.endsWith("-privKeys.dat") &&
((!isClient(cur.getType())) || cur.getPersistentClientKey())) {
File pkf = new File(_context.getConfigDir(), pk);
if (pkf.exists()) {
String name = cur.getName();
if (name == null) {
name = cur.getDescription();
if (name == null) {
name = cur.getType();
if (name == null)
name = Long.toString(_context.clock().now());
}
}
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())
to = new File(backupDir, name);
else
to = new File(_context.getConfigDir(), name);
boolean success = FileUtil.rename(pkf, to);
if (success)
msgs.add("Private key file " + pkf.getAbsolutePath() +
" renamed to " + to.getAbsolutePath());
}
}
return getMessages(msgs);
}
/**
* Executes any action requested (start/stop/etc) and dump out the
* messages.
*
* @return HTML escaped
*/
public String getMessages() {
if (_group == null)
return _fatalError;
StringBuilder buf = new StringBuilder(512);
if (_action != null) {
try {
buf.append(processAction()).append('\n');
} catch (Exception e) {
_log.log(Log.CRIT, "Error processing " + _action, e);
buf.append("Error: ").append(e.toString()).append('\n');
}
}
getMessages(_group.clearAllMessages(), buf);
return DataHelper.escapeHTML(buf.toString());
}
////
// The remaining methods are simple bean props for the jsp to query
////
public String getTheme() {
String theme = _context.getProperty(PROP_THEME_NAME, DEFAULT_THEME);
return "/themes/console/" + theme + "/";
}
public boolean allowCSS() {
return !_context.getBooleanProperty(PROP_CSS_DISABLED);
}
public boolean allowJS() {
return !_context.getBooleanProperty(PROP_JS_DISABLED);
}
public int getTunnelCount() {
if (_group == null) return 0;
return _group.getControllers().size();
}
/**
* Is it a client or server in the UI and I2P side?
* Note that a streamr client is a UI and I2P client but a server on the localhost side.
* Note that a streamr server is a UI and I2P server but a client on the localhost side.
*/
public boolean isClient(int tunnelNum) {
TunnelController cur = getController(tunnelNum);
if (cur == null) return false;
return cur.isClient();
}
/**
* Is it a client or server in the UI and I2P side?
* Note that a streamr client is a UI and I2P client but a server on the localhost side.
* Note that a streamr server is a UI and I2P server but a client on the localhost side.
*/
public static boolean isClient(String type) {
return TunnelController.isClient(type);
}
public String getTunnelName(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null && tun.getName() != null)
return DataHelper.escapeHTML(tun.getName());
else
return _("New Tunnel");
}
/**
* No validation
*/
public String getClientPort(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null && tun.getListenPort() != null)
return tun.getListenPort();
else
return "";
}
/**
* Returns error message if blank or invalid
* @since 0.9.3
*/
public String getClientPort2(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null && tun.getListenPort() != null) {
String port = tun.getListenPort();
if (port.length() == 0)
return "<font color=\"red\">" + _("Port not set") + "</font>";
int iport = Addresses.getPort(port);
if (iport == 0)
return "<font color=\"red\">" + _("Invalid port") + ' ' + port + "</font>";
if (iport < 1024)
return "<font color=\"red\">" +
_("Warning - ports less than 1024 are not recommended") +
": " + port + "</font>";
// dup check, O(n**2)
List<TunnelController> controllers = _group.getControllers();
for (int i = 0; i < controllers.size(); i++) {
if (i == tunnel)
continue;
if (port.equals(controllers.get(i).getListenPort()))
return "<font color=\"red\">" +
_("Warning - duplicate port") +
": " + port + "</font>";
}
return port;
}
return "<font color=\"red\">" + _("Port not set") + "</font>";
}
public String getTunnelType(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null)
return getTypeName(tun.getType());
else
return "";
}
public String getTypeName(String internalType) {
if (TunnelController.TYPE_STD_CLIENT.equals(internalType)) return _("Standard client");
else if (TunnelController.TYPE_HTTP_CLIENT.equals(internalType)) return _("HTTP/HTTPS client");
else if (TunnelController.TYPE_IRC_CLIENT.equals(internalType)) return _("IRC client");
else if (TunnelController.TYPE_STD_SERVER.equals(internalType)) return _("Standard server");
else if (TunnelController.TYPE_HTTP_SERVER.equals(internalType)) return _("HTTP server");
else if (TunnelController.TYPE_SOCKS.equals(internalType)) return _("SOCKS 4/4a/5 proxy");
else if (TunnelController.TYPE_SOCKS_IRC.equals(internalType)) return _("SOCKS IRC proxy");
else if (TunnelController.TYPE_CONNECT.equals(internalType)) return _("CONNECT/SSL/HTTPS proxy");
else if (TunnelController.TYPE_IRC_SERVER.equals(internalType)) return _("IRC server");
else if (TunnelController.TYPE_STREAMR_CLIENT.equals(internalType)) return _("Streamr client");
else if (TunnelController.TYPE_STREAMR_SERVER.equals(internalType)) return _("Streamr server");
else if (TunnelController.TYPE_HTTP_BIDIR_SERVER.equals(internalType)) return _("HTTP bidir");
else return internalType;
}
public String getInternalType(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null)
return tun.getType();
else
return "";
}
public String getClientInterface(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null) {
if ("streamrclient".equals(tun.getType()))
return tun.getTargetHost();
else
return tun.getListenOnInterface();
} else
return "127.0.0.1";
}
public int getTunnelStatus(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun == null) return NOT_RUNNING;
if (tun.getIsRunning()) {
if (isClient(tunnel) && tun.getIsStandby())
return STANDBY;
else
return RUNNING;
} else if (tun.getIsStarting()) return STARTING;
else return NOT_RUNNING;
}
public String getTunnelDescription(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null && tun.getDescription() != null)
return DataHelper.escapeHTML(tun.getDescription());
else
return "";
}
public String getSharedClient(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null)
return tun.getSharedClient();
else
return "";
}
public String getClientDestination(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun == null) return "";
String rv;
if (TunnelController.TYPE_STD_CLIENT.equals(tun.getType()) ||
TunnelController.TYPE_IRC_CLIENT.equals(tun.getType()) ||
TunnelController.TYPE_STREAMR_CLIENT.equals(tun.getType()))
rv = tun.getTargetDestination();
else
rv = tun.getProxyList();
return rv != null ? rv : "";
}
/**
* Call this to see if it is ok to linkify getServerTarget()
* @since 0.8.3
*/
public boolean isServerTargetLinkValid(int tunnel) {
TunnelController tun = getController(tunnel);
return tun != null &&
TunnelController.TYPE_HTTP_SERVER.equals(tun.getType()) &&
tun.getTargetHost() != null &&
tun.getTargetPort() != null;
}
/**
* @return valid host:port only if isServerTargetLinkValid() is true
*/
public String getServerTarget(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null) {
String host;
if ("streamrserver".equals(tun.getType()))
host = tun.getListenOnInterface();
else
host = tun.getTargetHost();
String port = tun.getTargetPort();
if (host == null || host.length() == 0)
host = "<font color=\"red\">" + _("Host not set") + "</font>";
else if (Addresses.getIP(host) == null)
host = "<font color=\"red\">" + _("Invalid address") + ' ' + host + "</font>";
else if (host.indexOf(':') >= 0)
host = '[' + host + ']';
if (port == null || port.length() == 0)
port = "<font color=\"red\">" + _("Port not set") + "</font>";
else if (Addresses.getPort(port) == 0)
port = "<font color=\"red\">" + _("Invalid port") + ' ' + port + "</font>";
return host + ':' + port;
} else
return "";
}
/**
* Works even if tunnel is not running.
* @return Destination or null
* @since 0.9.17
*/
protected Destination getDestination(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null) {
Destination rv = tun.getDestination();
if (rv != null)
return rv;
// if not running, do this the hard way
File keyFile = tun.getPrivateKeyFile();
if (keyFile != null) {
PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
try {
rv = pkf.getDestination();
if (rv != null)
return rv;
} catch (Exception e) {}
}
}
return null;
}
/**
* Works even if tunnel is not running.
* @return Base64 or ""
*/
public String getDestinationBase64(int tunnel) {
Destination d = getDestination(tunnel);
if (d != null)
return d.toBase64();
return "";
}
/**
* Works even if tunnel is not running.
* @return "{52 chars}.b32.i2p" or ""
*/
public String getDestHashBase32(int tunnel) {
Destination d = getDestination(tunnel);
if (d != null)
return d.toBase32();
return "";
}
/**
* For index.jsp
* @return true if the plugin is enabled, installed, and running
* @since 0.9.11
*/
public boolean getIsUsingOutproxyPlugin(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null) {
if (TunnelController.TYPE_HTTP_CLIENT.equals(tun.getType())) {
Properties opts = tun.getClientOptionProps();
if (Boolean.parseBoolean(opts.getProperty(I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN, "true"))) {
ClientAppManager mgr = _context.clientAppManager();
if (mgr != null)
return mgr.getRegisteredApp(Outproxy.NAME) != null;
}
}
}
return false;
}
///
/// bean props for form submission
///
/**
* What type of tunnel (httpclient, ircclient, client, or server). This is
* required when adding a new tunnel.
*
*/
public void setType(String type) {
_config.setType(type);
}
String getType() { return _config.getType(); }
/** Short name of the tunnel */
public void setName(String name) {
_config.setName(name);
}
/** one line description */
public void setNofilter_description(String description) {
_config.setDescription(description);
}
/** I2CP host the router is on, ignored when in router context */
public void setClientHost(String host) {
_config.setClientHost(host);
}
/** I2CP port the router is on, ignored when in router context */
public void setClientport(String port) {
_config.setClientPort(port);
}
/** how many hops to use for inbound tunnels */
public void setTunnelDepth(String tunnelDepth) {
if (tunnelDepth != null) {
try {
_config.setTunnelDepth(Integer.parseInt(tunnelDepth.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** how many parallel inbound tunnels to use */
public void setTunnelQuantity(String tunnelQuantity) {
if (tunnelQuantity != null) {
try {
_config.setTunnelQuantity(Integer.parseInt(tunnelQuantity.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** how much randomisation to apply to the depth of tunnels */
public void setTunnelVariance(String tunnelVariance) {
if (tunnelVariance != null) {
try {
_config.setTunnelVariance(Integer.parseInt(tunnelVariance.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** how many tunnels to hold in reserve to guard against failures */
public void setTunnelBackupQuantity(String tunnelBackupQuantity) {
if (tunnelBackupQuantity != null) {
try {
_config.setTunnelBackupQuantity(Integer.parseInt(tunnelBackupQuantity.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** what I2P session overrides should be used */
public void setNofilter_customOptions(String customOptions) {
_config.setCustomOptions(customOptions);
}
/** what HTTP outproxies should be used (httpclient specific) */
public void setProxyList(String proxyList) {
_config.setProxyList(proxyList);
}
/** what port should this client/httpclient/ircclient listen on */
public void setPort(String port) {
if (port != null) {
try {
_config.setPort(Integer.parseInt(port.trim()));
} catch (NumberFormatException nfe) {}
}
}
/**
* what interface should this client/httpclient/ircclient listen on
*/
public void setReachableBy(String reachableBy) {
_config.setReachableBy(reachableBy);
}
/** What peer does this client tunnel point at */
public void setTargetDestination(String dest) {
_config.setTargetDestination(dest);
}
/** What host does this server tunnel point at */
public void setTargetHost(String host) {
_config.setTargetHost(host);
}
/** What port does this server tunnel point at */
public void setTargetPort(String port) {
if (port != null) {
try {
_config.setTargetPort(Integer.parseInt(port.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** What host does this http server tunnel spoof */
public void setSpoofedHost(String host) {
_config.setSpoofedHost(host);
}
/** What filename is this server tunnel's private keys stored in */
public void setPrivKeyFile(String file) {
_config.setPrivKeyFile(file);
}
/**
* If called with any value (and the form submitted with action=Remove),
* we really do want to stop and remove the tunnel.
*/
public void setRemoveConfirm(String moo) {
_removeConfirmed = true;
}
/**
* If called with any value, we want this tunnel to start whenever it is
* loaded (aka right now and whenever the router is started up)
*/
public void setStartOnLoad(String moo) {
_config.setStartOnLoad(true);
}
public void setShared(String moo) {
_config.setShared(true);
}
public void setShared(boolean val) {
_config.setShared(val);
}
public void setConnectDelay(String moo) {
_config.setConnectDelay(true);
}
public void setProfile(String profile) {
_config.setProfile(profile);
}
public void setReduce(String moo) {
_config.setReduce();
}
public void setClose(String moo) {
_config.setClose();
}
public void setEncrypt(String moo) {
_config.setEncrypt();
}
/** @since 0.8.9 */
public void setDCC(String moo) {
_config.setDCC();
}
/** @since 0.9.9 */
public void setUseSSL(String moo) {
_config.setUseSSL();
}
/** @since 0.9.9 */
public boolean isSSLEnabled(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null) {
Properties opts = tun.getClientOptionProps();
return Boolean.parseBoolean(opts.getProperty(I2PTunnelServer.PROP_USE_SSL));
}
return false;
}
/** @since 0.9.12 */
public void setRejectInproxy(String moo) {
_config.setRejectInproxy();
}
/** @since 0.9.12 */
public boolean isRejectInproxy(int tunnel) {
TunnelController tun = getController(tunnel);
if (tun != null) {
Properties opts = tun.getClientOptionProps();
return Boolean.parseBoolean(opts.getProperty(I2PTunnelHTTPServer.OPT_REJECT_INPROXY));
}
return false;
}
/** @since 0.9.13 */
public void setUniqueLocal(String moo) {
_config.setUniqueLocal();
}
protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
public void setAccessMode(String val) {
_config.setAccessMode(val);
}
public void setDelayOpen(String moo) {
_config.setDelayOpen();
}
public void setNewDest(String val) {
_config.setNewDest(val);
}
public void setReduceTime(String val) {
if (val != null) {
try {
_config.setReduceTime(Integer.parseInt(val.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setReduceCount(String val) {
if (val != null) {
try {
_config.setReduceCount(Integer.parseInt(val.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setEncryptKey(String val) {
_config.setEncryptKey(val);
}
public void setAccessList(String val) {
_config.setAccessList(val);
}
public void setJumpList(String val) {
_config.setJumpList(val);
}
public void setCloseTime(String val) {
if (val != null) {
try {
_config.setCloseTime(Integer.parseInt(val.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** @since 0.9.14 */
public void setAllowUserAgent(String moo) {
_config.setAllowUserAgent();
}
/** @since 0.9.14 */
public void setAllowReferer(String moo) {
_config.setAllowReferer();
}
/** @since 0.9.14 */
public void setAllowAccept(String moo) {
_config.setAllowAccept();
}
/** @since 0.9.14 */
public void setAllowInternalSSL(String moo) {
_config.setAllowInternalSSL();
}
/** @since 0.9.18 */
public void setMultihome(String moo) {
_config.setMultihome();
}
/** all proxy auth @since 0.8.2 */
public void setProxyAuth(String s) {
_config.setProxyAuth(s);
}
public void setProxyUsername(String s) {
_config.setProxyUsername(s);
}
public void setNofilter_proxyPassword(String s) {
_config.setProxyPassword(s);
}
public void setOutproxyAuth(String s) {
_config.setOutproxyAuth(s);
}
public void setOutproxyUsername(String s) {
_config.setOutproxyUsername(s);
}
public void setNofilter_outproxyPassword(String s) {
_config.setOutproxyPassword(s);
}
/** @since 0.9.11 */
public void setSslProxies(String s) {
_config.setSslProxies(s);
}
/** @since 0.9.11 */
public void setUseOutproxyPlugin(String moo) {
_config.setUseOutproxyPlugin();
}
public void setLimitMinute(String s) {
if (s != null) {
try {
_config.setLimitMinute(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setLimitHour(String s) {
if (s != null) {
try {
_config.setLimitHour(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setLimitDay(String s) {
if (s != null) {
try {
_config.setLimitDay(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setTotalMinute(String s) {
if (s != null) {
try {
_config.setTotalMinute(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setTotalHour(String s) {
if (s != null) {
try {
_config.setTotalHour(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setTotalDay(String s) {
if (s != null) {
try {
_config.setTotalDay(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setMaxStreams(String s) {
if (s != null) {
try {
_config.setMaxStreams(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
/**
* POST limits
* @since 0.9.9
*/
public void setPostMax(String s) {
if (s != null) {
try {
_config.setPostMax(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostTotalMax(String s) {
if (s != null) {
try {
_config.setPostTotalMax(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostCheckTime(String s) {
if (s != null) {
try {
_config.setPostCheckTime(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostBanTime(String s) {
if (s != null) {
try {
_config.setPostBanTime(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostTotalBanTime(String s) {
if (s != null) {
try {
_config.setPostTotalBanTime(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** params needed for hashcash and dest modification */
public void setEffort(String val) {
if (val != null) {
try {
_hashCashValue = Integer.parseInt(val.trim());
} catch (NumberFormatException nfe) {}
}
}
public void setCert(String val) {
if (val != null) {
try {
_certType = Integer.parseInt(val.trim());
} catch (NumberFormatException nfe) {}
}
}
public void setSigner(String val) {
_certSigner = val;
}
/** @since 0.9.12 */
public void setSigType(String val) {
if (val != null) {
_config.setSigType(val);
if (val.equals("0"))
_certType = 0;
else
_certType = 5;
}
// TODO: Call modifyDestination??
// Otherwise this only works on a new tunnel...
}
/**
* Random keys, hidden in forms
* @since 0.9.18
*/
public void setKey1(String s) {
_config.setInboundRandomKey(s);
}
public void setKey2(String s) {
_config.setOutboundRandomKey(s);
}
public void setKey3(String s) {
_config.setLeaseSetSigningPrivateKey(s);
}
public void setKey4(String s) {
_config.setLeaseSetPrivateKey(s);
}
/** Modify or create a destination */
private String modifyDestination() {
String privKeyFile = _config.getPrivKeyFile();
if (privKeyFile == null)
return "Private Key File not specified";
TunnelController tun = getController(_tunnel);
Properties config = getConfig();
if (tun == null) {
// creating new
tun = new TunnelController(config, "", true);
_group.addController(tun);
saveChanges();
} else if (tun.getIsRunning() || tun.getIsStarting()) {
return "Tunnel must be stopped before modifying destination";
}
File keyFile = new File(privKeyFile);
if (!keyFile.isAbsolute())
keyFile = new File(_context.getConfigDir(), privKeyFile);
PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
try {
pkf.createIfAbsent();
} catch (Exception e) {
return "Create private key file failed: " + e;
}
switch (_certType) {
case Certificate.CERTIFICATE_TYPE_NULL:
case Certificate.CERTIFICATE_TYPE_HIDDEN:
pkf.setCertType(_certType);
break;
case Certificate.CERTIFICATE_TYPE_HASHCASH:
pkf.setHashCashCert(_hashCashValue);
break;
case Certificate.CERTIFICATE_TYPE_SIGNED:
if (_certSigner == null || _certSigner.trim().length() <= 0)
return "No signing destination specified";
// find the signer's key file...
String signerPKF = null;
for (int i = 0; i < getTunnelCount(); i++) {
TunnelController c = getController(i);
if (_certSigner.equals(c.getConfig("").getProperty(TunnelController.PROP_NAME)) ||
_certSigner.equals(c.getConfig("").getProperty(TunnelController.PROP_SPOOFED_HOST))) {
signerPKF = c.getConfig("").getProperty(TunnelController.PROP_FILE);
break;
}
}
if (signerPKF == null || signerPKF.length() <= 0)
return "Signing destination " + _certSigner + " not found";
if (privKeyFile.equals(signerPKF))
return "Self-signed destinations not allowed";
Certificate c = pkf.setSignedCert(new PrivateKeyFile(signerPKF));
if (c == null)
return "Signing failed - does signer destination exist?";
break;
default:
return "Unknown certificate type";
}
Destination newdest;
try {
pkf.write();
newdest = pkf.getDestination();
} catch (Exception e) {
return "Modification failed: " + e;
}
return "Destination modified - " +
"New Base32 is " + newdest.toBase32() +
"New Destination is " + newdest.toBase64();
}
/** New key */
private String generateNewEncryptionKey() {
TunnelController tun = getController(_tunnel);
Properties config = getConfig();
if (tun == null) {
// creating new
tun = new TunnelController(config, "", true);
_group.addController(tun);
saveChanges();
} else if (tun.getIsRunning() || tun.getIsStarting()) {
return "Tunnel must be stopped before modifying leaseset encryption key";
}
byte[] data = new byte[SessionKey.KEYSIZE_BYTES];
_context.random().nextBytes(data);
SessionKey sk = new SessionKey(data);
setEncryptKey(sk.toBase64());
setEncrypt("");
saveChanges();
return "New Leaseset Encryption Key: " + sk.toBase64();
}
/**
* Based on all provided data, create a set of configuration parameters
* suitable for use in a TunnelController. This will replace (not add to)
* any existing parameters, so this should return a comprehensive mapping.
*
*/
private Properties getConfig() {
// This is easier than requiring TunnelConfig to talk to
// TunnelControllerGroup and TunnelController
_config.setDestination(getDestination(_tunnel));
return _config.getConfig();
}
///
///
///
protected TunnelController getController(int tunnel) {
if (tunnel < 0) return null;
if (_group == null) return null;
List<TunnelController> controllers = _group.getControllers();
if (controllers.size() > tunnel)
return controllers.get(tunnel);
else
return null;
}
private static String getMessages(List<String> msgs) {
StringBuilder buf = new StringBuilder(128);
getMessages(msgs, buf);
return buf.toString();
}
private static void getMessages(List<String> msgs, StringBuilder buf) {
if (msgs == null) return;
for (int i = 0; i < msgs.size(); i++) {
buf.append(msgs.get(i)).append("\n");
}
}
protected String _(String key) {
return Messages._(key, _context);
}
/** translate (ngettext)
* @since 0.9.7
*/
protected String ngettext(String s, String p, int n) {
return Messages.ngettext(s, p, n, _context);
}
}