diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index dc9dfd2fc..b11f954e7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -552,14 +552,14 @@ public class I2PTunnel implements Logging, EventDispatcher { * Integer port number if the client is listening * sharedClient parameter is a String "true" or "false" * - * @param args {portNumber, destinationBase64 or "file:filename"[, sharedClient]} + * @param args {portNumber, destinationBase64 or "file:filename"[, sharedClient [, privKeyFile]]} * @param l logger to receive events and output */ public void runClient(String args[], Logging l) { boolean isShared = true; - if (args.length == 3) + if (args.length >= 3) isShared = Boolean.valueOf(args[2].trim()).booleanValue(); - if ( (args.length == 2) || (args.length == 3) ) { + if (args.length >= 2) { int portNum = -1; try { portNum = Integer.parseInt(args[0]); @@ -572,7 +572,10 @@ public class I2PTunnel implements Logging, EventDispatcher { I2PTunnelTask task; ownDest = !isShared; try { - task = new I2PTunnelClient(portNum, args[1], l, ownDest, (EventDispatcher) this, this); + String privateKeyFile = null; + if (args.length >= 4) + privateKeyFile = args[3]; + task = new I2PTunnelClient(portNum, args[1], l, ownDest, (EventDispatcher) this, this, privateKeyFile); addtask(task); notifyEvent("clientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { @@ -581,7 +584,7 @@ public class I2PTunnel implements Logging, EventDispatcher { notifyEvent("clientTaskId", Integer.valueOf(-1)); } } else { - l.log("client [,]|file:[ ]"); + l.log("client [,]|file:[ ] []"); l.log(" creates a client that forwards port to the pubkey.\n" + " use 0 as port to get a free port assigned. If you specify\n" + " a comma delimited list of pubkeys, it will rotate among them\n" @@ -720,11 +723,11 @@ public class I2PTunnel implements Logging, EventDispatcher { * Also sets "ircclientStatus" = "ok" or "error" after the client tunnel has started. * parameter sharedClient is a String, either "true" or "false" * - * @param args {portNumber,destinationBase64 or "file:filename" [, sharedClient]} + * @param args {portNumber,destinationBase64 or "file:filename" [, sharedClient [, privKeyFile]]} * @param l logger to receive events and output */ public void runIrcClient(String args[], Logging l) { - if (args.length >= 2 && args.length <= 3) { + if (args.length >= 2) { int port = -1; try { port = Integer.parseInt(args[0]); @@ -751,7 +754,10 @@ public class I2PTunnel implements Logging, EventDispatcher { I2PTunnelTask task; ownDest = !isShared; try { - task = new I2PTunnelIRCClient(port, args[1],l, ownDest, (EventDispatcher) this, this); + String privateKeyFile = null; + if (args.length >= 4) + privateKeyFile = args[3]; + task = new I2PTunnelIRCClient(port, args[1], l, ownDest, (EventDispatcher) this, this, privateKeyFile); addtask(task); notifyEvent("ircclientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { @@ -760,7 +766,7 @@ public class I2PTunnel implements Logging, EventDispatcher { notifyEvent("ircclientTaskId", Integer.valueOf(-1)); } } else { - l.log("ircclient []"); + l.log("ircclient [ []]"); l.log(" creates a client that filter IRC protocol."); l.log(" (optional) indicates if this client shares tunnels with other clients (true of false)"); notifyEvent("ircclientTaskId", Integer.valueOf(-1)); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java index 4739a07f4..502bb28d5 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java @@ -31,8 +31,8 @@ public class I2PTunnelClient extends I2PTunnelClientBase { */ public I2PTunnelClient(int localPort, String destinations, Logging l, boolean ownDest, EventDispatcher notifyThis, - I2PTunnel tunnel) throws IllegalArgumentException { - super(localPort, ownDest, l, notifyThis, "SynSender", tunnel); + I2PTunnel tunnel, String pkf) throws IllegalArgumentException { + super(localPort, ownDest, l, notifyThis, "SynSender", tunnel, pkf); if (waitEventValue("openBaseClientResult").equals("error")) { notifyEvent("openClientResult", "error"); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index c926156f4..fadbf9fa1 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -3,6 +3,7 @@ */ package net.i2p.i2ptunnel; +import java.io.FileInputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.net.ConnectException; @@ -59,6 +60,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna private byte[] pubkey; private String handlerName; + private String privKeyFile; private Object conLock = new Object(); @@ -91,18 +93,28 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna // I2PTunnelClientBase(localPort, ownDest, l, (EventDispatcher)null); //} + public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l, + EventDispatcher notifyThis, String handlerName, + I2PTunnel tunnel) throws IllegalArgumentException { + this(localPort, ownDest, l, notifyThis, handlerName, tunnel, null); + } + /** + * @param privKeyFile null to generate a transient key + * * @throws IllegalArgumentException if the I2CP configuration is b0rked so * badly that we cant create a socketManager */ public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l, EventDispatcher notifyThis, String handlerName, - I2PTunnel tunnel) throws IllegalArgumentException{ + I2PTunnel tunnel, String pkf) throws IllegalArgumentException{ super(localPort + " (uninitialized)", notifyThis, tunnel); _clientId = ++__clientId; this.localPort = localPort; this.l = l; this.handlerName = handlerName + _clientId; + this.privKeyFile = pkf; + _context = tunnel.getContext(); _context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 }); @@ -195,28 +207,34 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna private static I2PSocketManager socketManager; protected synchronized I2PSocketManager getSocketManager() { - return getSocketManager(getTunnel()); + return getSocketManager(getTunnel(), this.privKeyFile); } protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel) { + return getSocketManager(tunnel, null); + } + protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) { if (socketManager != null) { I2PSession s = socketManager.getSession(); if ( (s == null) || (s.isClosed()) ) { _log.info("Building a new socket manager since the old one closed [s=" + s + "]"); - socketManager = buildSocketManager(tunnel); + socketManager = buildSocketManager(tunnel, pkf); } else { _log.info("Not building a new socket manager since the old one is open [s=" + s + "]"); } } else { _log.info("Building a new socket manager since there is no other one"); - socketManager = buildSocketManager(tunnel); + socketManager = buildSocketManager(tunnel, pkf); } return socketManager; } protected I2PSocketManager buildSocketManager() { - return buildSocketManager(getTunnel()); + return buildSocketManager(getTunnel(), this.privKeyFile); } protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel) { + return buildSocketManager(tunnel, null); + } + protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf) { Properties props = new Properties(); props.putAll(tunnel.getClientOptions()); int portNum = 7654; @@ -230,10 +248,22 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna I2PSocketManager sockManager = null; while (sockManager == null) { - // if persistent dest - // sockManager = I2PSocketManagerFactory.createManager(privData, tunnel.host, portNum, props); - // else - sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props); + if (pkf != null) { + // Persistent client dest + FileInputStream fis = null; + try { + fis = new FileInputStream(pkf); + sockManager = I2PSocketManagerFactory.createManager(fis, tunnel.host, portNum, props); + } catch (IOException ioe) { + _log.error("Error opening key file", ioe); + // this is going to loop but if we break we'll get a NPE + } finally { + if (fis != null) + try { fis.close(); } catch (IOException ioe) {} + } + } else { + sockManager = I2PSocketManagerFactory.createManager(tunnel.host, portNum, props); + } if (sockManager == null) { _log.log(Log.CRIT, "Unable to create socket manager"); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index 5b223b1a4..732c222a7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -39,12 +39,12 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable Logging l, boolean ownDest, EventDispatcher notifyThis, - I2PTunnel tunnel) throws IllegalArgumentException { + I2PTunnel tunnel, String pkf) throws IllegalArgumentException { super(localPort, ownDest, l, notifyThis, - "IRCHandler " + (++__clientId), tunnel); + "IRCHandler " + (++__clientId), tunnel, pkf); StringTokenizer tok = new StringTokenizer(destinations, ","); dests = new ArrayList(1); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 727b18158..419e5a899 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -192,7 +192,12 @@ public class TunnelController implements Logging { String listenPort = getListenPort(); String dest = getTargetDestination(); String sharedClient = getSharedClient(); - _tunnel.runIrcClient(new String[] { listenPort, dest, sharedClient }, this); + if (getPersistentClientKey()) { + String privKeyFile = getPrivKeyFile(); + _tunnel.runIrcClient(new String[] { listenPort, dest, sharedClient, privKeyFile }, this); + } else { + _tunnel.runIrcClient(new String[] { listenPort, dest, sharedClient }, this); + } } private void startSocksClient() { @@ -264,7 +269,12 @@ public class TunnelController implements Logging { String listenPort = getListenPort(); String dest = getTargetDestination(); String sharedClient = getSharedClient(); - _tunnel.runClient(new String[] { listenPort, dest, sharedClient }, this); + if (getPersistentClientKey()) { + String privKeyFile = getPrivKeyFile(); + _tunnel.runClient(new String[] { listenPort, dest, sharedClient, privKeyFile }, this); + } else { + _tunnel.runClient(new String[] { listenPort, dest, sharedClient }, this); + } } private void startServer() { @@ -395,7 +405,7 @@ public class TunnelController implements Logging { public String getProxyList() { return _config.getProperty("proxyList"); } public String getSharedClient() { return _config.getProperty("sharedClient", "true"); } public boolean getStartOnLoad() { return "true".equalsIgnoreCase(_config.getProperty("startOnLoad", "true")); } - public boolean getPersistentClientKey() { return Boolean.valueOf(_config.getProperty("persistentClientKey")).booleanValue(); } + public boolean getPersistentClientKey() { return Boolean.valueOf(_config.getProperty("option.persistentClientKey")).booleanValue(); } public String getMyDestination() { if (_tunnel != null) { List sessions = _tunnel.getSessions(); diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp index 3c046badd..178f564ef 100644 --- a/apps/i2ptunnel/jsp/editClient.jsp +++ b/apps/i2ptunnel/jsp/editClient.jsp @@ -351,6 +351,7 @@
+ <% if ("client".equals(tunnelType) || "ircclient".equals(tunnelType)) { %>
+
+ + + (if known) +

+ <% } %>