Move TunnelController config creation logic into class that Android UI can use

This commit is contained in:
str4d
2015-03-10 20:05:45 +00:00
parent 419e27cfd1
commit 812c00f11e
3 changed files with 892 additions and 499 deletions

View File

@ -0,0 +1,715 @@
package net.i2p.i2ptunnel;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PClient;
import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.SigType;
import net.i2p.data.Base64;
import net.i2p.data.Destination;
import net.i2p.data.SimpleDataStructure;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.PasswordManager;
/**
* Helper class to generate a valid TunnelController configuration from provided
* settings.
*
* @since 0.9.19 logic moved from IndexBean
*/
public class TunnelConfig {
public static final String SHARED_CLIENT_NICKNAME = "shared clients";
private static final String OPT = TunnelController.PFX_OPTION;
protected final I2PAppContext _context;
private String _type;
private String _name;
private String _description;
private String _i2cpHost;
private String _i2cpPort;
private int _tunnelDepth = -1;
private int _tunnelQuantity = -1;
private int _tunnelVariance = -1;
private int _tunnelBackupQuantity = -1;
private boolean _connectDelay;
private String _customOptions;
private String _proxyList;
private int _port = -1;
private String _reachableBy;
private String _targetDestination;
private String _targetHost;
private int _targetPort = -1;
private String _spoofedHost;
private String _privKeyFile;
private String _profile;
private boolean _startOnLoad;
private boolean _sharedClient;
private final Set<String> _booleanOptions;
private final Map<String, String> _otherOptions;
private String _newProxyUser;
private String _newProxyPW;
private Destination _dest;
public TunnelConfig() {
_context = I2PAppContext.getGlobalContext();
_booleanOptions = new ConcurrentHashSet<String>(4);
_otherOptions = new ConcurrentHashMap<String, String>(4);
}
/**
* What type of tunnel (httpclient, ircclient, client, or server). This is
* required when adding a new tunnel.
*
*/
public void setType(String type) {
_type = (type != null ? type.trim() : null);
}
public String getType() {
return _type;
}
/** Short name of the tunnel */
public void setName(String name) {
_name = (name != null ? name.trim() : null);
}
/** one line description */
public void setDescription(String description) {
// '#' will blow up DataHelper.storeProps()
_description = (description != null ? description.replace('#', ' ').trim() : null);
}
/** I2CP host the router is on, ignored when in router context */
public void setClientHost(String host) {
_i2cpHost = (host != null ? host.trim() : null);
}
/** I2CP port the router is on, ignored when in router context */
public void setClientPort(String port) {
_i2cpPort = (port != null ? port.trim() : null);
}
/** how many hops to use for inbound tunnels */
public void setTunnelDepth(int tunnelDepth) {
_tunnelDepth = tunnelDepth;
}
/** how many parallel inbound tunnels to use */
public void setTunnelQuantity(int tunnelQuantity) {
_tunnelQuantity = tunnelQuantity;
}
/** how much randomisation to apply to the depth of tunnels */
public void setTunnelVariance(int tunnelVariance) {
_tunnelVariance = tunnelVariance;
}
/** how many tunnels to hold in reserve to guard against failures */
public void setTunnelBackupQuantity(int tunnelBackupQuantity) {
_tunnelBackupQuantity = tunnelBackupQuantity;
}
/** what I2P session overrides should be used */
public void setCustomOptions(String customOptions) {
_customOptions = (customOptions != null ? customOptions.trim() : null);
}
/** what HTTP outproxies should be used (httpclient specific) */
public void setProxyList(String proxyList) {
_proxyList = (proxyList != null ? proxyList.trim() : null);
}
/** what port should this client/httpclient/ircclient listen on */
public void setPort(int port) {
_port = port;
}
/**
* what interface should this client/httpclient/ircclient listen on
*/
public void setReachableBy(String reachableBy) {
_reachableBy = (reachableBy != null ? reachableBy.trim() : null);
}
/** What peer does this client tunnel point at */
public void setTargetDestination(String dest) {
_targetDestination = (dest != null ? dest.trim() : null);
}
/** What host does this server tunnel point at */
public void setTargetHost(String host) {
_targetHost = (host != null ? host.trim() : null);
}
/** What port does this server tunnel point at */
public void setTargetPort(int port) {
_targetPort = port;
}
/** What host does this http server tunnel spoof */
public void setSpoofedHost(String host) {
_spoofedHost = (host != null ? host.trim() : null);
}
/** What filename is this server tunnel's private keys stored in */
public void setPrivKeyFile(String file) {
_privKeyFile = (file != null ? file.trim() : null);
}
public String getPrivKeyFile() {
return _privKeyFile;
}
/**
* 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(boolean val) {
_startOnLoad = val;
}
public void setShared(boolean val) {
_sharedClient = val;
}
public void setConnectDelay(boolean val) {
_connectDelay = val;
}
public void setProfile(String profile) {
_profile = profile;
}
public void setReduce() {
_booleanOptions.add("i2cp.reduceOnIdle");
}
public void setClose() {
_booleanOptions.add("i2cp.closeOnIdle");
}
public void setEncrypt() {
_booleanOptions.add("i2cp.encryptLeaseSet");
}
public void setDCC() {
_booleanOptions.add(I2PTunnelIRCClient.PROP_DCC);
}
public void setUseSSL() {
_booleanOptions.add(I2PTunnelServer.PROP_USE_SSL);
}
public void setRejectInproxy() {
_booleanOptions.add(I2PTunnelHTTPServer.OPT_REJECT_INPROXY);
}
public void setUniqueLocal() {
_booleanOptions.add(I2PTunnelServer.PROP_UNIQUE_LOCAL);
}
protected static final String PROP_ENABLE_ACCESS_LIST = "i2cp.enableAccessList";
protected static final String PROP_ENABLE_BLACKLIST = "i2cp.enableBlackList";
public void setAccessMode(String val) {
if ("1".equals(val))
_booleanOptions.add(PROP_ENABLE_ACCESS_LIST);
else if ("2".equals(val))
_booleanOptions.add(PROP_ENABLE_BLACKLIST);
}
public void setDelayOpen() {
_booleanOptions.add("i2cp.delayOpen");
}
public void setNewDest(String val) {
if ("1".equals(val))
_booleanOptions.add("i2cp.newDestOnResume");
else if ("2".equals(val))
_booleanOptions.add("persistentClientKey");
}
public void setReduceTime(int val) {
_otherOptions.put("i2cp.reduceIdleTime", Integer.toString(val * 60*1000));
}
public void setReduceCount(int val) {
_otherOptions.put("i2cp.reduceQuantity", Integer.toString(val));
}
public void setEncryptKey(String val) {
if (val != null)
_otherOptions.put("i2cp.leaseSetKey", val.trim());
}
public void setAccessList(String val) {
if (val != null)
_otherOptions.put("i2cp.accessList", val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
}
public void setJumpList(String val) {
if (val != null)
_otherOptions.put(I2PTunnelHTTPClient.PROP_JUMP_SERVERS, val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
}
public void setCloseTime(int val) {
_otherOptions.put("i2cp.closeIdleTime", Integer.toString(val * 60*1000));
}
public void setAllowUserAgent() {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_USER_AGENT);
}
public void setAllowReferer() {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_REFERER);
}
public void setAllowAccept() {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_ACCEPT);
}
public void setAllowInternalSSL() {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_INTERNAL_SSL);
}
public void setMultihome() {
_booleanOptions.add("shouldBundleReplyInfo");
}
/** all proxy auth */
public void setProxyAuth(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
}
public void setProxyUsername(String s) {
if (s != null)
_newProxyUser = s.trim();
}
public void setProxyPassword(String s) {
if (s != null)
_newProxyPW = s.trim();
}
public void setOutproxyAuth(String s) {
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
}
public void setOutproxyUsername(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER, s.trim());
}
public void setOutproxyPassword(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW, s.trim());
}
public void setSslProxies(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClient.PROP_SSL_OUTPROXIES, s.trim().replace(" ", ","));
}
public void setUseOutproxyPlugin() {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN);
}
/**
* all of these are @since 0.8.3 (moved from IndexBean)
*/
public static final String PROP_MAX_CONNS_MIN = "i2p.streaming.maxConnsPerMinute";
public static final String PROP_MAX_CONNS_HOUR = "i2p.streaming.maxConnsPerHour";
public static final String PROP_MAX_CONNS_DAY = "i2p.streaming.maxConnsPerDay";
public static final String PROP_MAX_TOTAL_CONNS_MIN = "i2p.streaming.maxTotalConnsPerMinute";
public static final String PROP_MAX_TOTAL_CONNS_HOUR = "i2p.streaming.maxTotalConnsPerHour";
public static final String PROP_MAX_TOTAL_CONNS_DAY = "i2p.streaming.maxTotalConnsPerDay";
public static final String PROP_MAX_STREAMS = "i2p.streaming.maxConcurrentStreams";
public void setLimitMinute(int val) {
_otherOptions.put(PROP_MAX_CONNS_MIN, Integer.toString(val));
}
public void setLimitHour(int val) {
_otherOptions.put(PROP_MAX_CONNS_HOUR, Integer.toString(val));
}
public void setLimitDay(int val) {
_otherOptions.put(PROP_MAX_CONNS_DAY, Integer.toString(val));
}
public void setTotalMinute(int val) {
_otherOptions.put(PROP_MAX_TOTAL_CONNS_MIN, Integer.toString(val));
}
public void setTotalHour(int val) {
_otherOptions.put(PROP_MAX_TOTAL_CONNS_HOUR, Integer.toString(val));
}
public void setTotalDay(int val) {
_otherOptions.put(PROP_MAX_TOTAL_CONNS_DAY, Integer.toString(val));
}
public void setMaxStreams(int val) {
_otherOptions.put(PROP_MAX_STREAMS, Integer.toString(val));
}
/**
* POST limits
*/
public void setPostMax(int val) {
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_MAX, Integer.toString(val));
}
public void setPostTotalMax(int val) {
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_TOTAL_MAX, Integer.toString(val));
}
public void setPostCheckTime(int val) {
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_WINDOW, Integer.toString(val * 60));
}
public void setPostBanTime(int val) {
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_BAN_TIME, Integer.toString(val * 60));
}
public void setPostTotalBanTime(int val) {
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_TOTAL_BAN_TIME, Integer.toString(val * 60));
}
public void setSigType(String val) {
if (val != null)
_otherOptions.put(I2PClient.PROP_SIGTYPE, val);
}
/**
* Random keys
*/
public void setInboundRandomKey(String s) {
if (s != null)
_otherOptions.put("inbound.randomKey", s.trim());
}
public void setOutboundRandomKey(String s) {
if (s != null)
_otherOptions.put("outbound.randomKey", s.trim());
}
public void setLeaseSetSigningPrivateKey(String s) {
if (s != null)
_otherOptions.put("i2cp.leaseSetSigningPrivateKey", s.trim());
}
public void setLeaseSetPrivateKey(String s) {
if (s != null)
_otherOptions.put("i2cp.leaseSetPrivateKey", s.trim());
}
/**
* This is easier than requiring TunnelConfig to talk to
* TunnelControllerGroup and TunnelController.
*
* @param dest the current Destination for this tunnel.
*/
public void setDestination(Destination dest) {
_dest = dest;
}
/**
* 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.
*
*/
public Properties getConfig() {
Properties config = new Properties();
updateConfigGeneric(config);
if ((TunnelController.isClient(_type) && !TunnelController.TYPE_STREAMR_CLIENT.equals(_type)) ||
TunnelController.TYPE_STREAMR_SERVER.equals(_type)) {
// streamrserver uses interface
if (_reachableBy != null)
config.setProperty(TunnelController.PROP_INTFC, _reachableBy);
else
config.setProperty(TunnelController.PROP_INTFC, "");
} else {
// streamrclient uses targetHost
if (_targetHost != null)
config.setProperty(TunnelController.PROP_TARGET_HOST, _targetHost);
}
if (TunnelController.isClient(_type)) {
// generic client stuff
if (_port >= 0)
config.setProperty(TunnelController.PROP_LISTEN_PORT, Integer.toString(_port));
config.setProperty(TunnelController.PROP_SHARED, _sharedClient + "");
for (String p : _booleanClientOpts)
config.setProperty(OPT + p, "" + _booleanOptions.contains(p));
for (String p : _otherClientOpts) {
if (_otherOptions.containsKey(p))
config.setProperty(OPT + p, _otherOptions.get(p));
}
} else {
// generic server stuff
if (_targetPort >= 0)
config.setProperty(TunnelController.PROP_TARGET_PORT, Integer.toString(_targetPort));
for (String p : _booleanServerOpts)
config.setProperty(OPT + p, "" + _booleanOptions.contains(p));
for (String p : _otherServerOpts) {
if (_otherOptions.containsKey(p))
config.setProperty(OPT + p, _otherOptions.get(p));
}
}
// generic proxy stuff
if (TunnelController.TYPE_HTTP_CLIENT.equals(_type) || TunnelController.TYPE_CONNECT.equals(_type) ||
TunnelController.TYPE_SOCKS.equals(_type) ||TunnelController.TYPE_SOCKS_IRC.equals(_type)) {
for (String p : _booleanProxyOpts)
config.setProperty(OPT + p, "" + _booleanOptions.contains(p));
if (_proxyList != null)
config.setProperty(TunnelController.PROP_PROXIES, _proxyList);
}
// Proxy auth including migration to MD5
if (TunnelController.TYPE_HTTP_CLIENT.equals(_type) || TunnelController.TYPE_CONNECT.equals(_type)) {
// Migrate even if auth is disabled
// go get the old from custom options that updateConfigGeneric() put in there
String puser = OPT + I2PTunnelHTTPClientBase.PROP_USER;
String user = config.getProperty(puser);
String ppw = OPT + I2PTunnelHTTPClientBase.PROP_PW;
String pw = config.getProperty(ppw);
if (user != null && pw != null && user.length() > 0 && pw.length() > 0) {
String pmd5 = OPT + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
user + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
if (config.getProperty(pmd5) == null) {
// not in there, migrate
String realm = _type.equals(TunnelController.TYPE_HTTP_CLIENT) ? I2PTunnelHTTPClient.AUTH_REALM
: I2PTunnelConnectClient.AUTH_REALM;
String hex = PasswordManager.md5Hex(realm, user, pw);
if (hex != null) {
config.setProperty(pmd5, hex);
config.remove(puser);
config.remove(ppw);
}
}
}
// New user/password
String auth = _otherOptions.get(I2PTunnelHTTPClientBase.PROP_AUTH);
if (auth != null && !auth.equals("false")) {
if (_newProxyUser != null && _newProxyPW != null &&
_newProxyUser.length() > 0 && _newProxyPW.length() > 0) {
String pmd5 = OPT + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
_newProxyUser + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
String realm = _type.equals(TunnelController.TYPE_HTTP_CLIENT) ? I2PTunnelHTTPClient.AUTH_REALM
: I2PTunnelConnectClient.AUTH_REALM;
String hex = PasswordManager.md5Hex(realm, _newProxyUser, _newProxyPW);
if (hex != null)
config.setProperty(pmd5, hex);
}
}
}
if (TunnelController.TYPE_IRC_CLIENT.equals(_type) ||
TunnelController.TYPE_STD_CLIENT.equals(_type) ||
TunnelController.TYPE_STREAMR_CLIENT.equals(_type)) {
if (_targetDestination != null)
config.setProperty(TunnelController.PROP_DEST, _targetDestination);
} else if (TunnelController.TYPE_HTTP_SERVER.equals(_type) ||
TunnelController.TYPE_HTTP_BIDIR_SERVER.equals(_type)) {
if (_spoofedHost != null)
config.setProperty(TunnelController.PROP_SPOOFED_HOST, _spoofedHost);
for (String p : _httpServerOpts)
if (_otherOptions.containsKey(p))
config.setProperty(OPT + p, _otherOptions.get(p));
}
if (TunnelController.TYPE_HTTP_BIDIR_SERVER.equals(_type)) {
if (_port >= 0)
config.setProperty(TunnelController.PROP_LISTEN_PORT, Integer.toString(_port));
if (_reachableBy != null)
config.setProperty(TunnelController.PROP_INTFC, _reachableBy);
else if (_targetHost != null)
config.setProperty(TunnelController.PROP_INTFC, _targetHost);
else
config.setProperty(TunnelController.PROP_INTFC, "");
}
if (TunnelController.TYPE_IRC_CLIENT.equals(_type)) {
boolean dcc = _booleanOptions.contains(I2PTunnelIRCClient.PROP_DCC);
config.setProperty(OPT + I2PTunnelIRCClient.PROP_DCC,
"" + dcc);
// add some sane server options since they aren't in the GUI (yet)
if (dcc) {
config.setProperty(OPT + PROP_MAX_CONNS_MIN, "3");
config.setProperty(OPT + PROP_MAX_CONNS_HOUR, "10");
config.setProperty(OPT + PROP_MAX_TOTAL_CONNS_MIN, "5");
config.setProperty(OPT + PROP_MAX_TOTAL_CONNS_HOUR, "25");
}
}
if (!TunnelController.isClient(_type) || _booleanOptions.contains("persistentClientKey")) {
// As of 0.9.17, add a persistent random key if not present
String p = OPT + "inbound.randomKey";
if (!config.containsKey(p)) {
byte[] rk = new byte[32];
_context.random().nextBytes(rk);
config.setProperty(p, Base64.encode(rk));
p = OPT + "outbound.randomKey";
_context.random().nextBytes(rk);
config.setProperty(p, Base64.encode(rk));
}
// As of 0.9.18, add persistent leaseset keys if not present
// but only if we know the sigtype
p = OPT + "i2cp.leaseSetSigningPrivateKey";
if (_dest != null && !config.containsKey(p)) {
try {
SigType type = _dest.getSigType();
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
config.setProperty(p, type.name() + ':' + keys[1].toBase64());
p = OPT + "i2cp.leaseSetPrivateKey";
keys = KeyGenerator.getInstance().generatePKIKeys();
config.setProperty(p, "ELGAMAL_2048:" + keys[1].toBase64());
} catch (GeneralSecurityException gse) {
// so much for that
}
}
}
return config;
}
private static final String _noShowOpts[] = {
"inbound.length", "outbound.length", "inbound.lengthVariance", "outbound.lengthVariance",
"inbound.backupQuantity", "outbound.backupQuantity", "inbound.quantity", "outbound.quantity",
"inbound.nickname", "outbound.nickname", "i2p.streaming.connectDelay", "i2p.streaming.maxWindowSize",
I2PTunnelIRCClient.PROP_DCC
};
private static final String _booleanClientOpts[] = {
"i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen",
I2PTunnelClientBase.PROP_USE_SSL,
};
private static final String _booleanProxyOpts[] = {
I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH,
I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN,
I2PTunnelHTTPClient.PROP_USER_AGENT,
I2PTunnelHTTPClient.PROP_REFERER,
I2PTunnelHTTPClient.PROP_ACCEPT,
I2PTunnelHTTPClient.PROP_INTERNAL_SSL
};
private static final String _booleanServerOpts[] = {
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST,
I2PTunnelServer.PROP_USE_SSL,
I2PTunnelHTTPServer.OPT_REJECT_INPROXY,
I2PTunnelServer.PROP_UNIQUE_LOCAL,
"shouldBundleReplyInfo"
};
private static final String _otherClientOpts[] = {
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
"outproxyUsername", "outproxyPassword",
I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
I2PTunnelHTTPClientBase.PROP_AUTH,
I2PClient.PROP_SIGTYPE,
I2PTunnelHTTPClient.PROP_SSL_OUTPROXIES,
// following are mostly server but could also be persistent client
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey"
};
private static final String _otherServerOpts[] = {
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
PROP_MAX_STREAMS, I2PClient.PROP_SIGTYPE,
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey"
};
private static final String _httpServerOpts[] = {
I2PTunnelHTTPServer.OPT_POST_WINDOW,
I2PTunnelHTTPServer.OPT_POST_BAN_TIME,
I2PTunnelHTTPServer.OPT_POST_TOTAL_BAN_TIME,
I2PTunnelHTTPServer.OPT_POST_MAX,
I2PTunnelHTTPServer.OPT_POST_TOTAL_MAX
};
/**
* do NOT add these to noShoOpts, we must leave them in for HTTPClient and ConnectCLient
* so they will get migrated to MD5
* TODO migrate socks to MD5
*/
private static final String _otherProxyOpts[] = {
"proxyUsername", "proxyPassword"
};
public static final Set<String> _noShowSet = new HashSet<String>(128);
public static final Set<String> _nonProxyNoShowSet = new HashSet<String>(4);
static {
_noShowSet.addAll(Arrays.asList(_noShowOpts));
_noShowSet.addAll(Arrays.asList(_booleanClientOpts));
_noShowSet.addAll(Arrays.asList(_booleanProxyOpts));
_noShowSet.addAll(Arrays.asList(_booleanServerOpts));
_noShowSet.addAll(Arrays.asList(_otherClientOpts));
_noShowSet.addAll(Arrays.asList(_otherServerOpts));
_noShowSet.addAll(Arrays.asList(_httpServerOpts));
_nonProxyNoShowSet.addAll(Arrays.asList(_otherProxyOpts));
}
private void updateConfigGeneric(Properties config) {
config.setProperty(TunnelController.PROP_TYPE, _type);
if (_name != null)
config.setProperty(TunnelController.PROP_NAME, _name);
if (_description != null)
config.setProperty(TunnelController.PROP_DESCR, _description);
if (!_context.isRouterContext()) {
if (_i2cpHost != null)
config.setProperty(TunnelController.PROP_I2CP_HOST, _i2cpHost);
if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
config.setProperty(TunnelController.PROP_I2CP_PORT, _i2cpPort);
} else {
config.setProperty(TunnelController.PROP_I2CP_PORT, "7654");
}
}
if (_privKeyFile != null)
config.setProperty(TunnelController.PROP_FILE, _privKeyFile);
if (_customOptions != null) {
StringTokenizer tok = new StringTokenizer(_customOptions);
while (tok.hasMoreTokens()) {
String pair = tok.nextToken();
int eq = pair.indexOf('=');
if ( (eq <= 0) || (eq >= pair.length()) )
continue;
String key = pair.substring(0, eq);
if (_noShowSet.contains(key))
continue;
// leave in for HTTP and Connect so it can get migrated to MD5
// hide for SOCKS until migrated to MD5
if ((!TunnelController.TYPE_HTTP_CLIENT.equals(_type)) &&
(!TunnelController.TYPE_CONNECT.equals(_type)) &&
_nonProxyNoShowSet.contains(key))
continue;
String val = pair.substring(eq+1);
config.setProperty(OPT + key, val);
}
}
config.setProperty(TunnelController.PROP_START, _startOnLoad + "");
updateTunnelQuantities(config);
if (_connectDelay)
config.setProperty("option.i2p.streaming.connectDelay", "1000");
else
config.setProperty("option.i2p.streaming.connectDelay", "0");
if (TunnelController.isClient(_type) && _sharedClient) {
config.setProperty("option.inbound.nickname", SHARED_CLIENT_NICKNAME);
config.setProperty("option.outbound.nickname", SHARED_CLIENT_NICKNAME);
} else if (_name != null) {
config.setProperty("option.inbound.nickname", _name);
config.setProperty("option.outbound.nickname", _name);
}
if ("interactive".equals(_profile))
// This was 1 which doesn't make much sense
// The real way to make it interactive is to make the streaming lib
// MessageInputStream flush faster but there's no option for that yet,
// Setting it to 16 instead of the default but not sure what good that is either.
config.setProperty("option.i2p.streaming.maxWindowSize", "16");
else
config.remove("option.i2p.streaming.maxWindowSize");
}
/**
* Update tunnel quantities for the provided config from this TunnelConfig.
*
* @param config the config to update.
*/
public void updateTunnelQuantities(Properties config) {
if (_tunnelQuantity >= 0) {
config.setProperty("option.inbound.quantity", Integer.toString(_tunnelQuantity));
config.setProperty("option.outbound.quantity", Integer.toString(_tunnelQuantity));
}
if (_tunnelDepth >= 0) {
config.setProperty("option.inbound.length", Integer.toString(_tunnelDepth));
config.setProperty("option.outbound.length", Integer.toString(_tunnelDepth));
}
if (_tunnelVariance >= 0) {
config.setProperty("option.inbound.lengthVariance", Integer.toString(_tunnelVariance));
config.setProperty("option.outbound.lengthVariance", Integer.toString(_tunnelVariance));
}
if (_tunnelBackupQuantity >= 0) {
config.setProperty("option.inbound.backupQuantity", Integer.toString(_tunnelBackupQuantity));
config.setProperty("option.outbound.backupQuantity", Integer.toString(_tunnelBackupQuantity));
}
}
}

