* 2005-07-27 0.6 released

2005-07-27  jrandom
    * Enabled SSU as the default top priority transport, adjusting the
      config.jsp page accordingly.
    * Add verification fields to the SSU and TCP connection negotiation (not
      compatible with previous builds)
    * Enable the backwards incompatible tunnel crypto change as documented in
      tunnel-alt.html (have each hop encrypt the received IV before using it,
      then encrypt it again before sending it on)
    * Disable the I2CP encryption, leaving in place the end to end garlic
      encryption (another backwards incompatible change)
    * Adjust the protocol versions on the TCP and SSU transports so that they
      won't talk to older routers.
    * Fix up the config stats handling again
    * Fix a rare off-by-one in the SSU fragmentation
    * Reduce some unnecessary netDb resending by inluding the peers queried
      successfully in the store redundancy count.
This commit is contained in:
jrandom
2005-07-27 19:03:43 +00:00
committed by zzz
parent aeb8f02269
commit a8a866b5f6
45 changed files with 325 additions and 827 deletions

View File

@ -1,445 +0,0 @@
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
* (c) 2003 - 2004 mihi
*/
package net.i2p.i2ptunnel;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.Clock;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
/**
* Quick and dirty socket listener to control an I2PTunnel.
* Basically run this class as TunnelManager [listenHost] [listenPort] and
* then send it commands on that port. Commands are one shot deals -
* Send a command + newline, get a response plus newline, then get disconnected.
* <p />
* <b>Implemented commands:</b>
* <pre>
* -------------------------------------------------
* lookup &lt;name&gt;\n
* --
* &lt;base64 of the destination&gt;\n
* or
* &lt;error message, usually 'Unknown host'&gt;\n
*
* Lookup the public key of a named destination (i.e. listed in hosts.txt)
* -------------------------------------------------
* genkey\n
* --
* &lt;base64 of the destination&gt;\t&lt;base64 of private data&gt;\n
*
* Generates a new public and private key pair
* -------------------------------------------------
* convertprivate &lt;base64 of privkey&gt;
* --
* &lt;base64 of destination&gt;\n
* or
* &lt;error message&gt;\n
*
* Returns the destination (pubkey) of a given private key.
* -------------------------------------------------
* listen_on &lt;ip&gt;\n
* --
* ok\n
* or
* error\n
*
* Sets the ip address clients will listen on. By default this is the
* localhost (127.0.0.1)
* -------------------------------------------------
* openclient &lt;listenPort&gt; &lt;peer&gt;[ &lt;sharedClient&gt;]\n
* --
* ok [&lt;jobId&gt;]\n
* or
* ok &lt;listenPort&gt; [&lt;jobId&gt;]\n
* or
* error\n
*
* Open a tunnel on the given &lt;listenport&gt; to the destination specified
* by &lt;peer&gt;. If &lt;listenPort&gt; is 0 a free port is picked and returned in
* the reply message. Otherwise the short reply message is used.
* Peer can be the base64 of the destination, a file with the public key
* specified as 'file:&lt;filename&gt;' or the name of a destination listed in
* hosts.txt. The &lt;jobId&gt; returned together with "ok" and &lt;listenport&gt; can
* later be used as argument for the "close" command.
* &lt;sharedClient&gt; indicates if this httpclient shares tunnels with other
* clients or not (just use 'true' and 'false'
* -------------------------------------------------
* openhttpclient &lt;listenPort&gt; [&lt;sharedClient&gt;] [&lt;proxy&gt;]\n
* --
* ok [&lt;jobId&gt;]\n
* or
* ok &lt;listenPort&gt; [&lt;jobId&gt;]\n
* or
* error\n
*
* Open an HTTP proxy through the I2P on the given
* &lt;listenport&gt;. &lt;proxy&gt; (optional) specifies a
* destination to be used as an outbound proxy, to access normal WWW
* sites out of the .i2p domain. If &lt;listenPort&gt; is 0 a free
* port is picked and returned in the reply message. Otherwise the
* short reply message is used. &lt;proxy&gt; can be the base64 of the
* destination, a file with the public key specified as
* 'file:&lt;filename&gt;' or the name of a destination listed in
* hosts.txt. The &lt;jobId&gt; returned together with "ok" and
* &lt;listenport&gt; can later be used as argument for the "close"
* command.
* &lt;sharedClient&gt; indicates if this httpclient shares tunnels with other
* clients or not (just use 'true' and 'false'
* -------------------------------------------------
* opensockstunnel &lt;listenPort&gt;\n
* --
* ok [&lt;jobId&gt;]\n
* or
* ok &lt;listenPort&gt; [&lt;jobId&gt;]\n
* or
* error\n
*
* Open an SOCKS tunnel through the I2P on the given
* &lt;listenport&gt;. If &lt;listenPort&gt; is 0 a free port is
* picked and returned in the reply message. Otherwise the short
* reply message is used. The &lt;jobId&gt; returned together with
* "ok" and &lt;listenport&gt; can later be used as argument for the
* "close" command.
* -------------------------------------------------
* openserver &lt;serverHost&gt; &lt;serverPort&gt; &lt;serverKeys&gt;\n
* --
* ok [&lt;jobId&gt;]\n
* or
* error\n
*
* Starts receiving traffic for the destination specified by &lt;serverKeys&gt;
* and forwards it to the &lt;serverPort&gt; of &lt;serverHost&gt;.
* &lt;serverKeys&gt; is the base 64 encoded private key set of the local
* destination. The &lt;joId&gt; returned together with "ok" can later be used
* as argument for the "close" command.
* -------------------------------------------------
* close [forced] &lt;jobId&gt;\n
* or
* close [forced] all\n
* --
* ok\n
* or
* error\n
*
* Closes the job specified by &lt;jobId&gt; or all jobs. Use the list command
* for a list of running jobs.
* Normally a connection job is not closed when it still has an active
* connection. Use the optional 'forced' keyword to close connections
* regardless of their use.
* -------------------------------------------------
* list\n
* --
* Example output:
*
* [0] i2p.dnsalias.net/69.55.226.145:5555 &lt;- C:\i2pKeys\squidPriv
* [1] 8767 -&gt; HTTPClient
* [2] 7575 -&gt; file:C:\i2pKeys\squidPub
* [3] 5252 -&gt; sCcSANIO~f4AQtCNI1BvDp3ZBS~9Ag5O0k0Msm7XBWWz5eOnZWL3MQ-2rxlesucb9XnpASGhWzyYNBpWAfaIB3pux1J1xujQLOwscMIhm7T8BP76Ly5jx6BLZCYrrPj0BI0uV90XJyT~4UyQgUlC1jzFQdZ9HDgBPJDf1UI4-YjIwEHuJgdZynYlQ1oUFhgno~HhcDByXO~PDaO~1JDMDbBEfIh~v6MgmHp-Xchod1OfKFrxFrzHgcJbn7E8edTFjZA6JCi~DtFxFelQz1lSBd-QB1qJnA0g-pVL5qngNUojXJCXs4qWcQ7ICLpvIc-Fpfj-0F1gkVlGDSGkb1yLH3~8p4czYgR3W5D7OpwXzezz6clpV8kmbd~x2SotdWsXBPRhqpewO38coU4dJG3OEUbuYmdN~nJMfWbmlcM1lXzz2vBsys4sZzW6dV3hZnbvbfxNTqbdqOh-KXi1iAzXv7CVTun0ubw~CfeGpcAqutC5loRUq7Mq62ngOukyv8Z9AAAA
*
* Lists descriptions of all running jobs. The exact format of the
* description depends on the type of job.
* -------------------------------------------------
* </pre>
*
*
* @deprecated this isn't run by default, and no one seems to use it, and has
* lots of things to maintain. so, at some point this may dissapear
* unless someone pipes up ;)
*/
public class TunnelManager implements Runnable {
private final static Log _log = new Log(TunnelManager.class);
private I2PTunnel _tunnel;
private ServerSocket _socket;
private boolean _keepAccepting;
public TunnelManager(int listenPort) {
this(null, listenPort);
}
public TunnelManager(String listenHost, int listenPort) {
_tunnel = new I2PTunnel();
_keepAccepting = true;
try {
if (listenHost != null) {
_socket = new ServerSocket(listenPort, 0, InetAddress.getByName(listenHost));
_log.info("Listening for tunnel management clients on " + listenHost + ":" + listenPort);
} else {
_socket = new ServerSocket(listenPort);
_log.info("Listening for tunnel management clients on localhost:" + listenPort);
}
} catch (Exception e) {
_log.error("Error starting up tunnel management listener on " + listenPort, e);
}
}
public static void main(String args[]) {
int port = 7676;
String host = null;
if (args.length == 1) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException nfe) {
_log.error("Usage: TunnelManager [host] [port]");
return;
}
} else if (args.length == 2) {
host = args[0];
try {
port = Integer.parseInt(args[1]);
} catch (NumberFormatException nfe) {
_log.error("Usage: TunnelManager [host] [port]");
return;
}
}
TunnelManager mgr = new TunnelManager(host, port);
Thread t = new I2PThread(mgr, "Listener");
t.start();
}
public void run() {
if (_socket == null) {
_log.error("Unable to start listening, since the socket was not bound. Already running?");
return;
}
_log.debug("Running");
try {
while (_keepAccepting) {
Socket socket = _socket.accept();
_log.debug("Client accepted");
if (socket != null) {
Thread t = new I2PThread(new TunnelManagerClientRunner(this, socket));
t.setName("TunnelManager Client");
t.setPriority(I2PThread.MIN_PRIORITY);
t.start();
}
}
} catch (IOException ioe) {
_log.error("Error accepting connections", ioe);
} catch (Exception e) {
_log.error("Other error?!", e);
} finally {
if (_socket != null) try {
_socket.close();
} catch (IOException ioe) {
}
}
try {
Thread.sleep(5000);
} catch (InterruptedException ie) {
}
}
public void error(String msg, OutputStream out) throws IOException {
out.write(msg.getBytes());
out.write('\n');
}
public void processQuit(OutputStream out) throws IOException {
out.write("Nice try".getBytes());
out.write('\n');
}
public void processList(OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
long startCommand = Clock.getInstance().now();
_tunnel.runCommand("list", buf);
Object obj = _tunnel.waitEventValue("listDone");
long endCommand = Clock.getInstance().now();
String str = buf.getBuffer();
_log.debug("ListDone complete after " + (endCommand - startCommand) + "ms: [" + str + "]");
out.write(str.getBytes());
out.write('\n');
buf.ignoreFurtherActions();
}
public void processListenOn(String ip, OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand("listen_on " + ip, buf);
String status = (String) _tunnel.waitEventValue("listen_onResult");
out.write((status + "\n").getBytes());
buf.ignoreFurtherActions();
}
/**
* "lookup <name>" returns with the result in base64, else "Unknown host" [or something like that],
* then a newline.
*
*/
public void processLookup(String name, OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand("lookup " + name, buf);
String rv = (String) _tunnel.waitEventValue("lookupResult");
out.write(rv.getBytes());
out.write('\n');
buf.ignoreFurtherActions();
}
public void processTestDestination(String destKey, OutputStream out) throws IOException {
try {
Destination d = new Destination();
d.fromBase64(destKey);
out.write("valid\n".getBytes());
} catch (DataFormatException dfe) {
out.write("invalid\n".getBytes());
}
out.flush();
}
public void processConvertPrivate(String priv, OutputStream out) throws IOException {
try {
Destination dest = new Destination();
dest.fromBase64(priv);
String str = dest.toBase64();
out.write(str.getBytes());
out.write('\n');
} catch (DataFormatException dfe) {
_log.error("Error converting private data", dfe);
out.write("Error converting private key\n".getBytes());
}
}
public void processClose(String which, boolean forced, OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand((forced ? "close forced " : "close ") + which, buf);
String str = (String) _tunnel.waitEventValue("closeResult");
out.write((str + "\n").getBytes());
buf.ignoreFurtherActions();
}
/**
* "genkey" returns with the base64 of the destination, followed by a tab, then the base64 of that
* destination's private keys, then a newline.
*
*/
public void processGenKey(OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand("gentextkeys", buf);
String priv = (String) _tunnel.waitEventValue("privateKey");
String pub = (String) _tunnel.waitEventValue("publicDestination");
out.write((pub + "\t" + priv).getBytes());
out.write('\n');
buf.ignoreFurtherActions();
}
public void processOpenClient(int listenPort, String peer, String sharedClient, OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand("client " + listenPort + " " + peer + " " + sharedClient, buf);
Integer taskId = (Integer) _tunnel.waitEventValue("clientTaskId");
if (taskId.intValue() < 0) {
out.write("error\n".getBytes());
buf.ignoreFurtherActions();
return;
}
String rv = (String) _tunnel.waitEventValue("openClientResult");
if (rv.equals("error")) {
out.write((rv + "\n").getBytes());
buf.ignoreFurtherActions();
return;
}
if (listenPort != 0) {
out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
buf.ignoreFurtherActions();
return;
}
Integer port = (Integer) _tunnel.waitEventValue("clientLocalPort");
out.write((rv + " " + port.intValue() + " [" + taskId.intValue() + "]\n").getBytes());
buf.ignoreFurtherActions();
}
public void processOpenHTTPClient(int listenPort, String sharedClient, String proxy, OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand("httpclient " + listenPort + " " + sharedClient + " " + proxy, buf);
Integer taskId = (Integer) _tunnel.waitEventValue("httpclientTaskId");
if (taskId.intValue() < 0) {
out.write("error\n".getBytes());
buf.ignoreFurtherActions();
return;
}
String rv = (String) _tunnel.waitEventValue("openHTTPClientResult");
if (rv.equals("error")) {
out.write((rv + "\n").getBytes());
buf.ignoreFurtherActions();
return;
}
if (listenPort != 0) {
out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
buf.ignoreFurtherActions();
return;
}
Integer port = (Integer) _tunnel.waitEventValue("clientLocalPort");
out.write((rv + " " + port.intValue() + " [" + taskId.intValue() + "]\n").getBytes());
buf.ignoreFurtherActions();
}
public void processOpenSOCKSTunnel(int listenPort, OutputStream out) throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand("sockstunnel " + listenPort, buf);
Integer taskId = (Integer) _tunnel.waitEventValue("sockstunnelTaskId");
if (taskId.intValue() < 0) {
out.write("error\n".getBytes());
buf.ignoreFurtherActions();
return;
}
String rv = (String) _tunnel.waitEventValue("openSOCKSTunnelResult");
if (rv.equals("error")) {
out.write((rv + "\n").getBytes());
buf.ignoreFurtherActions();
return;
}
if (listenPort != 0) {
out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
buf.ignoreFurtherActions();
return;
}
Integer port = (Integer) _tunnel.waitEventValue("clientLocalPort");
out.write((rv + " " + port.intValue() + " [" + taskId.intValue() + "]\n").getBytes());
buf.ignoreFurtherActions();
}
public void processOpenServer(String serverHost, int serverPort, String privateKeys, OutputStream out)
throws IOException {
BufferLogger buf = new BufferLogger();
_tunnel.runCommand("textserver " + serverHost + " " + serverPort + " " + privateKeys, buf);
Integer taskId = (Integer) _tunnel.waitEventValue("serverTaskId");
if (taskId.intValue() < 0) {
out.write("error\n".getBytes());
buf.ignoreFurtherActions();
return;
}
String rv = (String) _tunnel.waitEventValue("openServerResult");
if (rv.equals("error")) {
out.write((rv + "\n").getBytes());
buf.ignoreFurtherActions();
return;
}
out.write((rv + " [" + taskId.intValue() + "]\n").getBytes());
buf.ignoreFurtherActions();
}
/**
* Frisbee.
*
*/
public void unknownCommand(String command, OutputStream out) throws IOException {
out.write("Unknown command: ".getBytes());
out.write(command.getBytes());
out.write("\n".getBytes());
}
}

