forked from I2P_Developers/i2p.i2p
I2CP:
- Add support for hostname lookups over I2CP with new HostLookup and HostReply messages. - Move username / password from CreateSession to GetDate for early authentication; this is an incompatible chage. Outside router context with authentication enabled, new clients will not work with old routers. Early authentication is not yet enforced, enable with i2cp.strictAuth=true. Will change default to true in a later release. - Block all actions before authentication. - Better disconnect messages to clients for diagnostics - Improve lookup command, add auth command in i2ptunnel CLI for testing - Don't start ClientWriterRunner thread in constructor - Don't flush in ClientWriterRunner unless necessary - Send GetDate even in SimpleSession outside of RouterContext - Improve SetDate wait logic to reduce locks and break out when Disconnect received - Add Disconnect handler to SimpleSession - I2Ping cleanups - Javadocs
This commit is contained in:
@ -46,6 +46,7 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
@ -57,6 +58,8 @@ import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSimpleClient;
|
||||
import net.i2p.client.naming.NamingService;
|
||||
import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
@ -68,6 +71,7 @@ import net.i2p.i2ptunnel.streamr.StreamrConsumer;
|
||||
import net.i2p.i2ptunnel.streamr.StreamrProducer;
|
||||
import net.i2p.util.EventDispatcherImpl;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.OrderedProperties;
|
||||
|
||||
/**
|
||||
* An I2PTunnel tracks one or more I2PTunnelTasks and one or more I2PSessions.
|
||||
@ -87,9 +91,9 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
|
||||
public boolean ownDest = false;
|
||||
|
||||
/** the I2CP port */
|
||||
/** the I2CP port, non-null */
|
||||
public String port = System.getProperty(I2PClient.PROP_TCP_PORT, "7654");
|
||||
/** the I2CP host */
|
||||
/** the I2CP host, non-null */
|
||||
public String host = System.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
|
||||
/** the listen-on host. Sadly the listen-on port does not have a field. */
|
||||
public String listenHost = host;
|
||||
@ -168,7 +172,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
System.out.println("Enter 'help' for help.");
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
|
||||
while (true) {
|
||||
System.out.print("I2PTunnel>");
|
||||
System.out.print("I2PTunnel> ");
|
||||
String cmd = r.readLine();
|
||||
if (cmd == null) break;
|
||||
if (cmd.length() <= 0) continue;
|
||||
@ -293,6 +297,8 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
runPing(allargs, l);
|
||||
} else if (cmdname.equals("owndest")) {
|
||||
runOwnDest(args, l);
|
||||
} else if (cmdname.equals("auth")) {
|
||||
runAuth(args, l);
|
||||
} else {
|
||||
l.log("Unknown command [" + cmdname + "]");
|
||||
}
|
||||
@ -308,27 +314,28 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
private static void runHelp(Logging l) {
|
||||
l.log("Command list:");
|
||||
// alphabetical please...
|
||||
l.log("client <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
|
||||
l.log("clientoptions[ key=value]*");
|
||||
l.log("close [forced] <jobnumber>|all");
|
||||
l.log("config <i2phost> <i2pport>");
|
||||
l.log("connectclient <port> [<sharedClient>] [<proxy>]");
|
||||
l.log("genkeys <privkeyfile> [<pubkeyfile>]");
|
||||
l.log("gentextkeys");
|
||||
l.log("httpbidirserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
|
||||
l.log("httpclient <port> [<sharedClient>] [<proxy>]");
|
||||
l.log("httpserver <host> <port> <spoofedhost> <privkeyfile>");
|
||||
l.log("ircclient <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
|
||||
l.log("list");
|
||||
l.log("listen_on <ip>");
|
||||
l.log("lookup <name>");
|
||||
l.log("owndest yes|no");
|
||||
l.log("ping <args>");
|
||||
l.log("quit");
|
||||
l.log("read_timeout <msecs>");
|
||||
l.log("run <commandfile>");
|
||||
l.log("server <host> <port> <privkeyfile>");
|
||||
l.log("textserver <host> <port> <privkey>");
|
||||
l.log(" auth <username> <password>");
|
||||
l.log(" client <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
|
||||
l.log(" clientoptions [key=value ]*");
|
||||
l.log(" close [forced] <jobnumber>|all");
|
||||
l.log(" config [-s] <i2phost> <i2pport>");
|
||||
l.log(" connectclient <port> [<sharedClient>] [<proxy>]");
|
||||
l.log(" genkeys <privkeyfile> [<pubkeyfile>]");
|
||||
l.log(" gentextkeys");
|
||||
l.log(" httpbidirserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
|
||||
l.log(" httpclient <port> [<sharedClient>] [<proxy>]");
|
||||
l.log(" httpserver <host> <port> <spoofedhost> <privkeyfile>");
|
||||
l.log(" ircclient <port> <pubkey>[,<pubkey,...]|file:<pubkeyfile> [<sharedClient>]");
|
||||
l.log(" list");
|
||||
l.log(" listen_on <ip>");
|
||||
l.log(" lookup <name>");
|
||||
l.log(" owndest yes|no");
|
||||
l.log(" ping <args>");
|
||||
l.log(" quit");
|
||||
l.log(" read_timeout <msecs>");
|
||||
l.log(" run <commandfile>");
|
||||
l.log(" server <host> <port> <privkeyfile>");
|
||||
l.log(" textserver <host> <port> <privkey>");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -345,15 +352,43 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
* @param l logger to receive events and output
|
||||
*/
|
||||
public void runClientOptions(String args[], Logging l) {
|
||||
_clientOptions.clear();
|
||||
if (args != null) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args != null && args.length > 0) {
|
||||
int i = 0;
|
||||
if (args[0].equals("-a")) {
|
||||
i++;
|
||||
} else if (args[0].equals("-c")) {
|
||||
_clientOptions.clear();
|
||||
l.log("Client options cleared");
|
||||
return;
|
||||
} else if (args[0].equals("-x")) {
|
||||
i++;
|
||||
for ( ; i < args.length; i++) {
|
||||
if (_clientOptions.remove(args[i]) != null)
|
||||
l.log("Removed " + args[i]);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
_clientOptions.clear();
|
||||
}
|
||||
for ( ; i < args.length; i++) {
|
||||
int index = args[i].indexOf('=');
|
||||
if (index <= 0) continue;
|
||||
String key = args[i].substring(0, index);
|
||||
String val = args[i].substring(index+1);
|
||||
_clientOptions.setProperty(key, val);
|
||||
}
|
||||
} else {
|
||||
l.log("Usage:");
|
||||
l.log(" clientoptions [key=value ]* // sets current options");
|
||||
l.log(" clientoptions -a [key=value ]* // adds to current options");
|
||||
l.log(" clientoptions -c // clears current options");
|
||||
l.log(" clientoptions -x [key ]* // removes listed options");
|
||||
l.log("Current options:");
|
||||
Properties p = new OrderedProperties();
|
||||
p.putAll(_clientOptions);
|
||||
for (Map.Entry<Object, Object> e : p.entrySet()) {
|
||||
l.log(" [" + e.getKey() + "] = [" + e.getValue() + ']');
|
||||
}
|
||||
}
|
||||
notifyEvent("clientoptions_onResult", "ok");
|
||||
}
|
||||
@ -1147,18 +1182,47 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
* @param l logger to receive events and output
|
||||
*/
|
||||
private void runConfig(String args[], Logging l) {
|
||||
if (args.length == 2) {
|
||||
host = args[0];
|
||||
if (args.length >= 2) {
|
||||
int i = 0;
|
||||
if (args[0].equals("-s")) {
|
||||
_clientOptions.setProperty("i2cp.SSL", "true");
|
||||
i++;
|
||||
} else {
|
||||
_clientOptions.remove("i2cp.SSL");
|
||||
}
|
||||
host = args[i++];
|
||||
listenHost = host;
|
||||
port = args[1];
|
||||
port = args[i];
|
||||
notifyEvent("configResult", "ok");
|
||||
} else {
|
||||
l.log("config <i2phost> <i2pport>");
|
||||
l.log("Usage:");
|
||||
l.log(" config [-s] <i2phost> <i2pport>");
|
||||
l.log(" sets the connection to the i2p router.");
|
||||
l.log("Current setting:");
|
||||
boolean ssl = Boolean.parseBoolean(_clientOptions.getProperty("i2cp.SSL"));
|
||||
l.log(" " + host + ' ' + port + (ssl ? " SSL" : ""));
|
||||
notifyEvent("configResult", "error");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the i2cp username and password
|
||||
*
|
||||
* @param args {username, password}
|
||||
* @param l logger to receive events and output
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void runAuth(String args[], Logging l) {
|
||||
if (args.length == 2) {
|
||||
_clientOptions.setProperty("i2cp.username", args[0]);
|
||||
_clientOptions.setProperty("i2cp.password", args[1]);
|
||||
} else {
|
||||
l.log("Usage:");
|
||||
l.log(" auth <username> <password>");
|
||||
l.log(" Sets the i2cp credentials");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to use its own destination for each outgoing tunnel
|
||||
* Deprecated - only used by CLI
|
||||
@ -1415,16 +1479,19 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
notifyEvent("lookupResult", "invalidUsage");
|
||||
} else {
|
||||
try {
|
||||
Destination dest = destFromName(args[0]);
|
||||
boolean ssl = Boolean.parseBoolean(_clientOptions.getProperty("i2cp.SSL"));
|
||||
String user = _clientOptions.getProperty("i2cp.username");
|
||||
String pw = _clientOptions.getProperty("i2cp.password");
|
||||
Destination dest = destFromName(args[0], host, port, ssl, user, pw);
|
||||
if (dest == null) {
|
||||
l.log("Unknown host");
|
||||
l.log("Unknown host: " + args[0]);
|
||||
notifyEvent("lookupResult", "unkown host");
|
||||
} else {
|
||||
l.log(dest.toBase64());
|
||||
notifyEvent("lookupResult", dest.toBase64());
|
||||
}
|
||||
} catch (DataFormatException dfe) {
|
||||
l.log("Unknown or invalid host");
|
||||
l.log("Unknown or invalid host: " + args[0]);
|
||||
notifyEvent("lookupResult", "invalid host");
|
||||
}
|
||||
}
|
||||
@ -1599,6 +1666,19 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
* @deprecated Don't use i2ptunnel for lookup! Use I2PAppContext.getGlobalContext().namingService().lookup(name) from i2p.jar
|
||||
*/
|
||||
public static Destination destFromName(String name) throws DataFormatException {
|
||||
return destFromName(name, null, null, false, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param i2cpHost may be null
|
||||
* @param i2cpPort may be null
|
||||
* @param user may be null
|
||||
* @param pw may be null
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private static Destination destFromName(String name, String i2cpHost,
|
||||
String i2cpPort, boolean isSSL,
|
||||
String user, String pw) throws DataFormatException {
|
||||
|
||||
if ((name == null) || (name.trim().length() <= 0)) throw new DataFormatException("Empty destination provided");
|
||||
|
||||
@ -1642,8 +1722,46 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging {
|
||||
}
|
||||
} else {
|
||||
// ask naming service
|
||||
name = name.trim();
|
||||
NamingService inst = ctx.namingService();
|
||||
return inst.lookup(name);
|
||||
boolean b32 = name.length() == 60 && name.toLowerCase(Locale.US).endsWith(".b32.i2p");
|
||||
Destination d = null;
|
||||
if (ctx.isRouterContext() || !b32) {
|
||||
// Local lookup.
|
||||
// Even though we could do b32 outside router ctx here,
|
||||
// we do it below instead so we can set the host and port,
|
||||
// which we can't do with lookup()
|
||||
d = inst.lookup(name);
|
||||
if (d != null || ctx.isRouterContext())
|
||||
return d;
|
||||
}
|
||||
// Outside router context only,
|
||||
// try simple session to ask the router.
|
||||
I2PClient client = new I2PSimpleClient();
|
||||
Properties opts = new Properties();
|
||||
if (i2cpHost != null)
|
||||
opts.put(I2PClient.PROP_TCP_HOST, i2cpHost);
|
||||
if (i2cpPort != null)
|
||||
opts.put(I2PClient.PROP_TCP_PORT, i2cpPort);
|
||||
opts.put("i2cp.SSL", Boolean.toString(isSSL));
|
||||
if (user != null)
|
||||
opts.put("i2cp.username", user);
|
||||
if (pw != null)
|
||||
opts.put("i2cp.password", pw);
|
||||
I2PSession session = null;
|
||||
try {
|
||||
session = client.createSession(null, opts);
|
||||
session.connect();
|
||||
d = session.lookupDest(name);
|
||||
} catch (I2PSessionException ise) {
|
||||
if (log.shouldLog(Log.WARN))
|
||||
log.warn("Lookup via router failed", ise);
|
||||
} finally {
|
||||
if (session != null) {
|
||||
try { session.destroySession(); } catch (I2PSessionException ise) {}
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2Ping extends I2PTunnelTask implements Runnable {
|
||||
private final static Log _log = new Log(I2Ping.class);
|
||||
private final Log _log = new Log(I2Ping.class);
|
||||
|
||||
private int PING_COUNT = 3;
|
||||
private static final int CPING_COUNT = 5;
|
||||
@ -28,20 +28,20 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
|
||||
|
||||
private int MAX_SIMUL_PINGS = 10; // not really final...
|
||||
|
||||
private boolean countPing = false;
|
||||
private boolean countPing;
|
||||
private boolean reportTimes = true;
|
||||
|
||||
private I2PSocketManager sockMgr;
|
||||
private Logging l;
|
||||
private boolean finished = false;
|
||||
private String command;
|
||||
private final I2PSocketManager sockMgr;
|
||||
private final Logging l;
|
||||
private boolean finished;
|
||||
private final String command;
|
||||
private long timeout = PING_TIMEOUT;
|
||||
|
||||
private final Object simulLock = new Object();
|
||||
private int simulPings = 0;
|
||||
private long lastPingTime = 0;
|
||||
private int simulPings;
|
||||
private long lastPingTime;
|
||||
|
||||
private final Object lock = new Object(), slock = new Object();
|
||||
private final Object lock = new Object();
|
||||
|
||||
//public I2Ping(String cmd, Logging l,
|
||||
// boolean ownDest) {
|
||||
@ -52,12 +52,10 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
|
||||
super("I2Ping [" + cmd + "]", notifyThis, tunnel);
|
||||
this.l = l;
|
||||
command = cmd;
|
||||
synchronized (slock) {
|
||||
if (ownDest) {
|
||||
sockMgr = I2PTunnelClient.buildSocketManager(tunnel);
|
||||
} else {
|
||||
sockMgr = I2PTunnelClient.getSocketManager(tunnel);
|
||||
}
|
||||
if (ownDest) {
|
||||
sockMgr = I2PTunnelClient.buildSocketManager(tunnel);
|
||||
} else {
|
||||
sockMgr = I2PTunnelClient.getSocketManager(tunnel);
|
||||
}
|
||||
Thread t = new I2PAppThread(this);
|
||||
t.setName("Client");
|
||||
@ -187,7 +185,7 @@ public class I2Ping extends I2PTunnelTask implements Runnable {
|
||||
}
|
||||
|
||||
public class PingHandler extends I2PAppThread {
|
||||
private String destination;
|
||||
private final String destination;
|
||||
|
||||
public PingHandler(String dest) {
|
||||
this.destination = dest;
|
||||
|
Reference in New Issue
Block a user