View File

@ -27,6 +27,7 @@ import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
import net.i2p.i2ptunnel.I2PTunnelHTTPServer;
import net.i2p.i2ptunnel.I2PTunnelIRCClient;
import net.i2p.i2ptunnel.I2PTunnelServer;
import net.i2p.i2ptunnel.TunnelConfig;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.util.Addresses;
@ -359,31 +360,31 @@ public class EditBean extends IndexBean {
/** all of these are @since 0.8.3 */
public int getLimitMinute(int tunnel) {
return getProperty(tunnel, PROP_MAX_CONNS_MIN, 0);
return getProperty(tunnel, TunnelConfig.PROP_MAX_CONNS_MIN, 0);
}
public int getLimitHour(int tunnel) {
return getProperty(tunnel, PROP_MAX_CONNS_HOUR, 0);
return getProperty(tunnel, TunnelConfig.PROP_MAX_CONNS_HOUR, 0);
}
public int getLimitDay(int tunnel) {
return getProperty(tunnel, PROP_MAX_CONNS_DAY, 0);
return getProperty(tunnel, TunnelConfig.PROP_MAX_CONNS_DAY, 0);
}
public int getTotalMinute(int tunnel) {
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_MIN, 0);
return getProperty(tunnel, TunnelConfig.PROP_MAX_TOTAL_CONNS_MIN, 0);
}
public int getTotalHour(int tunnel) {
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_HOUR, 0);
return getProperty(tunnel, TunnelConfig.PROP_MAX_TOTAL_CONNS_HOUR, 0);
}
public int getTotalDay(int tunnel) {
return getProperty(tunnel, PROP_MAX_TOTAL_CONNS_DAY, 0);
return getProperty(tunnel, TunnelConfig.PROP_MAX_TOTAL_CONNS_DAY, 0);
}
public int getMaxStreams(int tunnel) {
return getProperty(tunnel, PROP_MAX_STREAMS, 0);
return getProperty(tunnel, TunnelConfig.PROP_MAX_STREAMS, 0);
}
/**
@ -499,12 +500,12 @@ public class EditBean extends IndexBean {
Map<String, String> sorted = new TreeMap<String, String>();
for (Map.Entry<Object, Object> e : opts.entrySet()) {
String key = (String)e.getKey();
if (_noShowSet.contains(key))
if (TunnelConfig._noShowSet.contains(key))
continue;
// leave in for HTTP and Connect so it can get migrated to MD5
// hide for SOCKS until migrated to MD5
if ((!isMD5Proxy) &&
_nonProxyNoShowSet.contains(key))
TunnelConfig._nonProxyNoShowSet.contains(key))
continue;
sorted.put(key, (String)e.getValue());
}

View File

@ -10,46 +10,30 @@ package net.i2p.i2ptunnel.web;
import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import net.i2p.I2PAppContext;
import net.i2p.app.ClientAppManager;
import net.i2p.app.Outproxy;
import net.i2p.client.I2PClient;
import net.i2p.crypto.KeyGenerator;
import net.i2p.crypto.SigType;
import net.i2p.data.Base64;
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.data.SimpleDataStructure;
import net.i2p.i2ptunnel.I2PTunnelClientBase;
import net.i2p.i2ptunnel.I2PTunnelConnectClient;
import net.i2p.i2ptunnel.I2PTunnelHTTPClient;
import net.i2p.i2ptunnel.I2PTunnelHTTPClientBase;
import net.i2p.i2ptunnel.I2PTunnelHTTPServer;
import net.i2p.i2ptunnel.I2PTunnelIRCClient;
import net.i2p.i2ptunnel.I2PTunnelServer;
import net.i2p.i2ptunnel.SSLClientUtil;
import net.i2p.i2ptunnel.TunnelConfig;
import net.i2p.i2ptunnel.TunnelController;
import net.i2p.i2ptunnel.TunnelControllerGroup;
import net.i2p.util.Addresses;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
import net.i2p.util.PasswordManager;
import net.i2p.util.SecureFile;
/**
@ -71,36 +55,11 @@ public class IndexBean {
private String _curNonce;
//private long _nextNonce;
private String _type;
private String _name;
private String _description;
private String _i2cpHost;
private String _i2cpPort;
private String _tunnelDepth;
private String _tunnelQuantity;
private String _tunnelVariance;
private String _tunnelBackupQuantity;
private boolean _connectDelay;
private String _customOptions;
private String _proxyList;
private String _port;
private String _reachableBy;
private String _targetDestination;
private String _targetHost;
private String _targetPort;
private String _spoofedHost;
private String _privKeyFile;
private String _profile;
private boolean _startOnLoad;
private boolean _sharedClient;
private TunnelConfig _config;
private boolean _removeConfirmed;
private final Set<String> _booleanOptions;
private final Map<String, String> _otherOptions;
private int _hashCashValue;
private int _certType;
private String _certSigner;
private String _newProxyUser;
private String _newProxyPW;
public static final int RUNNING = 1;
public static final int STARTING = 2;
@ -114,7 +73,6 @@ public class IndexBean {
/** 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);
static final String CLIENT_NICKNAME = "shared clients";
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";
@ -140,8 +98,7 @@ public class IndexBean {
_tunnel = -1;
_curNonce = "-1";
addNonce();
_booleanOptions = new ConcurrentHashSet<String>(4);
_otherOptions = new ConcurrentHashMap<String, String>(4);
_config = new TunnelConfig();
}
/**
@ -332,24 +289,9 @@ public class IndexBean {
// if it belongs to a shared destination, and is of supported type
if (Boolean.parseBoolean(c.getSharedClient()) && isClient(c.getType())) {
Properties cOpt = c.getConfig("");
if (_tunnelQuantity != null) {
cOpt.setProperty("option.inbound.quantity", _tunnelQuantity);
cOpt.setProperty("option.outbound.quantity", _tunnelQuantity);
}
if (_tunnelDepth != null) {
cOpt.setProperty("option.inbound.length", _tunnelDepth);
cOpt.setProperty("option.outbound.length", _tunnelDepth);
}
if (_tunnelVariance != null) {
cOpt.setProperty("option.inbound.lengthVariance", _tunnelVariance);
cOpt.setProperty("option.outbound.lengthVariance", _tunnelVariance);
}
if (_tunnelBackupQuantity != null) {
cOpt.setProperty("option.inbound.backupQuantity", _tunnelBackupQuantity);
cOpt.setProperty("option.outbound.backupQuantity", _tunnelBackupQuantity);
}
cOpt.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
cOpt.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
_config.updateTunnelQuantities(config);
cOpt.setProperty("option.inbound.nickname", TunnelConfig.SHARED_CLIENT_NICKNAME);
cOpt.setProperty("option.outbound.nickname", TunnelConfig.SHARED_CLIENT_NICKNAME);
c.setConfig(cOpt, "");
}
@ -396,7 +338,7 @@ public class IndexBean {
// Use configured file name if available, not the one from the form.
String pk = cur.getPrivKeyFile();
if (pk == null)
pk = _privKeyFile;
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);
@ -743,80 +685,103 @@ public class IndexBean {
*
*/
public void setType(String type) {
_type = (type != null ? type.trim() : null);
_config.setType(type);
}
String getType() { return _type; }
String getType() { return _config.getType(); }
/** Short name of the tunnel */
public void setName(String name) {
_name = (name != null ? name.trim() : null);
_config.setName(name);
}
/** one line description */
public void setNofilter_description(String description) {
// '#' will blow up DataHelper.storeProps()
_description = (description != null ? description.replace('#', ' ').trim() : null);
_config.setDescription(description);
}
/** I2CP host the router is on, ignored when in router context */
public void setClientHost(String host) {
_i2cpHost = (host != null ? host.trim() : null);
_config.setClientHost(host);
}
/** I2CP port the router is on, ignored when in router context */
public void setClientport(String port) {
_i2cpPort = (port != null ? port.trim() : null);
_config.setClientPort(port);
}
/** how many hops to use for inbound tunnels */
public void setTunnelDepth(String tunnelDepth) {
_tunnelDepth = (tunnelDepth != null ? tunnelDepth.trim() : null);
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) {
_tunnelQuantity = (tunnelQuantity != null ? tunnelQuantity.trim() : null);
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) {
_tunnelVariance = (tunnelVariance != null ? tunnelVariance.trim() : null);
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) {
_tunnelBackupQuantity = (tunnelBackupQuantity != null ? tunnelBackupQuantity.trim() : null);
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) {
_customOptions = (customOptions != null ? customOptions.trim() : null);
_config.setCustomOptions(customOptions);
}
/** what HTTP outproxies should be used (httpclient specific) */
public void setProxyList(String proxyList) {
_proxyList = (proxyList != null ? proxyList.trim() : null);
_config.setProxyList(proxyList);
}
/** what port should this client/httpclient/ircclient listen on */
public void setPort(String port) {
_port = (port != null ? port.trim() : null);
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) {
_reachableBy = (reachableBy != null ? reachableBy.trim() : null);
_config.setReachableBy(reachableBy);
}
/** What peer does this client tunnel point at */
public void setTargetDestination(String dest) {
_targetDestination = (dest != null ? dest.trim() : null);
_config.setTargetDestination(dest);
}
/** What host does this server tunnel point at */
public void setTargetHost(String host) {
_targetHost = (host != null ? host.trim() : null);
_config.setTargetHost(host);
}
/** What port does this server tunnel point at */
public void setTargetPort(String port) {
_targetPort = (port != null ? port.trim() : null);
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) {
_spoofedHost = (host != null ? host.trim() : null);
_config.setSpoofedHost(host);
}
/** What filename is this server tunnel's private keys stored in */
public void setPrivKeyFile(String file) {
_privKeyFile = (file != null ? file.trim() : null);
_config.setPrivKeyFile(file);
}
/**
* If called with any value (and the form submitted with action=Remove),
@ -830,39 +795,39 @@ public class IndexBean {
* loaded (aka right now and whenever the router is started up)
*/
public void setStartOnLoad(String moo) {
_startOnLoad = true;
_config.setStartOnLoad(true);
}
public void setShared(String moo) {
_sharedClient=true;
_config.setShared(true);
}
public void setShared(boolean val) {
_sharedClient=val;
_config.setShared(val);
}
public void setConnectDelay(String moo) {
_connectDelay = true;
_config.setConnectDelay(true);
}
public void setProfile(String profile) {
_profile = profile;
_config.setProfile(profile);
}
public void setReduce(String moo) {
_booleanOptions.add("i2cp.reduceOnIdle");
_config.setReduce();
}
public void setClose(String moo) {
_booleanOptions.add("i2cp.closeOnIdle");
_config.setClose();
}
public void setEncrypt(String moo) {
_booleanOptions.add("i2cp.encryptLeaseSet");
_config.setEncrypt();
}
/** @since 0.8.9 */
public void setDCC(String moo) {
_booleanOptions.add(I2PTunnelIRCClient.PROP_DCC);
_config.setDCC();
}
/** @since 0.9.9 */
public void setUseSSL(String moo) {
_booleanOptions.add(I2PTunnelServer.PROP_USE_SSL);
_config.setUseSSL();
}
/** @since 0.9.9 */
@ -877,7 +842,7 @@ public class IndexBean {
/** @since 0.9.12 */
public void setRejectInproxy(String moo) {
_booleanOptions.add(I2PTunnelHTTPServer.OPT_REJECT_INPROXY);
_config.setRejectInproxy();
}
/** @since 0.9.12 */
@ -892,171 +857,171 @@ public class IndexBean {
/** @since 0.9.13 */
public void setUniqueLocal(String moo) {
_booleanOptions.add(I2PTunnelServer.PROP_UNIQUE_LOCAL);
_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) {
if ("1".equals(val))
_booleanOptions.add(PROP_ENABLE_ACCESS_LIST);
else if ("2".equals(val))
_booleanOptions.add(PROP_ENABLE_BLACKLIST);
_config.setAccessMode(val);
}
public void setDelayOpen(String moo) {
_booleanOptions.add("i2cp.delayOpen");
_config.setDelayOpen();
}
public void setNewDest(String val) {
if ("1".equals(val))
_booleanOptions.add("i2cp.newDestOnResume");
else if ("2".equals(val))
_booleanOptions.add("persistentClientKey");
_config.setNewDest(val);
}
public void setReduceTime(String val) {
if (val != null) {
try {
_otherOptions.put("i2cp.reduceIdleTime", Integer.toString(Integer.parseInt(val.trim()) * 60*1000));
_config.setReduceTime(Integer.parseInt(val.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setReduceCount(String val) {
if (val != null)
_otherOptions.put("i2cp.reduceQuantity", val.trim());
if (val != null) {
try {
_config.setReduceCount(Integer.parseInt(val.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setEncryptKey(String val) {
if (val != null)
_otherOptions.put("i2cp.leaseSetKey", val.trim());
_config.setEncryptKey(val);
}
public void setAccessList(String val) {
if (val != null)
_otherOptions.put("i2cp.accessList", val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
_config.setAccessList(val);
}
public void setJumpList(String val) {
if (val != null)
_otherOptions.put(I2PTunnelHTTPClient.PROP_JUMP_SERVERS, val.trim().replace("\r\n", ",").replace("\n", ",").replace(" ", ","));
_config.setJumpList(val);
}
public void setCloseTime(String val) {
if (val != null) {
try {
_otherOptions.put("i2cp.closeIdleTime", Integer.toString(Integer.parseInt(val.trim()) * 60*1000));
_config.setCloseTime(Integer.parseInt(val.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** @since 0.9.14 */
public void setAllowUserAgent(String moo) {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_USER_AGENT);
_config.setAllowUserAgent();
}
/** @since 0.9.14 */
public void setAllowReferer(String moo) {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_REFERER);
_config.setAllowReferer();
}
/** @since 0.9.14 */
public void setAllowAccept(String moo) {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_ACCEPT);
_config.setAllowAccept();
}
/** @since 0.9.14 */
public void setAllowInternalSSL(String moo) {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_INTERNAL_SSL);
_config.setAllowInternalSSL();
}
/** @since 0.9.18 */
public void setMultihome(String moo) {
_booleanOptions.add("shouldBundleReplyInfo");
_config.setMultihome();
}
/** all proxy auth @since 0.8.2 */
public void setProxyAuth(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
_config.setProxyAuth(s);
}
public void setProxyUsername(String s) {
if (s != null)
_newProxyUser = s.trim();
_config.setProxyUsername(s);
}
public void setNofilter_proxyPassword(String s) {
if (s != null)
_newProxyPW = s.trim();
_config.setProxyPassword(s);
}
public void setOutproxyAuth(String s) {
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH, I2PTunnelHTTPClientBase.DIGEST_AUTH);
_config.setOutproxyAuth(s);
}
public void setOutproxyUsername(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_USER, s.trim());
_config.setOutproxyUsername(s);
}
public void setNofilter_outproxyPassword(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClientBase.PROP_OUTPROXY_PW, s.trim());
_config.setOutproxyPassword(s);
}
/** @since 0.9.11 */
public void setSslProxies(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPClient.PROP_SSL_OUTPROXIES, s.trim().replace(" ", ","));
_config.setSslProxies(s);
}
/** @since 0.9.11 */
public void setUseOutproxyPlugin(String moo) {
_booleanOptions.add(I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN);
_config.setUseOutproxyPlugin();
}
/** all of these are @since 0.8.3 */
protected static final String PROP_MAX_CONNS_MIN = "i2p.streaming.maxConnsPerMinute";
protected static final String PROP_MAX_CONNS_HOUR = "i2p.streaming.maxConnsPerHour";
protected static final String PROP_MAX_CONNS_DAY = "i2p.streaming.maxConnsPerDay";
protected static final String PROP_MAX_TOTAL_CONNS_MIN = "i2p.streaming.maxTotalConnsPerMinute";
protected static final String PROP_MAX_TOTAL_CONNS_HOUR = "i2p.streaming.maxTotalConnsPerHour";
protected static final String PROP_MAX_TOTAL_CONNS_DAY = "i2p.streaming.maxTotalConnsPerDay";
protected static final String PROP_MAX_STREAMS = "i2p.streaming.maxConcurrentStreams";
public void setLimitMinute(String s) {
if (s != null)
_otherOptions.put(PROP_MAX_CONNS_MIN, s.trim());
if (s != null) {
try {
_config.setLimitMinute(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setLimitHour(String s) {
if (s != null)
_otherOptions.put(PROP_MAX_CONNS_HOUR, s.trim());
if (s != null) {
try {
_config.setLimitHour(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setLimitDay(String s) {
if (s != null)
_otherOptions.put(PROP_MAX_CONNS_DAY, s.trim());
if (s != null) {
try {
_config.setLimitDay(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setTotalMinute(String s) {
if (s != null)
_otherOptions.put(PROP_MAX_TOTAL_CONNS_MIN, s.trim());
if (s != null) {
try {
_config.setTotalMinute(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setTotalHour(String s) {
if (s != null)
_otherOptions.put(PROP_MAX_TOTAL_CONNS_HOUR, s.trim());
if (s != null) {
try {
_config.setTotalHour(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setTotalDay(String s) {
if (s != null)
_otherOptions.put(PROP_MAX_TOTAL_CONNS_DAY, s.trim());
if (s != null) {
try {
_config.setTotalDay(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setMaxStreams(String s) {
if (s != null)
_otherOptions.put(PROP_MAX_STREAMS, s.trim());
if (s != null) {
try {
_config.setMaxStreams(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
/**
@ -1064,28 +1029,43 @@ public class IndexBean {
* @since 0.9.9
*/
public void setPostMax(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_MAX, s.trim());
if (s != null) {
try {
_config.setPostMax(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostTotalMax(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_TOTAL_MAX, s.trim());
if (s != null) {
try {
_config.setPostTotalMax(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostCheckTime(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_WINDOW, Integer.toString(Integer.parseInt(s.trim()) * 60));
if (s != null) {
try {
_config.setPostCheckTime(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostBanTime(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_BAN_TIME, Integer.toString(Integer.parseInt(s.trim()) * 60));
if (s != null) {
try {
_config.setPostBanTime(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
public void setPostTotalBanTime(String s) {
if (s != null)
_otherOptions.put(I2PTunnelHTTPServer.OPT_POST_TOTAL_BAN_TIME, Integer.toString(Integer.parseInt(s.trim()) * 60));
if (s != null) {
try {
_config.setPostTotalBanTime(Integer.parseInt(s.trim()));
} catch (NumberFormatException nfe) {}
}
}
/** params needed for hashcash and dest modification */
@ -1112,7 +1092,7 @@ public class IndexBean {
/** @since 0.9.12 */
public void setSigType(String val) {
if (val != null) {
_otherOptions.put(I2PClient.PROP_SIGTYPE, val);
_config.setSigType(val);
if (val.equals("0"))
_certType = 0;
else
@ -1127,28 +1107,25 @@ public class IndexBean {
* @since 0.9.18
*/
public void setKey1(String s) {
if (s != null)
_otherOptions.put("inbound.randomKey", s.trim());
_config.setInboundRandomKey(s);
}
public void setKey2(String s) {
if (s != null)
_otherOptions.put("outbound.randomKey", s.trim());
_config.setOutboundRandomKey(s);
}
public void setKey3(String s) {
if (s != null)
_otherOptions.put("i2cp.leaseSetSigningPrivateKey", s.trim());
_config.setLeaseSetSigningPrivateKey(s);
}
public void setKey4(String s) {
if (s != null)
_otherOptions.put("i2cp.leaseSetPrivateKey", s.trim());
_config.setLeaseSetPrivateKey(s);
}
/** Modify or create a destination */
private String modifyDestination() {
if (_privKeyFile == null || _privKeyFile.trim().length() <= 0)
String privKeyFile = _config.getPrivKeyFile();
if (privKeyFile == null)
return "Private Key File not specified";
TunnelController tun = getController(_tunnel);
@ -1162,9 +1139,9 @@ public class IndexBean {
return "Tunnel must be stopped before modifying destination";
}
File keyFile = new File(_privKeyFile);
File keyFile = new File(privKeyFile);
if (!keyFile.isAbsolute())
keyFile = new File(_context.getConfigDir(), _privKeyFile);
keyFile = new File(_context.getConfigDir(), privKeyFile);
PrivateKeyFile pkf = new PrivateKeyFile(keyFile);
try {
pkf.createIfAbsent();
@ -1194,7 +1171,7 @@ public class IndexBean {
}
if (signerPKF == null || signerPKF.length() <= 0)
return "Signing destination " + _certSigner + " not found";
if (_privKeyFile.equals(signerPKF))
if (privKeyFile.equals(signerPKF))
return "Self-signed destinations not allowed";
Certificate c = pkf.setSignedCert(new PrivateKeyFile(signerPKF));
if (c == null)
@ -1243,310 +1220,10 @@ public class IndexBean {
*
*/
private Properties getConfig() {
Properties config = new Properties();
updateConfigGeneric(config);
if ((isClient(_type) && !TunnelController.TYPE_STREAMR_CLIENT.equals(_type)) ||
TunnelController.TYPE_STREAMR_SERVER.equals(_type)) {
// streamrserver uses interface
if (_reachableBy != null)
config.setProperty(TunnelController.PROP_INTFC, _reachableBy);
else
config.setProperty(TunnelController.PROP_INTFC, "");
} else {
// streamrclient uses targetHost
if (_targetHost != null)
config.setProperty(TunnelController.PROP_TARGET_HOST, _targetHost);
}
if (isClient(_type)) {
// generic client stuff
if (_port != null)
config.setProperty(TunnelController.PROP_LISTEN_PORT, _port);
config.setProperty(TunnelController.PROP_SHARED, _sharedClient + "");
for (String p : _booleanClientOpts)
config.setProperty(OPT + p, "" + _booleanOptions.contains(p));
for (String p : _otherClientOpts) {
if (_otherOptions.containsKey(p))
config.setProperty(OPT + p, _otherOptions.get(p));
}
} else {
// generic server stuff
if (_targetPort != null)
config.setProperty(TunnelController.PROP_TARGET_PORT, _targetPort);
for (String p : _booleanServerOpts)
config.setProperty(OPT + p, "" + _booleanOptions.contains(p));
for (String p : _otherServerOpts) {
if (_otherOptions.containsKey(p))
config.setProperty(OPT + p, _otherOptions.get(p));
}
}
// generic proxy stuff
if (TunnelController.TYPE_HTTP_CLIENT.equals(_type) || TunnelController.TYPE_CONNECT.equals(_type) ||
TunnelController.TYPE_SOCKS.equals(_type) ||TunnelController.TYPE_SOCKS_IRC.equals(_type)) {
for (String p : _booleanProxyOpts)
config.setProperty(OPT + p, "" + _booleanOptions.contains(p));
if (_proxyList != null)
config.setProperty(TunnelController.PROP_PROXIES, _proxyList);
}
// Proxy auth including migration to MD5
if (TunnelController.TYPE_HTTP_CLIENT.equals(_type) || TunnelController.TYPE_CONNECT.equals(_type)) {
// Migrate even if auth is disabled
// go get the old from custom options that updateConfigGeneric() put in there
String puser = OPT + I2PTunnelHTTPClientBase.PROP_USER;
String user = config.getProperty(puser);
String ppw = OPT + I2PTunnelHTTPClientBase.PROP_PW;
String pw = config.getProperty(ppw);
if (user != null && pw != null && user.length() > 0 && pw.length() > 0) {
String pmd5 = OPT + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
user + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
if (config.getProperty(pmd5) == null) {
// not in there, migrate
String realm = _type.equals(TunnelController.TYPE_HTTP_CLIENT) ? I2PTunnelHTTPClient.AUTH_REALM
: I2PTunnelConnectClient.AUTH_REALM;
String hex = PasswordManager.md5Hex(realm, user, pw);
if (hex != null) {
config.setProperty(pmd5, hex);
config.remove(puser);
config.remove(ppw);
}
}
}
// New user/password
String auth = _otherOptions.get(I2PTunnelHTTPClientBase.PROP_AUTH);
if (auth != null && !auth.equals("false")) {
if (_newProxyUser != null && _newProxyPW != null &&
_newProxyUser.length() > 0 && _newProxyPW.length() > 0) {
String pmd5 = OPT + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_PREFIX +
_newProxyUser + I2PTunnelHTTPClientBase.PROP_PROXY_DIGEST_SUFFIX;
String realm = _type.equals(TunnelController.TYPE_HTTP_CLIENT) ? I2PTunnelHTTPClient.AUTH_REALM
: I2PTunnelConnectClient.AUTH_REALM;
String hex = PasswordManager.md5Hex(realm, _newProxyUser, _newProxyPW);
if (hex != null)
config.setProperty(pmd5, hex);
}
}
}
if (TunnelController.TYPE_IRC_CLIENT.equals(_type) ||
TunnelController.TYPE_STD_CLIENT.equals(_type) ||
TunnelController.TYPE_STREAMR_CLIENT.equals(_type)) {
if (_targetDestination != null)
config.setProperty(TunnelController.PROP_DEST, _targetDestination);
} else if (TunnelController.TYPE_HTTP_SERVER.equals(_type) ||
TunnelController.TYPE_HTTP_BIDIR_SERVER.equals(_type)) {
if (_spoofedHost != null)
config.setProperty(TunnelController.PROP_SPOOFED_HOST, _spoofedHost);
for (String p : _httpServerOpts)
if (_otherOptions.containsKey(p))
config.setProperty(OPT + p, _otherOptions.get(p));
}
if (TunnelController.TYPE_HTTP_BIDIR_SERVER.equals(_type)) {
if (_port != null)
config.setProperty(TunnelController.PROP_LISTEN_PORT, _port);
if (_reachableBy != null)
config.setProperty(TunnelController.PROP_INTFC, _reachableBy);
else if (_targetHost != null)
config.setProperty(TunnelController.PROP_INTFC, _targetHost);
else
config.setProperty(TunnelController.PROP_INTFC, "");
}
if (TunnelController.TYPE_IRC_CLIENT.equals(_type)) {
boolean dcc = _booleanOptions.contains(I2PTunnelIRCClient.PROP_DCC);
config.setProperty(OPT + I2PTunnelIRCClient.PROP_DCC,
"" + dcc);
// add some sane server options since they aren't in the GUI (yet)
if (dcc) {
config.setProperty(OPT + PROP_MAX_CONNS_MIN, "3");
config.setProperty(OPT + PROP_MAX_CONNS_HOUR, "10");
config.setProperty(OPT + PROP_MAX_TOTAL_CONNS_MIN, "5");
config.setProperty(OPT + PROP_MAX_TOTAL_CONNS_HOUR, "25");
}
}
if (!isClient(_type) || _booleanOptions.contains("persistentClientKey")) {
// As of 0.9.17, add a persistent random key if not present
String p = OPT + "inbound.randomKey";
if (!config.containsKey(p)) {
byte[] rk = new byte[32];
_context.random().nextBytes(rk);
config.setProperty(p, Base64.encode(rk));
p = OPT + "outbound.randomKey";
_context.random().nextBytes(rk);
config.setProperty(p, Base64.encode(rk));
}
// As of 0.9.18, add persistent leaseset keys if not present
// but only if we know the sigtype
p = OPT + "i2cp.leaseSetSigningPrivateKey";
Destination dest = getDestination(_tunnel);
if (dest != null && !config.containsKey(p)) {
try {
SigType type = dest.getSigType();
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
config.setProperty(p, type.name() + ':' + keys[1].toBase64());
p = OPT + "i2cp.leaseSetPrivateKey";
keys = KeyGenerator.getInstance().generatePKIKeys();
config.setProperty(p, "ELGAMAL_2048:" + keys[1].toBase64());
} catch (GeneralSecurityException gse) {
// so much for that
}
}
}
return config;
}
private static final String _noShowOpts[] = {
"inbound.length", "outbound.length", "inbound.lengthVariance", "outbound.lengthVariance",
"inbound.backupQuantity", "outbound.backupQuantity", "inbound.quantity", "outbound.quantity",
"inbound.nickname", "outbound.nickname", "i2p.streaming.connectDelay", "i2p.streaming.maxWindowSize",
I2PTunnelIRCClient.PROP_DCC
};
private static final String _booleanClientOpts[] = {
"i2cp.reduceOnIdle", "i2cp.closeOnIdle", "i2cp.newDestOnResume", "persistentClientKey", "i2cp.delayOpen",
I2PTunnelClientBase.PROP_USE_SSL,
};
private static final String _booleanProxyOpts[] = {
I2PTunnelHTTPClientBase.PROP_OUTPROXY_AUTH,
I2PTunnelHTTPClient.PROP_USE_OUTPROXY_PLUGIN,
I2PTunnelHTTPClient.PROP_USER_AGENT,
I2PTunnelHTTPClient.PROP_REFERER,
I2PTunnelHTTPClient.PROP_ACCEPT,
I2PTunnelHTTPClient.PROP_INTERNAL_SSL
};
private static final String _booleanServerOpts[] = {
"i2cp.reduceOnIdle", "i2cp.encryptLeaseSet", PROP_ENABLE_ACCESS_LIST, PROP_ENABLE_BLACKLIST,
I2PTunnelServer.PROP_USE_SSL,
I2PTunnelHTTPServer.OPT_REJECT_INPROXY,
I2PTunnelServer.PROP_UNIQUE_LOCAL,
"shouldBundleReplyInfo"
};
private static final String _otherClientOpts[] = {
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.closeIdleTime",
"outproxyUsername", "outproxyPassword",
I2PTunnelHTTPClient.PROP_JUMP_SERVERS,
I2PTunnelHTTPClientBase.PROP_AUTH,
I2PClient.PROP_SIGTYPE,
I2PTunnelHTTPClient.PROP_SSL_OUTPROXIES,
// following are mostly server but could also be persistent client
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey"
};
private static final String _otherServerOpts[] = {
"i2cp.reduceIdleTime", "i2cp.reduceQuantity", "i2cp.leaseSetKey", "i2cp.accessList",
PROP_MAX_CONNS_MIN, PROP_MAX_CONNS_HOUR, PROP_MAX_CONNS_DAY,
PROP_MAX_TOTAL_CONNS_MIN, PROP_MAX_TOTAL_CONNS_HOUR, PROP_MAX_TOTAL_CONNS_DAY,
PROP_MAX_STREAMS, I2PClient.PROP_SIGTYPE,
"inbound.randomKey", "outbound.randomKey", "i2cp.leaseSetSigningPrivateKey", "i2cp.leaseSetPrivateKey"
};
private static final String _httpServerOpts[] = {
I2PTunnelHTTPServer.OPT_POST_WINDOW,
I2PTunnelHTTPServer.OPT_POST_BAN_TIME,
I2PTunnelHTTPServer.OPT_POST_TOTAL_BAN_TIME,
I2PTunnelHTTPServer.OPT_POST_MAX,
I2PTunnelHTTPServer.OPT_POST_TOTAL_MAX
};
/**
* do NOT add these to noShoOpts, we must leave them in for HTTPClient and ConnectCLient
* so they will get migrated to MD5
* TODO migrate socks to MD5
*/
private static final String _otherProxyOpts[] = {
"proxyUsername", "proxyPassword"
};
protected static final Set<String> _noShowSet = new HashSet<String>(128);
protected static final Set<String> _nonProxyNoShowSet = new HashSet<String>(4);
static {
_noShowSet.addAll(Arrays.asList(_noShowOpts));
_noShowSet.addAll(Arrays.asList(_booleanClientOpts));
_noShowSet.addAll(Arrays.asList(_booleanProxyOpts));
_noShowSet.addAll(Arrays.asList(_booleanServerOpts));
_noShowSet.addAll(Arrays.asList(_otherClientOpts));
_noShowSet.addAll(Arrays.asList(_otherServerOpts));
_noShowSet.addAll(Arrays.asList(_httpServerOpts));
_nonProxyNoShowSet.addAll(Arrays.asList(_otherProxyOpts));
}
private void updateConfigGeneric(Properties config) {
config.setProperty(TunnelController.PROP_TYPE, _type);
if (_name != null)
config.setProperty(TunnelController.PROP_NAME, _name);
if (_description != null)
config.setProperty(TunnelController.PROP_DESCR, _description);
if (!_context.isRouterContext()) {
if (_i2cpHost != null)
config.setProperty(TunnelController.PROP_I2CP_HOST, _i2cpHost);
if ( (_i2cpPort != null) && (_i2cpPort.trim().length() > 0) ) {
config.setProperty(TunnelController.PROP_I2CP_PORT, _i2cpPort);
} else {
config.setProperty(TunnelController.PROP_I2CP_PORT, "7654");
}
}
if (_privKeyFile != null)
config.setProperty(TunnelController.PROP_FILE, _privKeyFile);
if (_customOptions != null) {
StringTokenizer tok = new StringTokenizer(_customOptions);
while (tok.hasMoreTokens()) {
String pair = tok.nextToken();
int eq = pair.indexOf('=');
if ( (eq <= 0) || (eq >= pair.length()) )
continue;
String key = pair.substring(0, eq);
if (_noShowSet.contains(key))
continue;
// leave in for HTTP and Connect so it can get migrated to MD5
// hide for SOCKS until migrated to MD5
if ((!TunnelController.TYPE_HTTP_CLIENT.equals(_type)) &&
(!TunnelController.TYPE_CONNECT.equals(_type)) &&
_nonProxyNoShowSet.contains(key))
continue;
String val = pair.substring(eq+1);
config.setProperty(OPT + key, val);
}
}
config.setProperty(TunnelController.PROP_START, _startOnLoad + "");
if (_tunnelQuantity != null) {
config.setProperty("option.inbound.quantity", _tunnelQuantity);
config.setProperty("option.outbound.quantity", _tunnelQuantity);
}
if (_tunnelDepth != null) {
config.setProperty("option.inbound.length", _tunnelDepth);
config.setProperty("option.outbound.length", _tunnelDepth);
}
if (_tunnelVariance != null) {
config.setProperty("option.inbound.lengthVariance", _tunnelVariance);
config.setProperty("option.outbound.lengthVariance", _tunnelVariance);
}
if (_tunnelBackupQuantity != null) {
config.setProperty("option.inbound.backupQuantity", _tunnelBackupQuantity);
config.setProperty("option.outbound.backupQuantity", _tunnelBackupQuantity);
}
if (_connectDelay)
config.setProperty("option.i2p.streaming.connectDelay", "1000");
else
config.setProperty("option.i2p.streaming.connectDelay", "0");
if (isClient(_type) && _sharedClient) {
config.setProperty("option.inbound.nickname", CLIENT_NICKNAME);
config.setProperty("option.outbound.nickname", CLIENT_NICKNAME);
} else if (_name != null) {
config.setProperty("option.inbound.nickname", _name);
config.setProperty("option.outbound.nickname", _name);
}
if ("interactive".equals(_profile))
// This was 1 which doesn't make much sense
// The real way to make it interactive is to make the streaming lib
// MessageInputStream flush faster but there's no option for that yet,
// Setting it to 16 instead of the default but not sure what good that is either.
config.setProperty("option.i2p.streaming.maxWindowSize", "16");
else
config.remove("option.i2p.streaming.maxWindowSize");
// This is easier than requiring TunnelConfig to talk to
// TunnelControllerGroup and TunnelController
_config.setDestination(getDestination(_tunnel));
return _config.getConfig();
}
///