View File

@ -1,203 +0,0 @@
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
* (c) 2003 - 2004 mihi
*/
package net.i2p.i2ptunnel;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.StringTokenizer;
import net.i2p.util.Log;
/**
* Runner thread that reads commands from the socket and fires off commands to
* the TunnelManager
*
*/
class TunnelManagerClientRunner implements Runnable {
private final static Log _log = new Log(TunnelManagerClientRunner.class);
private TunnelManager _mgr;
private Socket _clientSocket;
public TunnelManagerClientRunner(TunnelManager mgr, Socket socket) {
_clientSocket = socket;
_mgr = mgr;
}
public void run() {
_log.debug("Client running");
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(_clientSocket.getInputStream()));
OutputStream out = _clientSocket.getOutputStream();
String cmd = reader.readLine();
if (cmd != null) processCommand(cmd, out);
} catch (IOException ioe) {
_log.error("Error processing client commands", ioe);
} finally {
if (_clientSocket != null) try {
_clientSocket.close();
} catch (IOException ioe) {
}
}
_log.debug("Client closed");
}
/**
* Parse the command string and fire off the appropriate tunnelManager method,
* sending the results to the output stream
*/
private void processCommand(String command, OutputStream out) throws IOException {
_log.debug("Processing [" + command + "]");
StringTokenizer tok = new StringTokenizer(command);
if (!tok.hasMoreTokens()) {
_mgr.unknownCommand(command, out);
} else {
String cmd = tok.nextToken();
if ("quit".equalsIgnoreCase(cmd)) {
_mgr.processQuit(out);
} else if ("lookup".equalsIgnoreCase(cmd)) {
if (tok.hasMoreTokens())
_mgr.processLookup(tok.nextToken(), out);
else
_mgr.error("Usage: lookup <hostname>", out);
} else if ("testdestination".equalsIgnoreCase(cmd)) {
if (tok.hasMoreTokens())
_mgr.processTestDestination(tok.nextToken(), out);
else
_mgr.error("Usage: testdestination <publicDestination>", out);
} else if ("convertprivate".equalsIgnoreCase(cmd)) {
if (tok.hasMoreTokens())
_mgr.processConvertPrivate(tok.nextToken(), out);
else
_mgr.error("Usage: convertprivate <privateData>", out);
} else if ("close".equalsIgnoreCase(cmd)) {
if (tok.hasMoreTokens()) {
String closeArg;
if ((closeArg = tok.nextToken()).equals("forced")) {
if (tok.hasMoreTokens()) {
_mgr.processClose(tok.nextToken(), true, out);
} else {
_mgr.error("Usage: close [forced] <jobnumber>|all", out);
}
} else {
_mgr.processClose(closeArg, false, out);
}
} else {
_mgr.error("Usage: close [forced] <jobnumber>|all", out);
}
} else if ("genkey".equalsIgnoreCase(cmd)) {
_mgr.processGenKey(out);
} else if ("list".equalsIgnoreCase(cmd)) {
_mgr.processList(out);
} else if ("listen_on".equalsIgnoreCase(cmd)) {
if (tok.hasMoreTokens()) {
_mgr.processListenOn(tok.nextToken(), out);
} else {
_mgr.error("Usage: listen_on <ip>", out);
}
} else if ("openclient".equalsIgnoreCase(cmd)) {
int listenPort = 0;
String peer = null;
String sharedClient = null;
int numTokens = tok.countTokens();
if (numTokens < 2 || numTokens > 3) {
_mgr.error("Usage: openclient <listenPort> <peer> <sharedClient>", out);
return;
}
try {
listenPort = Integer.parseInt(tok.nextToken());
peer = tok.nextToken();
if (tok.hasMoreTokens())
sharedClient = tok.nextToken();
else
sharedClient = "true";
_mgr.processOpenClient(listenPort, peer, sharedClient, out);
} catch (NumberFormatException nfe) {
_mgr.error("Bad listen port", out);
return;
}
} else if ("openhttpclient".equalsIgnoreCase(cmd)) {
int listenPort = 0;
String proxy = "squid.i2p";
String sharedClient = "true";
int numTokens = tok.countTokens();
if (numTokens < 1 || numTokens > 3) {
_mgr.error("Usage: openhttpclient <listenPort> [<sharedClient>] [<proxy>]", out);
return;
}
try {
listenPort = Integer.parseInt(tok.nextToken());
if (tok.hasMoreTokens()) {
String val = tok.nextToken();
if (tok.hasMoreTokens()) {
sharedClient = val;
proxy = tok.nextToken();
} else {
if ( ("true".equals(val)) || ("false".equals(val)) ) {
sharedClient = val;
} else {
proxy = val;
}
}
}
_mgr.processOpenHTTPClient(listenPort, sharedClient, proxy, out);
} catch (NumberFormatException nfe) {
_mgr.error("Bad listen port", out);
return;
}
} else if ("opensockstunnel".equalsIgnoreCase(cmd)) {
int listenPort = 0;
if (!tok.hasMoreTokens()) {
_mgr.error("Usage: opensockstunnel <listenPort>", out);
return;
}
try {
String portStr = tok.nextToken();
listenPort = Integer.parseInt(portStr);
} catch (NumberFormatException nfe) {
_mgr.error("Bad listen port", out);
return;
}
if (tok.hasMoreTokens()) {
_mgr.error("Usage: opensockstunnel <listenport>", out);
return;
}
_mgr.processOpenSOCKSTunnel(listenPort, out);
} else if ("openserver".equalsIgnoreCase(cmd)) {
int listenPort = 0;
String serverHost = null;
String serverKeys = null;
if (!tok.hasMoreTokens()) {
_mgr.error("Usage: openserver <serverHost> <serverPort> <serverKeys>", out);
return;
}
serverHost = tok.nextToken();
if (!tok.hasMoreTokens()) {
_mgr.error("Usage: openserver <serverHost> <serverPort> <serverKeys>", out);
return;
}
try {
String portStr = tok.nextToken();
listenPort = Integer.parseInt(portStr);
} catch (NumberFormatException nfe) {
_mgr.error("Bad listen port", out);
return;
}
if (!tok.hasMoreTokens()) {
_mgr.error("Usage: openserver <serverHost> <serverPort> <serverKeys>", out);
return;
}
serverKeys = tok.nextToken();
_mgr.processOpenServer(serverHost, listenPort, serverKeys, out);
} else {
_mgr.unknownCommand(command, out);
}
}
}
}

View File

@ -28,7 +28,8 @@ public class ConfigNetHandler extends FormHandler {
private boolean _reseedRequested; private boolean _reseedRequested;
private boolean _saveRequested; private boolean _saveRequested;
private boolean _timeSyncEnabled; private boolean _timeSyncEnabled;
private String _port; private String _tcpPort;
private String _udpPort;
private String _inboundRate; private String _inboundRate;
private String _inboundBurst; private String _inboundBurst;
private String _outboundRate; private String _outboundRate;
@ -56,8 +57,11 @@ public class ConfigNetHandler extends FormHandler {
public void setHostname(String hostname) { public void setHostname(String hostname) {
_hostname = (hostname != null ? hostname.trim() : null); _hostname = (hostname != null ? hostname.trim() : null);
} }
public void setPort(String port) { public void setTcpPort(String port) {
_port = (port != null ? port.trim() : null); _tcpPort = (port != null ? port.trim() : null);
}
public void setUdpPort(String port) {
_udpPort = (port != null ? port.trim() : null);
} }
public void setInboundrate(String rate) { public void setInboundrate(String rate) {
_inboundRate = (rate != null ? rate.trim() : null); _inboundRate = (rate != null ? rate.trim() : null);
@ -207,14 +211,25 @@ public class ConfigNetHandler extends FormHandler {
restartRequired = true; restartRequired = true;
} }
} }
if ( (_port != null) && (_port.length() > 0) ) { if ( (_tcpPort != null) && (_tcpPort.length() > 0) ) {
String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT); String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT);
if ( (oldPort == null) && (_port.equals("8887")) ) { if ( (oldPort == null) && (_tcpPort.equals("8887")) ) {
// still on default.. noop // still on default.. noop
} else if ( (oldPort == null) || (!oldPort.equalsIgnoreCase(_port)) ) { } else if ( (oldPort == null) || (!oldPort.equalsIgnoreCase(_tcpPort)) ) {
// its not the default OR it has changed // its not the default OR it has changed
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT, _port); _context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT, _tcpPort);
addFormNotice("Updating TCP port from " + oldPort + " to " + _port); addFormNotice("Updating TCP port from " + oldPort + " to " + _tcpPort);
restartRequired = true;
}
}
if ( (_udpPort != null) && (_udpPort.length() > 0) ) {
String oldPort = _context.router().getConfigSetting(ConfigNetHelper.PROP_I2NP_UDP_PORT);
if ( (oldPort == null) && (_udpPort.equals("8887")) ) {
// still on default.. noop
} else if ( (oldPort == null) || (!oldPort.equalsIgnoreCase(_udpPort)) ) {
// its not the default OR it has changed
_context.router().setConfigSetting(ConfigNetHelper.PROP_I2NP_TCP_PORT, _udpPort);
addFormNotice("Updating UDP port from " + oldPort + " to " + _udpPort);
restartRequired = true; restartRequired = true;
} }
} }

View File

@ -24,11 +24,13 @@ public class ConfigNetHelper {
/** copied from various private TCP components */ /** copied from various private TCP components */
public final static String PROP_I2NP_TCP_HOSTNAME = "i2np.tcp.hostname"; public final static String PROP_I2NP_TCP_HOSTNAME = "i2np.tcp.hostname";
public final static String PROP_I2NP_TCP_PORT = "i2np.tcp.port"; public final static String PROP_I2NP_TCP_PORT = "i2np.tcp.port";
public final static String PROP_I2NP_UDP_PORT = "i2np.udp.port";
public final static String PROP_I2NP_INTERNAL_UDP_PORT = "i2np.udp.internalPort";
public String getHostname() { public String getHostname() {
return _context.getProperty(PROP_I2NP_TCP_HOSTNAME); return _context.getProperty(PROP_I2NP_TCP_HOSTNAME);
} }
public String getPort() { public String getTcpPort() {
int port = 8887; int port = 8887;
String val = _context.getProperty(PROP_I2NP_TCP_PORT); String val = _context.getProperty(PROP_I2NP_TCP_PORT);
if (val != null) { if (val != null) {
@ -41,6 +43,21 @@ public class ConfigNetHelper {
return "" + port; return "" + port;
} }
public String getUdpPort() {
int port = 8887;
String val = _context.getProperty(PROP_I2NP_UDP_PORT);
if (val == null)
val = _context.getProperty(PROP_I2NP_INTERNAL_UDP_PORT);
if (val != null) {
try {
port = Integer.parseInt(val);
} catch (NumberFormatException nfe) {
// ignore, use default from above
}
}
return "" + port;
}
public String getEnableTimeSyncChecked() { public String getEnableTimeSyncChecked() {
String disabled = _context.getProperty(Timestamper.PROP_DISABLED, "false"); String disabled = _context.getProperty(Timestamper.PROP_DISABLED, "false");
if ( (disabled != null) && ("true".equalsIgnoreCase(disabled)) ) if ( (disabled != null) && ("true".equalsIgnoreCase(disabled)) )

View File

@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import net.i2p.util.Log;
import net.i2p.stat.StatManager; import net.i2p.stat.StatManager;
/** /**
@ -22,6 +23,7 @@ public class ConfigStatsHandler extends FormHandler {
public ConfigStatsHandler() { public ConfigStatsHandler() {
super(); super();
_stats = new ArrayList(); _stats = new ArrayList();
_explicitFilter = false;
} }
protected void processForm() { protected void processForm() {
@ -36,27 +38,14 @@ public class ConfigStatsHandler extends FormHandler {
if (stats != null) { if (stats != null) {
for (int i = 0; i < stats.length; i++) { for (int i = 0; i < stats.length; i++) {
String cur = stats[i].trim(); String cur = stats[i].trim();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Stat: [" + cur + "]");
if ( (cur.length() > 0) && (!_stats.contains(cur)) ) if ( (cur.length() > 0) && (!_stats.contains(cur)) )
_stats.add(cur); _stats.add(cur);
} }
} }
} if (_log.shouldLog(Log.DEBUG))
_log.debug("Updated stats: " + _stats);
public void setStatList(String stat) {
if (stat != null) {
if (stat.indexOf(',') != -1) {
StringTokenizer tok = new StringTokenizer(stat, ",");
while (tok.hasMoreTokens()) {
String cur = tok.nextToken().trim();
if ( (cur.length() > 0) && (!_stats.contains(cur)) )
_stats.add(cur);
}
} else {
stat = stat.trim();
if ( (stat.length() > 0) && (!_stats.contains(stat)) )
_stats.add(stat);
}
}
} }
public void setExplicitFilter(String foo) { _explicitFilter = true; } public void setExplicitFilter(String foo) { _explicitFilter = true; }
@ -74,7 +63,19 @@ public class ConfigStatsHandler extends FormHandler {
if (_explicitFilter) { if (_explicitFilter) {
_stats.clear(); _stats.clear();
setStatList(_explicitFilterValue);
if (_explicitFilterValue.indexOf(',') != -1) {
StringTokenizer tok = new StringTokenizer(_explicitFilterValue, ",");
while (tok.hasMoreTokens()) {
String cur = tok.nextToken().trim();
if ( (cur.length() > 0) && (!_stats.contains(cur)) )
_stats.add(cur);
}
} else {
String stat = _explicitFilterValue.trim();
if ( (stat.length() > 0) && (!_stats.contains(stat)) )
_stats.add(stat);
}
} }
StringBuffer stats = new StringBuffer(); StringBuffer stats = new StringBuffer();

View File

@ -4,6 +4,7 @@ import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import net.i2p.router.RouterContext; import net.i2p.router.RouterContext;
import net.i2p.util.Log;
/** /**
* Simple form handler base class - does not depend on servlets or jsp, * Simple form handler base class - does not depend on servlets or jsp,
@ -16,6 +17,7 @@ import net.i2p.router.RouterContext;
*/ */
public class FormHandler { public class FormHandler {
protected RouterContext _context; protected RouterContext _context;
protected Log _log;
private String _nonce; private String _nonce;
protected String _action; protected String _action;
private List _errors; private List _errors;
@ -41,6 +43,7 @@ public class FormHandler {
public void setContextId(String contextId) { public void setContextId(String contextId) {
try { try {
_context = ContextHelper.getContext(contextId); _context = ContextHelper.getContext(contextId);
_log = _context.logManager().getLog(getClass());
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
} }

View File

@ -28,13 +28,13 @@
<input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce")%>" /> <input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce")%>" />
<input type="hidden" name="action" value="blah" /> <input type="hidden" name="action" value="blah" />
TCP port: UDP port: <i><jsp:getProperty name="nethelper" property="udpPort" /></i><br />
<input name="port" type="text" size="4" value="<jsp:getProperty name="nethelper" property="port" />" /> <br /> <!-- <input name="udpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="udpPort" />" /><br /> -->
<b>You must poke a hole in your firewall or NAT (if applicable) to receive new inbound UDP packets on
this port from arbitrary peers (this requirement will be removed in i2p 0.6.1, but is necessary now)</b><br />
TCP port: <input name="tcpPort" type="text" size="5" value="<jsp:getProperty name="nethelper" property="tcpPort" />" /> <br />
<b>You must poke a hole in your firewall or NAT (if applicable) so that you can receive inbound TCP <b>You must poke a hole in your firewall or NAT (if applicable) so that you can receive inbound TCP
connections on it.</b> Nothing will work if you don't. Sorry. We know how to make it so connections on it (this requirement will be removed in i2p 0.6.1, but is necessary now)</b>
this restriction won't be necessary, but its later on in the
<a href="http://www.i2p.net/roadmap">roadmap</a> and we only have so many coder-hours (but if you want
to help, please <a href="http://www.i2p.net/getinvolved">get involved!</a>)
<hr /> <hr />
<b>Bandwidth limiter</b><br /> <b>Bandwidth limiter</b><br />
@ -57,7 +57,7 @@
packets on port 123 to one of the pool.ntp.org machines (or some other SNTP server).</i> packets on port 123 to one of the pool.ntp.org machines (or some other SNTP server).</i>
<hr /> <hr />
<input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br /> <input type="submit" name="save" value="Save changes" /> <input type="reset" value="Cancel" /><br />
<i>Changing the TCP port will force a 'soft restart' - dropping your connections and clients as <i>Changing the TCP or UDP port will force a 'soft restart' - dropping your connections and clients as
if the router was stopped and restarted. <b>Please be patient</b> - it may take if the router was stopped and restarted. <b>Please be patient</b> - it may take
a few seconds to complete.</i> a few seconds to complete.</i>
</form> </form>
@ -73,6 +73,13 @@
"i2p.reseedURL=someURL" (e.g. java -Di2p.reseedURL=http://dev.i2p.net/i2pdb/ ...). You can "i2p.reseedURL=someURL" (e.g. java -Di2p.reseedURL=http://dev.i2p.net/i2pdb/ ...). You can
also do it manually by getting routerInfo-*.dat files from someone (a friend, someone on IRC, also do it manually by getting routerInfo-*.dat files from someone (a friend, someone on IRC,
whatever) and saving them to your netDb/ directory.</p> whatever) and saving them to your netDb/ directory.</p>
<p>
With the SSU transport, the internal UDP port may be different from the external
UDP port (in case of a firewall/NAT) - the UDP port field above specifies the
external one and assumes they are the same, but if you want to set the internal
port to something else, you can add "i2np.udp.internalPort=1234" to the
<a href="configadvanced.jsp">advanced</a> config and restart the router.
</p>
</div> </div>
</body> </body>

View File

@ -33,7 +33,7 @@ public class ConnectionPacketHandler {
boolean ok = verifyPacket(packet, con); boolean ok = verifyPacket(packet, con);
if (!ok) { if (!ok) {
if ( (!packet.isFlagSet(Packet.FLAG_RESET)) && (_log.shouldLog(Log.ERROR)) ) if ( (!packet.isFlagSet(Packet.FLAG_RESET)) && (_log.shouldLog(Log.ERROR)) )
_log.error("Packet does NOT verify: " + packet); _log.error("Packet does NOT verify: " + packet + " on " + con);
packet.releasePayload(); packet.releasePayload();
return; return;
} }
@ -305,16 +305,16 @@ public class ConnectionPacketHandler {
if (packet.getSequenceNum() <= 2) { if (packet.getSequenceNum() <= 2) {
return true; return true;
} else { } else {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.ERROR))
_log.warn("Packet without RST or SYN where we dont know stream ID: " _log.error("Packet without RST or SYN where we dont know stream ID: "
+ packet); + packet);
return false; return false;
} }
} }
} else { } else {
if (!DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) { if (!DataHelper.eq(con.getSendStreamId(), packet.getReceiveStreamId())) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.ERROR))
_log.warn("Packet received with the wrong reply stream id: " _log.error("Packet received with the wrong reply stream id: "
+ con + " / " + packet); + con + " / " + packet);
return false; return false;
} else { } else {
@ -331,8 +331,8 @@ public class ConnectionPacketHandler {
if (DataHelper.eq(con.getReceiveStreamId(), packet.getSendStreamId())) { if (DataHelper.eq(con.getReceiveStreamId(), packet.getSendStreamId())) {
boolean ok = packet.verifySignature(_context, packet.getOptionalFrom(), null); boolean ok = packet.verifySignature(_context, packet.getOptionalFrom(), null);
if (!ok) { if (!ok) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.ERROR))
_log.warn("Received unsigned / forged RST on " + con); _log.error("Received unsigned / forged RST on " + con);
return; return;
} else { } else {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))

View File

@ -14,8 +14,8 @@ package net.i2p;
* *
*/ */
public class CoreVersion { public class CoreVersion {
public final static String ID = "$Revision: 1.34 $ $Date: 2005/04/06 10:43:26 $"; public final static String ID = "$Revision: 1.35 $ $Date: 2005/04/20 15:14:20 $";
public final static String VERSION = "0.5.0.7"; public final static String VERSION = "0.6";
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION); System.out.println("I2P Core version: " + VERSION);

View File

@ -121,7 +121,7 @@ class I2CPMessageProducer {
* garlic crypto added by the router) * garlic crypto added by the router)
* *
*/ */
static final boolean END_TO_END_CRYPTO = true; static final boolean END_TO_END_CRYPTO = false;
/** /**
* Create a new signed payload and send it off to the destination * Create a new signed payload and send it off to the destination

View File

@ -260,7 +260,10 @@ public class DHSessionKeyBuilder {
* *
*/ */
public byte[] getMyPublicValueBytes() { public byte[] getMyPublicValueBytes() {
BigInteger bi = getMyPublicValue(); return toByteArray(getMyPublicValue());
}
private static final byte[] toByteArray(BigInteger bi) {
byte data[] = bi.toByteArray(); byte data[] = bi.toByteArray();
byte rv[] = new byte[256]; byte rv[] = new byte[256];
if (data.length == 257) // high byte has the sign bit if (data.length == 257) // high byte has the sign bit
@ -299,6 +302,9 @@ public class DHSessionKeyBuilder {
public BigInteger getPeerPublicValue() { public BigInteger getPeerPublicValue() {
return _peerValue; return _peerValue;
} }
public byte[] getPeerPublicValueBytes() {
return toByteArray(getPeerPublicValue());
}
/** /**
* Retrieve the session key, calculating it if necessary (and if possible). * Retrieve the session key, calculating it if necessary (and if possible).

View File

@ -25,9 +25,13 @@ public class DHSessionKeyBuilderTest extends TestCase {
DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder(); DHSessionKeyBuilder builder1 = new DHSessionKeyBuilder();
DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder(); DHSessionKeyBuilder builder2 = new DHSessionKeyBuilder();
BigInteger pub1 = builder1.getMyPublicValue(); BigInteger pub1 = builder1.getMyPublicValue();
builder2.setPeerPublicValue(pub1);
BigInteger pub2 = builder2.getMyPublicValue(); BigInteger pub2 = builder2.getMyPublicValue();
try {
builder2.setPeerPublicValue(pub1);
builder1.setPeerPublicValue(pub2); builder1.setPeerPublicValue(pub2);
} catch (DHSessionKeyBuilder.InvalidPublicParameterException ippe) {
assertTrue(ippe.getMessage(), true);
}
SessionKey key1 = builder1.getSessionKey(); SessionKey key1 = builder1.getSessionKey();
SessionKey key2 = builder2.getSessionKey(); SessionKey key2 = builder2.getSessionKey();

View File

@ -30,9 +30,9 @@ import net.i2p.util.Log;
public class MessagePayloadMessageTest extends StructureTest { public class MessagePayloadMessageTest extends StructureTest {
public DataStructure createDataStructure() throws DataFormatException { public DataStructure createDataStructure() throws DataFormatException {
MessagePayloadMessage msg = new MessagePayloadMessage(); MessagePayloadMessage msg = new MessagePayloadMessage();
msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure()); msg.setMessageId(123);
msg.setPayload((Payload)(new PayloadTest()).createDataStructure()); msg.setPayload((Payload)(new PayloadTest()).createDataStructure());
msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure()); msg.setSessionId(321);
return msg; return msg;
} }
public DataStructure createStructureToRead() { return new MessagePayloadMessage(); } public DataStructure createStructureToRead() { return new MessagePayloadMessage(); }

View File

@ -22,8 +22,8 @@ import net.i2p.data.i2cp.SessionId;
public class MessageStatusMessageTest extends StructureTest { public class MessageStatusMessageTest extends StructureTest {
public DataStructure createDataStructure() throws DataFormatException { public DataStructure createDataStructure() throws DataFormatException {
MessageStatusMessage msg = new MessageStatusMessage(); MessageStatusMessage msg = new MessageStatusMessage();
msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure()); msg.setSessionId(42);
msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure()); msg.setMessageId(41);
msg.setSize(1024*1024*42L); msg.setSize(1024*1024*42L);
msg.setStatus(MessageStatusMessage.STATUS_AVAILABLE); msg.setStatus(MessageStatusMessage.STATUS_AVAILABLE);
msg.setNonce(1); msg.setNonce(1);

View File

@ -22,8 +22,8 @@ import net.i2p.data.i2cp.SessionId;
public class ReceiveMessageBeginMessageTest extends StructureTest { public class ReceiveMessageBeginMessageTest extends StructureTest {
public DataStructure createDataStructure() throws DataFormatException { public DataStructure createDataStructure() throws DataFormatException {
ReceiveMessageBeginMessage msg = new ReceiveMessageBeginMessage(); ReceiveMessageBeginMessage msg = new ReceiveMessageBeginMessage();
msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure()); msg.setSessionId(321);
msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure()); msg.setMessageId(123);
return msg; return msg;
} }
public DataStructure createStructureToRead() { return new ReceiveMessageBeginMessage(); } public DataStructure createStructureToRead() { return new ReceiveMessageBeginMessage(); }

View File

@ -22,8 +22,8 @@ import net.i2p.data.i2cp.SessionId;
public class ReceiveMessageEndMessageTest extends StructureTest { public class ReceiveMessageEndMessageTest extends StructureTest {
public DataStructure createDataStructure() throws DataFormatException { public DataStructure createDataStructure() throws DataFormatException {
ReceiveMessageEndMessage msg = new ReceiveMessageEndMessage(); ReceiveMessageEndMessage msg = new ReceiveMessageEndMessage();
msg.setSessionId((SessionId)(new SessionIdTest()).createDataStructure()); msg.setSessionId(321);
msg.setMessageId((MessageId)(new MessageIdTest()).createDataStructure()); msg.setMessageId(123);
return msg; return msg;
} }
public DataStructure createStructureToRead() { return new ReceiveMessageEndMessage(); } public DataStructure createStructureToRead() { return new ReceiveMessageEndMessage(); }

View File

@ -1,4 +1,23 @@
$Id: history.txt,v 1.216 2005/07/21 17:37:16 jrandom Exp $ $Id: history.txt,v 1.217 2005/07/22 19:15:59 jrandom Exp $
* 2005-07-27 0.6 released
2005-07-27 jrandom
* Enabled SSU as the default top priority transport, adjusting the
config.jsp page accordingly.
* Add verification fields to the SSU and TCP connection negotiation (not
compatible with previous builds)
* Enable the backwards incompatible tunnel crypto change as documented in
tunnel-alt.html (have each hop encrypt the received IV before using it,
then encrypt it again before sending it on)
* Disable the I2CP encryption, leaving in place the end to end garlic
encryption (another backwards incompatible change)
* Adjust the protocol versions on the TCP and SSU transports so that they
won't talk to older routers.
* Fix up the config stats handling again
* Fix a rare off-by-one in the SSU fragmentation
* Reduce some unnecessary netDb resending by inluding the peers queried
successfully in the store redundancy count.
2005-07-22 jrandom 2005-07-22 jrandom
* Use the small thread pool for I2PTunnelHTTPServer (already used for * Use the small thread pool for I2PTunnelHTTPServer (already used for

View File

@ -1,12 +1,12 @@
<i2p.news date="$Date: 2005/04/06 10:43:25 $"> <i2p.news date="$Date: 2005/04/20 15:14:18 $">
<i2p.release version="0.5.0.7" date="2005/04/20" minVersion="0.5.0.4" <i2p.release version="0.6" date="2005/07/27" minVersion="0.6"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud" anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud" publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/April-2005/000709.html" anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/April-2005/000709.html"
publicannouncement="http://dev.i2p.net/pipermail/i2p/April-2005/000709.html" /> publicannouncement="http://dev.i2p.net/pipermail/i2p/April-2005/000709.html" />
<i2p.notes date="2005/04/19" <i2p.notes date="2005/07/26"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/April-2005/000708.html" anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-July/000823.html"
publicurl="http://dev.i2p.net/pipermail/i2p/April-2005/000708.html" publicurl="http://dev.i2p.net/pipermail/i2p/2005-July/000823.html"
anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting138" anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting138"
publiclogs="http://www.i2p.net/meeting138" /> publiclogs="http://www.i2p.net/meeting138" />
<h1>Congratulations on getting I2P installed!</h1> <h1>Congratulations on getting I2P installed!</h1>

View File

@ -4,7 +4,7 @@
<info> <info>
<appname>i2p</appname> <appname>i2p</appname>
<appversion>0.5.0.7</appversion> <appversion>0.6</appversion>
<authors> <authors>
<author name="I2P" email="support@i2p.net"/> <author name="I2P" email="support@i2p.net"/>
</authors> </authors>

View File

@ -1,20 +1,15 @@
<i2p.news date="$Date: 2005/07/11 22:56:42 $"> <i2p.news date="$Date: 2005/07/13 16:59:01 $">
<i2p.release version="0.5.0.7" date="2005/04/20" minVersion="0.5.0.4" <i2p.release version="0.7" date="2005/07/27" minVersion="0.6"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud" anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/i2p/i2pupdate.sud"
publicurl="http://dev.i2p.net/i2p/i2pupdate.sud" publicurl="http://dev.i2p.net/i2p/i2pupdate.sud"
anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-April/000709.html" anonannouncement="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-April/000709.html"
publicannouncement="http://dev.i2p.net/pipermail/i2p/2005-April/000709.html" /> publicannouncement="http://dev.i2p.net/pipermail/i2p/2005-April/000709.html" />
<i2p.notes date="2005/04/19" <i2p.notes date="2005/04/19"
anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-April/000723.html" anonurl="http://i2p/NF2RLVUxVulR3IqK0sGJR0dHQcGXAzwa6rEO4WAWYXOHw-DoZhKnlbf1nzHXwMEJoex5nFTyiNMqxJMWlY54cvU~UenZdkyQQeUSBZXyuSweflUXFqKN-y8xIoK2w9Ylq1k8IcrAFDsITyOzjUKoOPfVq34rKNDo7fYyis4kT5bAHy~2N1EVMs34pi2RFabATIOBk38Qhab57Umpa6yEoE~rbyR~suDRvD7gjBvBiIKFqhFueXsR2uSrPB-yzwAGofTXuklofK3DdKspciclTVzqbDjsk5UXfu2nTrC1agkhLyqlOfjhyqC~t1IXm-Vs2o7911k7KKLGjB4lmH508YJ7G9fLAUyjuB-wwwhejoWqvg7oWvqo4oIok8LG6ECR71C3dzCvIjY2QcrhoaazA9G4zcGMm6NKND-H4XY6tUWhpB~5GefB3YczOqMbHq4wi0O9MzBFrOJEOs3X4hwboKWANf7DT5PZKJZ5KorQPsYRSq0E3wSOsFCSsdVCKUGsAAAA/pipermail/i2p/2005-July/000823.html"
publicurl="http://dev.i2p.net/pipermail/i2p/2005-April/000723.html" publicurl="http://dev.i2p.net/pipermail/i2p/2005-July/000823.html"
anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting139" anonlogs="http://i2p/Nf3ab-ZFkmI-LyMt7GjgT-jfvZ3zKDl0L96pmGQXF1B82W2Bfjf0n7~288vafocjFLnQnVcmZd~-p0-Oolfo9aW2Rm-AhyqxnxyLlPBqGxsJBXjPhm1JBT4Ia8FB-VXt0BuY0fMKdAfWwN61-tj4zIcQWRxv3DFquwEf035K~Ra4SWOqiuJgTRJu7~o~DzHVljVgWIzwf8Z84cz0X33pv-mdG~~y0Bsc2qJVnYwjjR178YMcRSmNE0FVMcs6f17c6zqhMw-11qjKpY~EJfHYCx4lBWF37CD0obbWqTNUIbL~78vxqZRT3dgAgnLixog9nqTO-0Rh~NpVUZnoUi7fNR~awW5U3Cf7rU7nNEKKobLue78hjvRcWn7upHUF45QqTDuaM3yZa7OsjbcH-I909DOub2Q0Dno6vIwuA7yrysccN1sbnkwZbKlf4T6~iDdhaSLJd97QCyPOlbyUfYy9QLNExlRqKgNVJcMJRrIual~Lb1CLbnzt0uvobM57UpqSAAAA/meeting139"
publiclogs="http://www.i2p.net/meeting138" /> publiclogs="http://www.i2p.net/meeting138" />
Thanks to those helping out with the SSU test - there have been lots Welcome to the new 0.6 series of releases, using the new SSU transport!
of updates lately, so upgrading to the latest CVS HEAD (currently
0.5.0.7-14 as of 2005/07/13) would be worthwhile, and the archived
i2pupdate.zip mentioned
<a href="http://dev.i2p.net/~jrandom/ssu_test.txt">before</a>
may not always be up to date.
<br /> <br />
</i2p.news> </i2p.news>

View File

@ -15,11 +15,10 @@ listed (if not, <a href="#trouble">see below</a>). Once those are up, you can:<
<li><a href="http://duck.i2p/">duck.i2p</a>: duck's eepsite, with links to other active sites</li> <li><a href="http://duck.i2p/">duck.i2p</a>: duck's eepsite, with links to other active sites</li>
<li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li> <li><a href="http://ugha.i2p/">ugha.i2p</a>: ugha's eepsite, a wiki that anyone can edit, and lots of links</li>
<li><a href="http://orion.i2p/">orion.i2p</a>: a site which tracks eepsite uptime and changes</li> <li><a href="http://orion.i2p/">orion.i2p</a>: a site which tracks eepsite uptime and changes</li>
<li><a href="http://files.i2p/">files.i2p</a>: a search engine that tries to keep track of things on I2P</li>
<li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li> <li><a href="http://forum.i2p/">forum.i2p</a>: a secure and anonymous connection to <a href="http://forum.i2p.net/">forum.i2p.net</a></li>
<li><a href="http://www.i2p/">www.i2p</a>: a secure and anonymous connection to <a href="http://www.i2p.net/">www.i2p.net</a></li> <li><a href="http://www.i2p/">www.i2p</a>: a secure and anonymous connection to <a href="http://www.i2p.net/">www.i2p.net</a></li>
<li><a href="http://dev.i2p/">dev.i2p</a>: a secure and anonymous connection to <a href="http://dev.i2p.net/">dev.i2p.net</a></li> <li><a href="http://dev.i2p/">dev.i2p</a>: a secure and anonymous connection to <a href="http://dev.i2p.net/">dev.i2p.net</a></li>
<li>Freenet proxies: <a href="http://fproxy.i2p/">fproxy.i2p</a> and <a href="http://freenet.eco.i2p/">freenet.eco.i2p</a></li> <li>Freenet proxies: <a href="http://fproxy.i2p/">fproxy.i2p</a></li>
</ul> </ul>
There are many more eepsites - just follow the links from the ones you see, There are many more eepsites - just follow the links from the ones you see,
bookmark your favorites, and visit them often!</li> bookmark your favorites, and visit them often!</li>
@ -56,7 +55,7 @@ IRC (be sure to split it into two lines, as its too long for one).</p>
<p>If the left hand side has a warning, telling you to check your NAT or firewall, please <p>If the left hand side has a warning, telling you to check your NAT or firewall, please
see the <a href="/config.jsp">config page</a> and make sure that you can receive <b>inbound see the <a href="/config.jsp">config page</a> and make sure that you can receive <b>inbound
TCP connections on port 8887</b> (or another port that you specify). Problems forwarding TCP and UDP connections on port 8887</b> (or another port that you specify). Problems forwarding
that port account for the vast majority of issues people run into. When it says that port account for the vast majority of issues people run into. When it says
"Active: 72/85", the "72" means how many peers you are connected with now, and "85" means "Active: 72/85", the "72" means how many peers you are connected with now, and "85" means
how many you have spoken with recently - if that first number is 0, you can bet that there how many you have spoken with recently - if that first number is 0, you can bet that there

View File

@ -1,4 +1,4 @@
<code>$Id: tunnel-alt.html,v 1.7 2005/02/16 19:48:18 jrandom Exp $</code> <code>$Id: tunnel-alt.html,v 1.8 2005/07/07 16:16:57 jrandom Exp $</code>
<pre> <pre>
1) <a href="#tunnel.overview">Tunnel overview</a> 1) <a href="#tunnel.overview">Tunnel overview</a>
2) <a href="#tunnel.operation">Tunnel operation</a> 2) <a href="#tunnel.operation">Tunnel operation</a>
@ -173,9 +173,12 @@ the initial preprocessed data.</p>
the same previous hop as before (initialized when the first message comes through the same previous hop as before (initialized when the first message comes through
the tunnel). If the previous peer is a different router, or if the message has the tunnel). If the previous peer is a different router, or if the message has
already been seen, the message is dropped. The participant then encrypts the already been seen, the message is dropped. The participant then encrypts the
data with AES256/CBC using the participant's layer key and the received IV, received IV with AES256/ECB using their IV key to determine the current IV, uses
updates the IV by encrypting it with AES256/ECB using the participant's IV key, that IV with the participant's layer key to encrypt the data, encrypts the
then forwards the tuple {nextTunnelId, nextIV, encryptedData} to the next hop.</p> current IV with AES256/ECB using their IV key again, then forwards the tuple
{nextTunnelId, nextIV, encryptedData} to the next hop. This double encryption
of the IV (both before and after use) help address a certain class of
confirmation attacks.</p>
<p>Duplicate message detection is handled by a decaying Bloom filter on message <p>Duplicate message detection is handled by a decaying Bloom filter on message
IVs. Each router maintains a single Bloom filter to contain the XOR of the IV and IVs. Each router maintains a single Bloom filter to contain the XOR of the IV and

View File

@ -1,4 +1,4 @@
<code>$Id: udp.html,v 1.12 2005/04/09 18:15:53 jrandom Exp $</code> <code>$Id: udp.html,v 1.13 2005/05/01 15:08:08 jrandom Exp $</code>
<h1>Secure Semireliable UDP (SSU)</h1> <h1>Secure Semireliable UDP (SSU)</h1>
<b>DRAFT</b> <b>DRAFT</b>
@ -141,7 +141,7 @@ around briefly, to address packet loss and reordering.</p>
<li>4 byte timestamp (seconds from the epoch) for use in the DSA <li>4 byte timestamp (seconds from the epoch) for use in the DSA
signature</li> signature</li>
<li>40 byte DSA signature of the critical exchanged data <li>40 byte DSA signature of the critical exchanged data
(Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's (X + Y + Alice's IP + Alice's port + Bob's IP + Bob's port + Alice's
new relay tag + Bob's signed on time), encrypted with another new relay tag + Bob's signed on time), encrypted with another
layer of encryption using the negotiated sessionKey. The IV layer of encryption using the negotiated sessionKey. The IV
is reused here.</li> is reused here.</li>
@ -197,7 +197,7 @@ bits 4-7: total identity fragments</pre></li>
<li>on the last identity fragment, the signed on time is <li>on the last identity fragment, the signed on time is
included after the identity fragment, and the last 40 included after the identity fragment, and the last 40
bytes contain the DSA signature of the critical exchanged bytes contain the DSA signature of the critical exchanged
data (Alice's IP + Alice's port + Bob's IP + Bob's port data (X + Y + Alice's IP + Alice's port + Bob's IP + Bob's port
+ Alice's new relay key + Alice's signed on time)</li> + Alice's new relay key + Alice's signed on time)</li>
</ul></td></tr> </ul></td></tr>
<tr><td align="right" valign="top"><b>Key used:</b></td> <tr><td align="right" valign="top"><b>Key used:</b></td>

View File

@ -15,9 +15,9 @@ import net.i2p.CoreVersion;
* *
*/ */
public class RouterVersion { public class RouterVersion {
public final static String ID = "$Revision: 1.207 $ $Date: 2005/07/21 17:37:15 $"; public final static String ID = "$Revision: 1.208 $ $Date: 2005/07/22 19:15:58 $";
public final static String VERSION = "0.5.0.7"; public final static String VERSION = "0.6";
public final static long BUILD = 19; public final static long BUILD = 0;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + VERSION); System.out.println("I2P Router version: " + VERSION);
System.out.println("Router ID: " + RouterVersion.ID); System.out.println("Router ID: " + RouterVersion.ID);

View File

@ -102,12 +102,12 @@ public class StatisticsManager implements Service {
stats.putAll(_context.profileManager().summarizePeers(_publishedStats)); stats.putAll(_context.profileManager().summarizePeers(_publishedStats));
includeThroughput(stats); includeThroughput(stats);
includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 }); //includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 });
includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 }); includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 });
includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 }); //includeRate("tunnel.duplicateIV", stats, new long[] { 24*60*60*1000 });
includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 }); includeRate("tunnel.fragmentedDropped", stats, new long[] { 10*60*1000, 3*60*60*1000 });
includeRate("tunnel.fullFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 }); //includeRate("tunnel.fullFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
includeRate("tunnel.smallFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 }); //includeRate("tunnel.smallFragments", stats, new long[] { 10*60*1000, 3*60*60*1000 });
includeRate("tunnel.testFailedTime", stats, new long[] { 60*60*1000 }); includeRate("tunnel.testFailedTime", stats, new long[] { 60*60*1000 });
includeRate("tunnel.buildFailure", stats, new long[] { 60*60*1000 }); includeRate("tunnel.buildFailure", stats, new long[] { 60*60*1000 });
@ -117,22 +117,26 @@ public class StatisticsManager implements Service {
includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 }); includeRate("tunnel.batchMultipleCount", stats, new long[] { 10*60*1000, 60*60*1000 });
includeRate("tunnel.corruptMessage", stats, new long[] { 60*60*1000l, 3*60*60*1000l }); includeRate("tunnel.corruptMessage", stats, new long[] { 60*60*1000l, 3*60*60*1000l });
includeRate("router.throttleTunnelProbTestSlow", stats, new long[] { 60*60*1000 }); //includeRate("router.throttleTunnelProbTestSlow", stats, new long[] { 60*60*1000 });
includeRate("router.throttleTunnelProbTooFast", stats, new long[] { 60*60*1000 }); //includeRate("router.throttleTunnelProbTooFast", stats, new long[] { 60*60*1000 });
includeRate("router.throttleTunnelProcessingTime1m", stats, new long[] { 60*60*1000 }); //includeRate("router.throttleTunnelProcessingTime1m", stats, new long[] { 60*60*1000 });
includeRate("router.fastPeers", stats, new long[] { 60*60*1000 }); includeRate("router.fastPeers", stats, new long[] { 60*60*1000 });
includeRate("clock.skew", stats, new long[] { 10*60*1000, 3*60*60*1000, 24*60*60*1000 }); includeRate("clock.skew", stats, new long[] { 10*60*1000, 3*60*60*1000, 24*60*60*1000 });
includeRate("transport.sendProcessingTime", stats, new long[] { 60*60*1000 }); //includeRate("transport.sendProcessingTime", stats, new long[] { 60*60*1000 });
includeRate("jobQueue.jobRunSlow", stats, new long[] { 10*60*1000l, 60*60*1000l }); //includeRate("jobQueue.jobRunSlow", stats, new long[] { 10*60*1000l, 60*60*1000l });
includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*60*1000 }); includeRate("crypto.elGamal.encrypt", stats, new long[] { 60*60*1000 });
includeRate("tunnel.participatingTunnels", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("tunnel.participatingTunnels", stats, new long[] { 5*60*1000, 60*60*1000 });
includeRate("tunnel.testSuccessTime", stats, new long[] { 60*60*1000l, 24*60*60*1000l }); includeRate("tunnel.testSuccessTime", stats, new long[] { 60*60*1000l, 24*60*60*1000l });
includeRate("client.sendAckTime", stats, new long[] { 60*60*1000 }, true); includeRate("client.sendAckTime", stats, new long[] { 60*60*1000 }, true);
includeRate("stream.con.sendDuplicateSize", stats, new long[] { 60*60*1000 }); includeRate("udp.sendConfirmTime", stats, new long[] { 10*60*1000 });
includeRate("stream.con.receiveDuplicateSize", stats, new long[] { 60*60*1000 }); includeRate("udp.sendVolleyTime", stats, new long[] { 10*60*1000 });
includeRate("udp.ignoreRecentDuplicate", stats, new long[] { 10*60*1000 });
includeRate("udp.congestionOccurred", stats, new long[] { 10*60*1000 });
//includeRate("stream.con.sendDuplicateSize", stats, new long[] { 60*60*1000 });
//includeRate("stream.con.receiveDuplicateSize", stats, new long[] { 60*60*1000 });
stats.setProperty("stat_uptime", DataHelper.formatDuration(_context.router().getUptime())); stats.setProperty("stat_uptime", DataHelper.formatDuration(_context.router().getUptime()));
stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]"); stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
_log.debug("Publishing peer rankings"); _log.debug("Publishing peer rankings");

View File

@ -281,7 +281,7 @@ class StoreJob extends JobImpl {
getContext().profileManager().dbStoreSent(_peer.getIdentity().getHash(), howLong); getContext().profileManager().dbStoreSent(_peer.getIdentity().getHash(), howLong);
getContext().statManager().addRateData("netDb.ackTime", howLong, howLong); getContext().statManager().addRateData("netDb.ackTime", howLong, howLong);
if (_state.getSuccessful().size() >= REDUNDANCY) { if (_state.getCompleteCount() >= REDUNDANCY) {
succeed(); succeed();
} else { } else {
sendNext(); sendNext();

View File

@ -21,6 +21,7 @@ class StoreState {
private HashSet _successfulExploratoryPeers; private HashSet _successfulExploratoryPeers;
private HashSet _failedPeers; private HashSet _failedPeers;
private HashSet _attemptedPeers; private HashSet _attemptedPeers;
private int _completeCount;
private volatile long _completed; private volatile long _completed;
private volatile long _started; private volatile long _started;
@ -34,8 +35,10 @@ class StoreState {
_pendingPeers = new HashSet(16); _pendingPeers = new HashSet(16);
_pendingPeerTimes = new HashMap(16); _pendingPeerTimes = new HashMap(16);
_attemptedPeers = new HashSet(16); _attemptedPeers = new HashSet(16);
if (toSkip != null) if (toSkip != null) {
_attemptedPeers.addAll(toSkip); _attemptedPeers.addAll(toSkip);
_completeCount = toSkip.size();
}
_failedPeers = new HashSet(16); _failedPeers = new HashSet(16);
_successfulPeers = new HashSet(16); _successfulPeers = new HashSet(16);
_successfulExploratoryPeers = new HashSet(16); _successfulExploratoryPeers = new HashSet(16);
@ -75,6 +78,7 @@ class StoreState {
if (completed) if (completed)
_completed = _context.clock().now(); _completed = _context.clock().now();
} }
public int getCompleteCount() { return _completeCount; }
public long getWhenStarted() { return _started; } public long getWhenStarted() { return _started; }
public long getWhenCompleted() { return _completed; } public long getWhenCompleted() { return _completed; }
@ -110,6 +114,7 @@ class StoreState {
synchronized (_successfulPeers) { synchronized (_successfulPeers) {
_successfulPeers.add(peer); _successfulPeers.add(peer);
} }
_completeCount++;
return rv; return rv;
} }

View File

@ -34,6 +34,7 @@ public class TransportManager implements TransportEventListener {
private final static String PROP_DISABLE_TCP = "i2np.tcp.disable"; private final static String PROP_DISABLE_TCP = "i2np.tcp.disable";
private final static String PROP_ENABLE_UDP = "i2np.udp.enable"; private final static String PROP_ENABLE_UDP = "i2np.udp.enable";
private static final String DEFAULT_ENABLE_UDP = "true";
public TransportManager(RouterContext context) { public TransportManager(RouterContext context) {
_context = context; _context = context;
@ -63,7 +64,9 @@ public class TransportManager implements TransportEventListener {
_transports.add(t); _transports.add(t);
} }
String enableUDP = _context.router().getConfigSetting(PROP_ENABLE_UDP); String enableUDP = _context.router().getConfigSetting(PROP_ENABLE_UDP);
if ( (enableUDP != null) && (Boolean.valueOf(enableUDP).booleanValue())) { if (enableUDP == null)
enableUDP = DEFAULT_ENABLE_UDP;
if ("true".equalsIgnoreCase(enableUDP)) {
UDPTransport udp = new UDPTransport(_context); UDPTransport udp = new UDPTransport(_context);
udp.setListener(this); udp.setListener(this);
_transports.add(udp); _transports.add(udp);

View File

@ -529,8 +529,12 @@ public class ConnectionBuilder {
return false; return false;
} }
// our public == X, since we are establishing the connection
byte X[] = builder.getMyPublicValueBytes();
byte Y[] = builder.getPeerPublicValueBytes();
// send: routerInfo + currentTime // send: routerInfo + currentTime
// + S(routerInfo + currentTime + nonce + nextTag, routerIdent.signingKey) // + S(routerInfo + currentTime + nonce + nextTag + X + Y, routerIdent.signingKey)
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(512); ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
_context.router().getRouterInfo().writeBytes(baos); _context.router().getRouterInfo().writeBytes(baos);
@ -540,6 +544,8 @@ public class ConnectionBuilder {
baos.write(_nonce.getData()); baos.write(_nonce.getData());
baos.write(_nextConnectionTag.getData()); baos.write(_nextConnectionTag.getData());
baos.write(X);
baos.write(Y);
Signature sig = _context.dsa().sign(baos.toByteArray(), Signature sig = _context.dsa().sign(baos.toByteArray(),
_context.keyManager().getSigningPrivateKey()); _context.keyManager().getSigningPrivateKey());
@ -556,7 +562,7 @@ public class ConnectionBuilder {
} }
// read: routerInfo + status + properties // read: routerInfo + status + properties
// + S(routerInfo + status + properties + nonce + nextTag, routerIdent.signingKey) // + S(routerInfo + status + properties + nonce + nextTag + X + Y, routerIdent.signingKey)
try { try {
RouterInfo peer = new RouterInfo(); RouterInfo peer = new RouterInfo();
peer.readBytes(_rawIn); peer.readBytes(_rawIn);
@ -578,6 +584,8 @@ public class ConnectionBuilder {
DataHelper.writeProperties(baos, props); DataHelper.writeProperties(baos, props);
baos.write(_nonce.getData()); baos.write(_nonce.getData());
baos.write(_nextConnectionTag.getData()); baos.write(_nextConnectionTag.getData());
baos.write(X);
baos.write(Y);
ok = _context.dsa().verifySignature(sig, baos.toByteArray(), ok = _context.dsa().verifySignature(sig, baos.toByteArray(),
peer.getIdentity().getSigningPublicKey()); peer.getIdentity().getSigningPublicKey());

View File

@ -555,8 +555,12 @@ public class ConnectionHandler {
long clockSkew = 0; long clockSkew = 0;
boolean sigOk = false; boolean sigOk = false;
// our public == Y, since we are receiving the connection
byte X[] = builder.getPeerPublicValueBytes();
byte Y[] = builder.getMyPublicValueBytes();
// read: routerInfo + currentTime // read: routerInfo + currentTime
// + S(routerInfo + currentTime + nonce + nextTag, routerIdent.signingKey) // + S(routerInfo + currentTime + nonce + nextTag + X + Y, routerIdent.signingKey)
try { try {
RouterInfo info = new RouterInfo(); RouterInfo info = new RouterInfo();
info.readBytes(_rawIn); info.readBytes(_rawIn);
@ -569,6 +573,8 @@ public class ConnectionHandler {
DataHelper.writeDate(baos, now); DataHelper.writeDate(baos, now);
baos.write(_nonce.getData()); baos.write(_nonce.getData());
baos.write(_nextConnectionTag.getData()); baos.write(_nextConnectionTag.getData());
baos.write(X);
baos.write(Y);
sigOk = _context.dsa().verifySignature(sig, baos.toByteArray(), sigOk = _context.dsa().verifySignature(sig, baos.toByteArray(),
info.getIdentity().getSigningPublicKey()); info.getIdentity().getSigningPublicKey());
@ -589,7 +595,7 @@ public class ConnectionHandler {
boolean reachable = verifyReachability(); boolean reachable = verifyReachability();
// send: routerInfo + status + properties // send: routerInfo + status + properties
// + S(routerInfo + status + properties + nonce + nextTag, routerIdent.signingKey) // + S(routerInfo + status + properties + nonce + nextTag + X + Y, routerIdent.signingKey)
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(512); ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
_context.router().getRouterInfo().writeBytes(baos); _context.router().getRouterInfo().writeBytes(baos);
@ -629,6 +635,8 @@ public class ConnectionHandler {
baos.write(_nonce.getData()); baos.write(_nonce.getData());
baos.write(_nextConnectionTag.getData()); baos.write(_nextConnectionTag.getData());
baos.write(X);
baos.write(Y);
Signature sig = _context.dsa().sign(baos.toByteArray(), Signature sig = _context.dsa().sign(baos.toByteArray(),
_context.keyManager().getSigningPrivateKey()); _context.keyManager().getSigningPrivateKey());

View File

@ -89,7 +89,7 @@ public class TCPTransport extends TransportImpl {
public static final int DEFAULT_ESTABLISHERS = 3; public static final int DEFAULT_ESTABLISHERS = 3;
/** Ordered list of supported I2NP protocols */ /** Ordered list of supported I2NP protocols */
public static final int[] SUPPORTED_PROTOCOLS = new int[] { 4 }; // drop <= 0.5.0.3 public static final int[] SUPPORTED_PROTOCOLS = new int[] { 5 }; // drop < 0.6
/** blah, people shouldnt use defaults... */ /** blah, people shouldnt use defaults... */
public static final int DEFAULT_LISTEN_PORT = 8887; public static final int DEFAULT_LISTEN_PORT = 8887;

View File

@ -98,6 +98,7 @@ public class ACKSender implements Runnable {
if ( (ackBitfields != null) && (ackBitfields.size() > 0) ) { if ( (ackBitfields != null) && (ackBitfields.size() > 0) ) {
_context.statManager().addRateData("udp.sendACKCount", ackBitfields.size(), 0); _context.statManager().addRateData("udp.sendACKCount", ackBitfields.size(), 0);
if (remaining > 0)
_context.statManager().addRateData("udp.sendACKRemaining", remaining, 0); _context.statManager().addRateData("udp.sendACKRemaining", remaining, 0);
now = _context.clock().now(); now = _context.clock().now();
if (lastSend < 0) if (lastSend < 0)

View File

@ -63,8 +63,7 @@ public class EstablishmentManager {
/** /**
* Grab the active establishing state * Grab the active establishing state
*/ */
InboundEstablishState getInboundState(InetAddress fromHost, int fromPort) { InboundEstablishState getInboundState(RemoteHostId from) {
RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
synchronized (_inboundStates) { synchronized (_inboundStates) {
InboundEstablishState state = (InboundEstablishState)_inboundStates.get(from); InboundEstablishState state = (InboundEstablishState)_inboundStates.get(from);
if ( (state == null) && (_log.shouldLog(Log.DEBUG)) ) if ( (state == null) && (_log.shouldLog(Log.DEBUG)) )
@ -73,8 +72,7 @@ public class EstablishmentManager {
} }
} }
OutboundEstablishState getOutboundState(InetAddress fromHost, int fromPort) { OutboundEstablishState getOutboundState(RemoteHostId from) {
RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
synchronized (_outboundStates) { synchronized (_outboundStates) {
OutboundEstablishState state = (OutboundEstablishState)_outboundStates.get(from); OutboundEstablishState state = (OutboundEstablishState)_outboundStates.get(from);
if ( (state == null) && (_log.shouldLog(Log.DEBUG)) ) if ( (state == null) && (_log.shouldLog(Log.DEBUG)) )
@ -121,12 +119,12 @@ public class EstablishmentManager {
* Got a SessionRequest (initiates an inbound establishment) * Got a SessionRequest (initiates an inbound establishment)
* *
*/ */
void receiveSessionRequest(RemoteHostId from, InetAddress host, int port, UDPPacketReader reader) { void receiveSessionRequest(RemoteHostId from, UDPPacketReader reader) {
InboundEstablishState state = null; InboundEstablishState state = null;
synchronized (_inboundStates) { synchronized (_inboundStates) {
state = (InboundEstablishState)_inboundStates.get(from); state = (InboundEstablishState)_inboundStates.get(from);
if (state == null) { if (state == null) {
state = new InboundEstablishState(_context, host, port, _transport.getLocalPort()); state = new InboundEstablishState(_context, from.getIP(), from.getPort(), _transport.getLocalPort());
_inboundStates.put(from, state); _inboundStates.put(from, state);
} }
} }

View File

@ -66,10 +66,10 @@ public class InboundEstablishState {
/** we have completely received all of the confirmation packets */ /** we have completely received all of the confirmation packets */
public static final int STATE_CONFIRMED_COMPLETELY = 4; public static final int STATE_CONFIRMED_COMPLETELY = 4;
public InboundEstablishState(RouterContext ctx, InetAddress remoteHost, int remotePort, int localPort) { public InboundEstablishState(RouterContext ctx, byte remoteIP[], int remotePort, int localPort) {
_context = ctx; _context = ctx;
_log = ctx.logManager().getLog(InboundEstablishState.class); _log = ctx.logManager().getLog(InboundEstablishState.class);
_aliceIP = remoteHost.getAddress(); _aliceIP = remoteIP;
_alicePort = remotePort; _alicePort = remotePort;
_remoteHostId = new RemoteHostId(_aliceIP, _alicePort); _remoteHostId = new RemoteHostId(_aliceIP, _alicePort);
_bobPort = localPort; _bobPort = localPort;
@ -141,7 +141,8 @@ public class InboundEstablishState {
* new relay tag + Bob's signed on time * new relay tag + Bob's signed on time
*/ */
private void signSessionCreated() { private void signSessionCreated() {
byte signed[] = new byte[_aliceIP.length + 2 byte signed[] = new byte[256 + 256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2 + _bobIP.length + 2
+ 4 // sent relay tag + 4 // sent relay tag
+ 4 // signed on time + 4 // signed on time
@ -149,6 +150,12 @@ public class InboundEstablishState {
_sentSignedOnTime = _context.clock().now() / 1000; _sentSignedOnTime = _context.clock().now() / 1000;
int off = 0; int off = 0;
System.arraycopy(_receivedX, 0, signed, off, _receivedX.length);
off += _receivedX.length;
if (_sentY == null)
_sentY = getSentY();
System.arraycopy(_sentY, 0, signed, off, _sentY.length);
off += _sentY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length); System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length; off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort); DataHelper.toLong(signed, off, 2, _alicePort);
@ -166,6 +173,8 @@ public class InboundEstablishState {
if (_log.shouldLog(Log.DEBUG)) { if (_log.shouldLog(Log.DEBUG)) {
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append("Signing sessionCreated:"); buf.append("Signing sessionCreated:");
buf.append(" ReceivedX: ").append(Base64.encode(_receivedX));
buf.append(" SentY: ").append(Base64.encode(_sentY));
buf.append(" AliceIP: ").append(Base64.encode(_aliceIP)); buf.append(" AliceIP: ").append(Base64.encode(_aliceIP));
buf.append(" AlicePort: ").append(_alicePort); buf.append(" AlicePort: ").append(_alicePort);
buf.append(" BobIP: ").append(Base64.encode(_bobIP)); buf.append(" BobIP: ").append(Base64.encode(_bobIP));
@ -266,13 +275,18 @@ public class InboundEstablishState {
try { try {
peer.readBytes(in); peer.readBytes(in);
byte signed[] = new byte[_aliceIP.length + 2 byte signed[] = new byte[256+256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2 + _bobIP.length + 2
+ 4 // Alice's relay key + 4 // Alice's relay key
+ 4 // signed on time + 4 // signed on time
]; ];
off = 0; off = 0;
System.arraycopy(_receivedX, 0, signed, off, _receivedX.length);
off += _receivedX.length;
System.arraycopy(_sentY, 0, signed, off, _sentY.length);
off += _sentY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length); System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length; off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort); DataHelper.toLong(signed, off, 2, _alicePort);

View File

@ -152,6 +152,7 @@ public class InboundMessageFragments /*implements UDPTransport.PartialACKSource
_log.info("Message received completely! " + state); _log.info("Message received completely! " + state);
_context.statManager().addRateData("udp.receivedCompleteTime", state.getLifetime(), state.getLifetime()); _context.statManager().addRateData("udp.receivedCompleteTime", state.getLifetime(), state.getLifetime());
if (state.getFragmentCount() > 0)
_context.statManager().addRateData("udp.receivedCompleteFragments", state.getFragmentCount(), state.getLifetime()); _context.statManager().addRateData("udp.receivedCompleteFragments", state.getFragmentCount(), state.getLifetime());
} else if (messageExpired) { } else if (messageExpired) {
state.releaseResources(); state.releaseResources();

View File

@ -234,13 +234,18 @@ public class OutboundEstablishState {
* new relay tag + Bob's signed on time * new relay tag + Bob's signed on time
*/ */
private boolean verifySessionCreated() { private boolean verifySessionCreated() {
byte signed[] = new byte[_aliceIP.length + 2 byte signed[] = new byte[256+256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2 + _bobIP.length + 2
+ 4 // sent relay tag + 4 // sent relay tag
+ 4 // signed on time + 4 // signed on time
]; ];
int off = 0; int off = 0;
System.arraycopy(_sentX, 0, signed, off, _sentX.length);
off += _sentX.length;
System.arraycopy(_receivedY, 0, signed, off, _receivedY.length);
off += _receivedY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length); System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length; off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort); DataHelper.toLong(signed, off, 2, _alicePort);
@ -287,7 +292,8 @@ public class OutboundEstablishState {
public synchronized void prepareSessionConfirmed() { public synchronized void prepareSessionConfirmed() {
if (_sentSignedOnTime > 0) if (_sentSignedOnTime > 0)
return; return;
byte signed[] = new byte[_aliceIP.length + 2 byte signed[] = new byte[256+256 // X + Y
+ _aliceIP.length + 2
+ _bobIP.length + 2 + _bobIP.length + 2
+ 4 // Alice's relay key + 4 // Alice's relay key
+ 4 // signed on time + 4 // signed on time
@ -296,6 +302,10 @@ public class OutboundEstablishState {
_sentSignedOnTime = _context.clock().now() / 1000; _sentSignedOnTime = _context.clock().now() / 1000;
int off = 0; int off = 0;
System.arraycopy(_sentX, 0, signed, off, _sentX.length);
off += _sentX.length;
System.arraycopy(_receivedY, 0, signed, off, _receivedY.length);
off += _receivedY.length;
System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length); System.arraycopy(_aliceIP, 0, signed, off, _aliceIP.length);
off += _aliceIP.length; off += _aliceIP.length;
DataHelper.toLong(signed, off, 2, _alicePort); DataHelper.toLong(signed, off, 2, _alicePort);

View File

@ -35,7 +35,7 @@ public class OutboundMessageFragments {
/** if we can handle more messages explicitly, set this to true */ /** if we can handle more messages explicitly, set this to true */
private boolean _allowExcess; private boolean _allowExcess;
private static final int MAX_ACTIVE = 16; private static final int MAX_ACTIVE = 32;
// don't send a packet more than 10 times // don't send a packet more than 10 times
static final int MAX_VOLLEYS = 10; static final int MAX_VOLLEYS = 10;
@ -414,7 +414,9 @@ public class OutboundMessageFragments {
_log.info("Received ack of " + messageId + " by " + ackedBy.toBase64() _log.info("Received ack of " + messageId + " by " + ackedBy.toBase64()
+ " after " + state.getLifetime() + " and " + numSends + " sends"); + " after " + state.getLifetime() + " and " + numSends + " sends");
_context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime()); _context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime());
if (state.getFragmentCount() > 1)
_context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime()); _context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime());
if (numSends > 1)
_context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount()); _context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount());
_transport.succeeded(state.getMessage()); _transport.succeeded(state.getMessage());
int numFragments = state.getFragmentCount(); int numFragments = state.getFragmentCount();
@ -494,7 +496,9 @@ public class OutboundMessageFragments {
if (isComplete) { if (isComplete) {
_context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime()); _context.statManager().addRateData("udp.sendConfirmTime", state.getLifetime(), state.getLifetime());
if (state.getFragmentCount() > 1)
_context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime()); _context.statManager().addRateData("udp.sendConfirmFragments", state.getFragmentCount(), state.getLifetime());
if (numSends > 1)
_context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount()); _context.statManager().addRateData("udp.sendConfirmVolley", numSends, state.getFragmentCount());
_transport.succeeded(state.getMessage()); _transport.succeeded(state.getMessage());

View File

@ -225,11 +225,16 @@ public class OutboundMessageState {
public boolean shouldSend(int fragmentNum) { return _fragmentSends[fragmentNum] >= (short)0; } public boolean shouldSend(int fragmentNum) { return _fragmentSends[fragmentNum] >= (short)0; }
public int fragmentSize(int fragmentNum) { public int fragmentSize(int fragmentNum) {
if (_messageBuf == null) return -1; if (_messageBuf == null) return -1;
if (fragmentNum + 1 == _fragmentSends.length) if (fragmentNum + 1 == _fragmentSends.length) {
return _messageBuf.getValid() % _fragmentSize; int valid = _messageBuf.getValid();
if (valid <= _fragmentSize)
return valid;
else else
return valid % _fragmentSize;
} else {
return _fragmentSize; return _fragmentSize;
} }
}
/** /**
* Write a part of the the message onto the specified buffer. * Write a part of the the message onto the specified buffer.
@ -241,10 +246,8 @@ public class OutboundMessageState {
*/ */
public int writeFragment(byte out[], int outOffset, int fragmentNum) { public int writeFragment(byte out[], int outOffset, int fragmentNum) {
int start = _fragmentSize * fragmentNum; int start = _fragmentSize * fragmentNum;
int end = start + _fragmentSize; int end = start + fragmentSize(fragmentNum);
if (_messageBuf == null) return -1; if (_messageBuf == null) return -1;
if (end > _messageBuf.getValid())
end = _messageBuf.getValid();
int toSend = end - start; int toSend = end - start;
System.arraycopy(_messageBuf.getData(), start, out, outOffset, toSend); System.arraycopy(_messageBuf.getData(), start, out, outOffset, toSend);
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))

View File

@ -100,13 +100,12 @@ public class PacketHandler {
private void handlePacket(UDPPacketReader reader, UDPPacket packet) { private void handlePacket(UDPPacketReader reader, UDPPacket packet) {
if (packet == null) return; if (packet == null) return;
InetAddress remAddr = packet.getPacket().getAddress(); RemoteHostId rem = packet.getRemoteHost();
int remPort = packet.getPacket().getPort(); PeerState state = _transport.getPeerState(rem);
PeerState state = _transport.getPeerState(remAddr, remPort);
if (state == null) { if (state == null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Packet received is not for a connected peer"); _log.debug("Packet received is not for a connected peer");
InboundEstablishState est = _establisher.getInboundState(remAddr, remPort); InboundEstablishState est = _establisher.getInboundState(rem);
if (est != null) { if (est != null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Packet received IS for an inbound establishment"); _log.debug("Packet received IS for an inbound establishment");
@ -114,7 +113,7 @@ public class PacketHandler {
} else { } else {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Packet received is not for an inbound establishment"); _log.debug("Packet received is not for an inbound establishment");
OutboundEstablishState oest = _establisher.getOutboundState(remAddr, remPort); OutboundEstablishState oest = _establisher.getOutboundState(rem);
if (oest != null) { if (oest != null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Packet received IS for an outbound establishment"); _log.debug("Packet received IS for an outbound establishment");
@ -152,9 +151,7 @@ public class PacketHandler {
_log.info("Validation with existing con failed, but validation as reestablish/stray passed"); _log.info("Validation with existing con failed, but validation as reestablish/stray passed");
packet.decrypt(_transport.getIntroKey()); packet.decrypt(_transport.getIntroKey());
} else { } else {
InetAddress remAddr = packet.getPacket().getAddress(); InboundEstablishState est = _establisher.getInboundState(packet.getRemoteHost());
int remPort = packet.getPacket().getPort();
InboundEstablishState est = _establisher.getInboundState(remAddr, remPort);
if (est != null) { if (est != null) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Packet from an existing peer IS for an inbound establishment"); _log.debug("Packet from an existing peer IS for an inbound establishment");
@ -304,13 +301,14 @@ public class PacketHandler {
_context.statManager().addRateData("udp.receivePacketSkew", skew, packet.getLifetime()); _context.statManager().addRateData("udp.receivePacketSkew", skew, packet.getLifetime());
InetAddress fromHost = packet.getPacket().getAddress(); //InetAddress fromHost = packet.getPacket().getAddress();
int fromPort = packet.getPacket().getPort(); //int fromPort = packet.getPacket().getPort();
RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort); //RemoteHostId from = new RemoteHostId(fromHost.getAddress(), fromPort);
RemoteHostId from = packet.getRemoteHost();
switch (reader.readPayloadType()) { switch (reader.readPayloadType()) {
case UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST: case UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST:
_establisher.receiveSessionRequest(from, fromHost, fromPort, reader); _establisher.receiveSessionRequest(from, reader);
break; break;
case UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED: case UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED:
_establisher.receiveSessionConfirmed(from, reader); _establisher.receiveSessionConfirmed(from, reader);

View File

@ -541,10 +541,11 @@ public class PeerState {
} }
} }
_context.statManager().addRateData("udp.sendACKPartial", partialIncluded, rv.size() - partialIncluded);
_lastACKSend = _context.clock().now(); _lastACKSend = _context.clock().now();
if (rv == null) if (rv == null)
rv = Collections.EMPTY_LIST; rv = Collections.EMPTY_LIST;
if (partialIncluded > 0)
_context.statManager().addRateData("udp.sendACKPartial", partialIncluded, rv.size() - partialIncluded);
return rv; return rv;
} }

View File

@ -37,7 +37,7 @@ public class UDPEndpoint {
_receiver.startup(); _receiver.startup();
} catch (SocketException se) { } catch (SocketException se) {
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error("Unable to bind on " + _listenPort); _log.error("Unable to bind on " + _listenPort, se);
} }
} }
@ -45,11 +45,10 @@ public class UDPEndpoint {
if (_sender != null) { if (_sender != null) {
_sender.shutdown(); _sender.shutdown();
_receiver.shutdown(); _receiver.shutdown();
_sender = null;
_receiver = null;
} }
} }
public void setListenPort(int newPort) { _listenPort = newPort; }
public void updateListenPort(int newPort) { public void updateListenPort(int newPort) {
if (newPort == _listenPort) return; if (newPort == _listenPort) return;
try { try {

View File

@ -32,6 +32,7 @@ public class UDPPacket {
private volatile byte[] _data; private volatile byte[] _data;
private volatile ByteArray _dataBuf; private volatile ByteArray _dataBuf;
private volatile int _markedType; private volatile int _markedType;
private volatile RemoteHostId _remoteHost;
private volatile boolean _released; private volatile boolean _released;
private volatile Exception _releasedBy; private volatile Exception _releasedBy;
private volatile Exception _acquiredBy; private volatile Exception _acquiredBy;
@ -78,6 +79,7 @@ public class UDPPacket {
_packet = new DatagramPacket(_data, MAX_PACKET_SIZE); _packet = new DatagramPacket(_data, MAX_PACKET_SIZE);
_initializeTime = _context.clock().now(); _initializeTime = _context.clock().now();
_markedType = -1; _markedType = -1;
_remoteHost = null;
} }
public void initialize(int priority, long expiration, InetAddress host, int port) { public void initialize(int priority, long expiration, InetAddress host, int port) {
@ -88,6 +90,7 @@ public class UDPPacket {
//_packet.setLength(0); //_packet.setLength(0);
_packet.setAddress(host); _packet.setAddress(host);
_packet.setPort(port); _packet.setPort(port);
_remoteHost = null;
_released = false; _released = false;
_releasedBy = null; _releasedBy = null;
} }
@ -113,6 +116,12 @@ public class UDPPacket {
*/ */
public int getMarkedType() { verifyNotReleased(); return _markedType; } public int getMarkedType() { verifyNotReleased(); return _markedType; }
public RemoteHostId getRemoteHost() {
if (_remoteHost == null)
_remoteHost = new RemoteHostId(_packet.getAddress().getAddress(), _packet.getPort());
return _remoteHost;
}
/** /**
* Validate the packet against the MAC specified, returning true if the * Validate the packet against the MAC specified, returning true if the
* MAC matches, false otherwise. * MAC matches, false otherwise.

View File

@ -75,7 +75,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
/** shared slow bid for unconnected peers when we want to prefer UDP */ /** shared slow bid for unconnected peers when we want to prefer UDP */
private TransportBid _slowPreferredBid; private TransportBid _slowPreferredBid;
public static final String STYLE = "SSUv1"; public static final String STYLE = "SSU";
public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort"; public static final String PROP_INTERNAL_PORT = "i2np.udp.internalPort";
/** define this to explicitly set an external IP address */ /** define this to explicitly set an external IP address */
@ -85,11 +85,12 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
/** /**
* If i2np.udp.alwaysPreferred is set, the UDP bids will always be under * If i2np.udp.alwaysPreferred is set, the UDP bids will always be under
* the bid from the TCP transport - even if a TCP connection already * the bid from the TCP transport - even if a TCP connection already
* exists. The default is to prefer UDP unless no UDP session exists and * exists. If this is true (the default), it will always prefer UDP, otherwise
* a TCP connection already exists. * it will prefer UDP unless no UDP session exists and a TCP connection
* already exists.
*/ */
public static final String PROP_ALWAYS_PREFER_UDP = "i2np.udp.alwaysPreferred"; public static final String PROP_ALWAYS_PREFER_UDP = "i2np.udp.alwaysPreferred";
private static final String DEFAULT_ALWAYS_PREFER_UDP = "true";
/** how many relays offered to us will we use at a time? */ /** how many relays offered to us will we use at a time? */
public static final int PUBLIC_RELAY_COUNT = 3; public static final int PUBLIC_RELAY_COUNT = 3;
@ -154,7 +155,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
rebuildExternalAddress(); rebuildExternalAddress();
if (_endpoint == null) {
int port = -1; int port = -1;
if (_externalListenPort <= 0) { if (_externalListenPort <= 0) {
// no explicit external port, so lets try an internal one // no explicit external port, so lets try an internal one
@ -168,15 +168,22 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} }
} }
if (port <= 0) { if (port <= 0) {
port = 1024 + _context.random().nextInt(31*1024); port = 8887;
//port = 1024 + _context.random().nextInt(31*1024);
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Selecting a random port to bind to: " + port); _log.info("Selecting an arbitrary port to bind to: " + port);
_context.router().setConfigSetting(PROP_INTERNAL_PORT, port+"");
// attempt to use it as our external port - this will be overridden by
// externalAddressReceived(...)
_context.router().setConfigSetting(PROP_EXTERNAL_PORT, port+"");
_context.router().saveConfig();
} }
} else { } else {
port = _externalListenPort; port = _externalListenPort;
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Binding to the explicitly specified external port: " + port); _log.info("Binding to the explicitly specified external port: " + port);
} }
if (_endpoint == null) {
try { try {
_endpoint = new UDPEndpoint(_context, port); _endpoint = new UDPEndpoint(_context, port);
} catch (SocketException se) { } catch (SocketException se) {
@ -184,6 +191,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
_log.log(Log.CRIT, "Unable to listen on the UDP port (" + port + ")", se); _log.log(Log.CRIT, "Unable to listen on the UDP port (" + port + ")", se);
return; return;
} }
} else {
_endpoint.setListenPort(port);
} }
if (_establisher == null) if (_establisher == null)
@ -211,14 +220,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} }
public void shutdown() { public void shutdown() {
if (_endpoint != null)
_endpoint.shutdown();
if (_flooder != null) if (_flooder != null)
_flooder.shutdown(); _flooder.shutdown();
if (_refiller != null) if (_refiller != null)
_refiller.shutdown(); _refiller.shutdown();
if (_handler != null) if (_handler != null)
_handler.shutdown(); _handler.shutdown();
if (_endpoint != null)
_endpoint.shutdown();
if (_fragments != null) if (_fragments != null)
_fragments.shutdown(); _fragments.shutdown();
if (_pusher != null) if (_pusher != null)
@ -268,6 +277,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} }
} }
_context.router().setConfigSetting(PROP_EXTERNAL_PORT, ourPort+"");
_context.router().saveConfig();
if (updated) if (updated)
_context.router().rebuildRouterInfo(); _context.router().rebuildRouterInfo();
} }
@ -280,8 +292,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
* get the state for the peer at the given remote host/port, or null * get the state for the peer at the given remote host/port, or null
* if no state exists * if no state exists
*/ */
public PeerState getPeerState(InetAddress remoteHost, int remotePort) { public PeerState getPeerState(RemoteHostId hostInfo) {
RemoteHostId hostInfo = new RemoteHostId(remoteHost.getAddress(), remotePort);
synchronized (_peersByRemoteHost) { synchronized (_peersByRemoteHost) {
return (PeerState)_peersByRemoteHost.get(hostInfo); return (PeerState)_peersByRemoteHost.get(hostInfo);
} }
@ -424,7 +435,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
} }
private boolean alwaysPreferUDP() { private boolean alwaysPreferUDP() {
String pref = _context.getProperty(PROP_ALWAYS_PREFER_UDP); String pref = _context.getProperty(PROP_ALWAYS_PREFER_UDP, DEFAULT_ALWAYS_PREFER_UDP);
return (pref != null) && "true".equals(pref); return (pref != null) && "true".equals(pref);
} }

View File

@ -29,7 +29,7 @@ public class HopProcessor {
* and after using it at each hop so as to prevent a certain type of replay/confirmation * and after using it at each hop so as to prevent a certain type of replay/confirmation
* attack. * attack.
*/ */
static final boolean USE_DOUBLE_IV_ENCRYPTION = false; static final boolean USE_DOUBLE_IV_ENCRYPTION = true;
static final int IV_LENGTH = 16; static final int IV_LENGTH = 16;
private static final ByteCache _cache = ByteCache.getInstance(128, IV_LENGTH); private static final ByteCache _cache = ByteCache.getInstance(128, IV_LENGTH);