diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/package.html b/apps/ministreaming/java/src/net/i2p/client/streaming/package.html index 735135074871957df6d46764e63f54d99537e4d1..8418604532afb4a7ef62c9d7d6e0d9621895179a 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/package.html +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/package.html @@ -16,9 +16,9 @@ net.i2p.client.streaming.I2PServerSocket#accept} method, which will provide an application wants to create a new stream to a peer, it should do so with the appropriate {@link net.i2p.client.streaming.I2PSocketManager#connect} call.</p> -<p>There is a simple pair of demo applications available as well - {@link -net.i2p.client.streaming.StreamSinkServer} listens to a destination and dumps -the data from all sockets it accepts to individual files, while {@link -net.i2p.client.streaming.StreamSinkClient} connects to a particular destination +<p>There is a simple pair of demo applications available as well - +net.i2p.client.streaming.StreamSinkServer listens to a destination and dumps +the data from all sockets it accepts to individual files, while +net.i2p.client.streaming.StreamSinkClient connects to a particular destination and sends a specific amount of random data then disconnects.</p> </body></html> diff --git a/apps/routerconsole/jsp/debug.jsp b/apps/routerconsole/jsp/debug.jsp new file mode 100644 index 0000000000000000000000000000000000000000..694f9c1df2452d71d0db24845313ad65703ecd28 --- /dev/null +++ b/apps/routerconsole/jsp/debug.jsp @@ -0,0 +1,30 @@ +<%@page contentType="text/html"%> +<%@page pageEncoding="UTF-8"%> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html><head><title>DEBUG</title> +<%@include file="css.jsp" %> +</head><body> +<%@include file="summary.jsp" %> +<div class="main" id="main"> +<% + /* + * Quick and easy place to put debugging stuff + */ + net.i2p.router.RouterContext ctx = (net.i2p.router.RouterContext) net.i2p.I2PAppContext.getGlobalContext(); + + /* + * Print out the status for all the SessionKeyManagers + */ + out.print("<h1>Router SKM</h1>"); + ctx.sessionKeyManager().renderStatusHTML(out); + java.util.Set<net.i2p.data.Destination> clients = ctx.clientManager().listClients(); + for (net.i2p.data.Destination dest : clients) { + net.i2p.data.Hash h = dest.calculateHash(); + net.i2p.crypto.SessionKeyManager skm = ctx.clientManager().getClientSessionKeyManager(h); + if (skm != null) { + out.print("<h1>" + h.toBase64().substring(0,6) + " SKM</h1>"); + skm.renderStatusHTML(out); + } + } +%> +</div></body></html> diff --git a/apps/streaming/java/src/net/i2p/client/streaming/Connection.java b/apps/streaming/java/src/net/i2p/client/streaming/Connection.java index c7495131f3d1609cc31840fb67e892298245801f..a47d361a668e0e0495eaaebfec4f1578614d8606 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/Connection.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/Connection.java @@ -354,6 +354,7 @@ public class Connection { */ } +/********* private class PingNotifier implements ConnectionManager.PingNotifier { private long _startedPingOn; public PingNotifier() { @@ -367,6 +368,7 @@ public class Connection { _options.updateRTT((int)time*2); } } +*********/ List ackPackets(long ackThrough, long nacks[]) { if (ackThrough < _highestAckedThrough) { @@ -548,20 +550,21 @@ public class Connection { killOutstandingPackets(); } + /** ignore tag issues */ private void killOutstandingPackets() { - boolean tagsCancelled = false; + //boolean tagsCancelled = false; synchronized (_outboundPackets) { for (Iterator iter = _outboundPackets.values().iterator(); iter.hasNext(); ) { PacketLocal pl = (PacketLocal)iter.next(); - if ( (pl.getTagsSent() != null) && (pl.getTagsSent().size() > 0) ) - tagsCancelled = true; + //if ( (pl.getTagsSent() != null) && (pl.getTagsSent().size() > 0) ) + // tagsCancelled = true; pl.cancelled(); } _outboundPackets.clear(); _outboundPackets.notifyAll(); } - if (tagsCancelled) - _context.sessionKeyManager().failTags(_remotePeer.getPublicKey()); + //if (tagsCancelled) + // _context.sessionKeyManager().failTags(_remotePeer.getPublicKey()); } private class DisconnectEvent implements SimpleTimer.TimedEvent { @@ -1140,12 +1143,12 @@ public class Connection { // in case things really suck, the other side may have lost thier // session tags (e.g. they restarted), so jump back to ElGamal. - int failTagsAt = _options.getMaxResends() - 2; - if ( (newWindowSize == 1) && (numSends == failTagsAt) ) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Optimistically failing tags at resend " + numSends); - _context.sessionKeyManager().failTags(_remotePeer.getPublicKey()); - } + //int failTagsAt = _options.getMaxResends() - 2; + //if ( (newWindowSize == 1) && (numSends == failTagsAt) ) { + // if (_log.shouldLog(Log.WARN)) + // _log.warn("Optimistically failing tags at resend " + numSends); + // _context.sessionKeyManager().failTags(_remotePeer.getPublicKey()); + //} if (numSends - 1 > _options.getMaxResends()) { if (_log.shouldLog(Log.DEBUG)) diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java index 7efc6cc401e99f56e9fb6fb1ba4b88c814238224..af44c41f24b1f0d02552f9241b5700732bb3a4f4 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java @@ -349,24 +349,35 @@ public class ConnectionManager { return new HashSet(_connectionByInboundId.values()); } } + + /** blocking */ public boolean ping(Destination peer, long timeoutMs) { - return ping(peer, timeoutMs, true); + return ping(peer, timeoutMs, true, null); } public boolean ping(Destination peer, long timeoutMs, boolean blocking) { - return ping(peer, timeoutMs, blocking, null, null, null); + return ping(peer, timeoutMs, blocking, null); } + /** + * @deprecated I2PSession ignores tags, use non-tag variant + * @param keyToUse ignored + * @param tagsToSend ignored + */ public boolean ping(Destination peer, long timeoutMs, boolean blocking, SessionKey keyToUse, Set tagsToSend, PingNotifier notifier) { + return ping(peer, timeoutMs, blocking, notifier); + } + + public boolean ping(Destination peer, long timeoutMs, boolean blocking, PingNotifier notifier) { Long id = new Long(_context.random().nextLong(Packet.MAX_STREAM_ID-1)+1); PacketLocal packet = new PacketLocal(_context, peer); packet.setSendStreamId(id.longValue()); packet.setFlag(Packet.FLAG_ECHO); packet.setFlag(Packet.FLAG_SIGNATURE_INCLUDED); packet.setOptionalFrom(_session.getMyDestination()); - if ( (keyToUse != null) && (tagsToSend != null) ) { - packet.setKeyUsed(keyToUse); - packet.setTagsSent(tagsToSend); - } + //if ( (keyToUse != null) && (tagsToSend != null) ) { + // packet.setKeyUsed(keyToUse); + // packet.setTagsSent(tagsToSend); + //} PingRequest req = new PingRequest(peer, packet, notifier); @@ -435,7 +446,7 @@ public class ConnectionManager { } public void pong() { _log.debug("Ping successful"); - _context.sessionKeyManager().tagsDelivered(_peer.getPublicKey(), _packet.getKeyUsed(), _packet.getTagsSent()); + //_context.sessionKeyManager().tagsDelivered(_peer.getPublicKey(), _packet.getKeyUsed(), _packet.getTagsSent()); synchronized (ConnectionManager.PingRequest.this) { _ponged = true; ConnectionManager.PingRequest.this.notifyAll(); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java index f7b245cb83fb0748f3d37e805ed1c2bd345b70b9..91a06e088b983b041a09d068bd5c46c8cffa22a0 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionPacketHandler.java @@ -263,12 +263,12 @@ public class ConnectionPacketHandler { numResends++; // ACK the tags we delivered so we can use them - if ( (p.getKeyUsed() != null) && (p.getTagsSent() != null) - && (p.getTagsSent().size() > 0) ) { - _context.sessionKeyManager().tagsDelivered(p.getTo().getPublicKey(), - p.getKeyUsed(), - p.getTagsSent()); - } + //if ( (p.getKeyUsed() != null) && (p.getTagsSent() != null) + // && (p.getTagsSent().size() > 0) ) { + // _context.sessionKeyManager().tagsDelivered(p.getTo().getPublicKey(), + // p.getKeyUsed(), + // p.getTagsSent()); + //} if (_log.shouldLog(Log.DEBUG)) _log.debug("Packet acked after " + p.getAckTime() + "ms: " + p); } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java b/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java index 9ed29b50fb21aca3d865fd281838246ef0926364..b1438a033ad63ec6c95e5a8483ce3014ddf92dbf 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/PacketLocal.java @@ -47,11 +47,31 @@ public class PacketLocal extends Packet implements MessageOutputStream.WriteStat public Destination getTo() { return _to; } public void setTo(Destination to) { _to = to; } + /** + * @deprecated should always return null + */ public SessionKey getKeyUsed() { return _keyUsed; } - public void setKeyUsed(SessionKey key) { _keyUsed = key; } + + /** + * @deprecated I2PSession throws out the tags + */ + public void setKeyUsed(SessionKey key) { + if (key != null) + _log.error("Who is sending tags thru the streaming lib?"); + _keyUsed = key; + } + /** + * @deprecated should always return null or an empty set + */ public Set getTagsSent() { return _tagsSent; } + + /** + * @deprecated I2PSession throws out the tags + */ public void setTagsSent(Set tags) { + if (tags != null && tags.size() > 0) + _log.error("Who is sending tags thru the streaming lib? " + tags.size()); if ( (_tagsSent != null) && (_tagsSent.size() > 0) && (tags.size() > 0) ) { //int old = _tagsSent.size(); //_tagsSent.addAll(tags); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java b/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java index db4adb27cd00f643199dc6ecb0e56273ad50cc43..8a4692ada76444ae972c52861b776d2453f6b4f5 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/PacketQueue.java @@ -36,16 +36,18 @@ public class PacketQueue { /** * Add a new packet to be sent out ASAP + * + * keys and tags disabled since dropped in I2PSession */ public void enqueue(PacketLocal packet) { packet.prepare(); - SessionKey keyUsed = packet.getKeyUsed(); - if (keyUsed == null) - keyUsed = new SessionKey(); - Set tagsSent = packet.getTagsSent(); - if (tagsSent == null) - tagsSent = new HashSet(0); + //SessionKey keyUsed = packet.getKeyUsed(); + //if (keyUsed == null) + // keyUsed = new SessionKey(); + //Set tagsSent = packet.getTagsSent(); + //if (tagsSent == null) + // tagsSent = new HashSet(0); // cache this from before sendMessage String conStr = null; @@ -92,13 +94,19 @@ public class PacketQueue { // I2PSessionImpl2 //sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, expires); // I2PSessionMuxedImpl - sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, expires, + //sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, expires, + // I2PSession.PROTO_STREAMING, I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED); + // I2PSessionMuxedImpl no tags + sent = _session.sendMessage(packet.getTo(), buf, 0, size, null, null, expires, I2PSession.PROTO_STREAMING, I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED); else // I2PSessionImpl2 //sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, 0); // I2PSessionMuxedImpl - sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, + //sent = _session.sendMessage(packet.getTo(), buf, 0, size, keyUsed, tagsSent, + // I2PSession.PROTO_STREAMING, I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED); + // I2PSessionMuxedImpl no tags + sent = _session.sendMessage(packet.getTo(), buf, 0, size, null, null, I2PSession.PROTO_STREAMING, I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED); end = _context.clock().now(); @@ -129,13 +137,11 @@ public class PacketQueue { if (c != null) // handle race on b0rk c.disconnect(false); } else { - packet.setKeyUsed(keyUsed); - packet.setTagsSent(tagsSent); + //packet.setKeyUsed(keyUsed); + //packet.setTagsSent(tagsSent); packet.incrementSends(); if (_log.shouldLog(Log.DEBUG)) { - String msg = "SEND " + packet + (tagsSent.size() > 0 - ? " with " + tagsSent.size() + " tags" - : "") + String msg = "SEND " + packet + " send # " + packet.getNumSends() + " sendTime: " + (end-begin) + " con: " + conStr; diff --git a/core/java/src/net/i2p/client/I2CPMessageProducer.java b/core/java/src/net/i2p/client/I2CPMessageProducer.java index b897d22d0ee2230577e80c6972f52ed77e97efba..220c0a851e0a59c4cd4887dbb8f9b1782962937e 100644 --- a/core/java/src/net/i2p/client/I2CPMessageProducer.java +++ b/core/java/src/net/i2p/client/I2CPMessageProducer.java @@ -93,6 +93,10 @@ class I2CPMessageProducer { /** * Package up and send the payload to the router for delivery * + * @param tag unused - no end-to-end crypto + * @param tags unused - no end-to-end crypto + * @param key unused - no end-to-end crypto + * @param newKey unused - no end-to-end crypto */ public void sendMessage(I2PSessionImpl session, Destination dest, long nonce, byte[] payload, SessionTag tag, SessionKey key, Set tags, SessionKey newKey, long expires) throws I2PSessionException { @@ -135,6 +139,10 @@ class I2CPMessageProducer { /** * Create a new signed payload and send it off to the destination * + * @param tag unused - no end-to-end crypto + * @param tags unused - no end-to-end crypto + * @param key unused - no end-to-end crypto + * @param newKey unused - no end-to-end crypto */ private Payload createPayload(Destination dest, byte[] payload, SessionTag tag, SessionKey key, Set tags, SessionKey newKey) throws I2PSessionException { diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index 8fc3087158020cb5112565f7d18ba46a30b1062c..7bee11a2c9bfa152a589b20b5f33553546a417b9 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -355,17 +355,23 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa */ public abstract boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException; + /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto + */ public abstract boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException; public abstract void receiveStatus(int msgId, long nonce, int status); +/****** no end-to-end crypto protected static final Set createNewTags(int num) { Set tags = new HashSet(); for (int i = 0; i < num; i++) tags.add(new SessionTag(true)); return tags; } +*******/ /** * Recieve a payload message and let the app know its available diff --git a/core/java/src/net/i2p/client/I2PSessionImpl2.java b/core/java/src/net/i2p/client/I2PSessionImpl2.java index 508057c2c55e6e2796280fb94d2bbe91049bc176..5b57b3137b47493d65551df4602012e51200f67f 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl2.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl2.java @@ -133,14 +133,28 @@ class I2PSessionImpl2 extends I2PSessionImpl { return sendMessage(dest, payload, offset, size, null, null, 0); } + /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto + */ @Override public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException { return sendMessage(dest, payload, 0, payload.length, keyUsed, tagsSent, 0); } + + /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto + */ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException { return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0); } + + /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto + */ public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expires) throws I2PSessionException { if (_log.shouldLog(Log.DEBUG)) _log.debug("sending message"); @@ -196,13 +210,17 @@ class I2PSessionImpl2 extends I2PSessionImpl { private static final int NUM_TAGS = 50; + /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto + */ protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires) throws I2PSessionException { - SessionKey key = null; - SessionKey newKey = null; - SessionTag tag = null; - Set sentTags = null; - int oldTags = 0; + //SessionKey key = null; + //SessionKey newKey = null; + //SessionTag tag = null; + //Set sentTags = null; + //int oldTags = 0; long begin = _context.clock().now(); /*********** if (I2CPMessageProducer.END_TO_END_CRYPTO) { @@ -256,27 +274,27 @@ class I2PSessionImpl2 extends I2PSessionImpl { long nonce = _context.random().nextInt(Integer.MAX_VALUE); if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync state"); MessageState state = new MessageState(_context, nonce, getPrefix()); - state.setKey(key); - state.setTags(sentTags); - state.setNewKey(newKey); + //state.setKey(key); + //state.setTags(sentTags); + //state.setNewKey(newKey); state.setTo(dest); - if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Setting key = " + key); + //if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Setting key = " + key); - if (keyUsed != null) { + //if (keyUsed != null) { //if (I2CPMessageProducer.END_TO_END_CRYPTO) { // if (newKey != null) // keyUsed.setData(newKey.getData()); // else // keyUsed.setData(key.getData()); //} else { - keyUsed.setData(SessionKey.INVALID_KEY.getData()); + // keyUsed.setData(SessionKey.INVALID_KEY.getData()); //} - } - if (tagsSent != null) { - if (sentTags != null) { - tagsSent.addAll(sentTags); - } - } + //} + //if (tagsSent != null) { + // if (sentTags != null) { + // tagsSent.addAll(sentTags); + // } + //} if (_log.shouldLog(Log.DEBUG)) _log.debug("before sync state"); long beforeSendingSync = _context.clock().now(); @@ -291,7 +309,8 @@ class I2PSessionImpl2 extends I2PSessionImpl { + state.getNonce() + " for best effort " + " sync took " + (inSendingSync-beforeSendingSync) + " add took " + (afterSendingSync-inSendingSync)); - _producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey, expires); + //_producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey, expires); + _producer.sendMessage(this, dest, nonce, payload, null, null, null, null, expires); // since this is 'best effort', all we're waiting for is a status update // saying that the router received it - in theory, that should come back diff --git a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java index 58b5cae9f29005e774df26d8bb407ecd0ca86a0a..c0533b1fff24a466102abad0cbec70342c3facc3 100644 --- a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java @@ -128,6 +128,10 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession { return sendMessage(dest, payload, 0, payload.length, null, null, 0, proto, fromport, toport); } + /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto + */ @Override public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expires) @@ -135,6 +139,10 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession { return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, PROTO_UNSPECIFIED, PORT_UNSPECIFIED, PORT_UNSPECIFIED); } + /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto + */ @Override public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, int proto, int fromport, int toport) throws I2PSessionException { @@ -142,6 +150,8 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession { } /** + * @param keyUsed unused - no end-to-end crypto + * @param tagsSent unused - no end-to-end crypto * @param proto 1-254 or 0 for unset; recommended: * I2PSession.PROTO_UNSPECIFIED * I2PSession.PROTO_STREAMING diff --git a/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java b/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java index 4b17a67d3a4c2c4d35754deab90b65c28d9773e1..7b294e3b6e54333d61966cb743aeaa9469c2fcc1 100644 --- a/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java +++ b/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java @@ -22,6 +22,8 @@ import net.i2p.util.Log; * of a message by accepting it, decrypting the payload, adding it to the set of * recieved messages, and telling the router that it has been recieved correctly. * + * We don't really decrypt (no more end-to-end crypto) + * * @author jrandom */ class MessagePayloadMessageHandler extends HandlerImpl { @@ -51,21 +53,24 @@ class MessagePayloadMessageHandler extends HandlerImpl { /** * Decrypt the payload + * + * We don't really decrypt (no more end-to-end crypto) + * If we do, we need to use the correct key manager in the decrypt() call below */ private Payload decryptPayload(MessagePayloadMessage msg, I2PSessionImpl session) throws DataFormatException { Payload payload = msg.getPayload(); - if (!I2CPMessageProducer.END_TO_END_CRYPTO) { + //if (!I2CPMessageProducer.END_TO_END_CRYPTO) { payload.setUnencryptedData(payload.getEncryptedData()); return payload; - } + //} - byte[] data = _context.elGamalAESEngine().decrypt(payload.getEncryptedData(), session.getDecryptionKey()); - if (data == null) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Error decrypting the payload"); - throw new DataFormatException("Unable to decrypt the payload"); - } - payload.setUnencryptedData(data); - return payload; + //byte[] data = _context.elGamalAESEngine().decrypt(payload.getEncryptedData(), session.getDecryptionKey()); + //if (data == null) { + // if (_log.shouldLog(Log.WARN)) + // _log.warn("Error decrypting the payload"); + // throw new DataFormatException("Unable to decrypt the payload"); + //} + //payload.setUnencryptedData(data); + //return payload; } } diff --git a/core/java/src/net/i2p/crypto/HMAC256Generator.java b/core/java/src/net/i2p/crypto/HMAC256Generator.java index 0335d1e7eb0ef6f3edfe96373847548dd4df1622..e84489d97173337d30dcdf92a26c85ac23c47067 100644 --- a/core/java/src/net/i2p/crypto/HMAC256Generator.java +++ b/core/java/src/net/i2p/crypto/HMAC256Generator.java @@ -12,7 +12,7 @@ import org.bouncycastle.crypto.macs.I2PHMac; /** * Calculate the HMAC-SHA256 of a key+message. All the good stuff occurs - * in {@link org.bouncycastle.crypto.macs.HMac} and + * in {@link org.bouncycastle.crypto.macs.I2PHMac} and * {@link org.bouncycastle.crypto.digests.MD5Digest}. * */ diff --git a/core/java/src/net/i2p/crypto/HMACGenerator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java index e37ec92023efbc7fb4d9f3ea5305b383cb38f5c3..9bf06aa70e32f83391daa70aa755b57e55928bcf 100644 --- a/core/java/src/net/i2p/crypto/HMACGenerator.java +++ b/core/java/src/net/i2p/crypto/HMACGenerator.java @@ -15,7 +15,7 @@ import org.bouncycastle.crypto.macs.I2PHMac; /** * Calculate the HMAC-MD5 of a key+message. All the good stuff occurs - * in {@link org.bouncycastle.crypto.macs.HMac} and + * in {@link org.bouncycastle.crypto.macs.I2PHMac} and * {@link org.bouncycastle.crypto.digests.MD5Digest}. * */ diff --git a/core/java/src/net/i2p/crypto/SessionKeyManager.java b/core/java/src/net/i2p/crypto/SessionKeyManager.java index b1547864cd4c2d4a279b07b158ae04ee4691284b..2cd86ba7d9a54f3b9adb0a6e26327fef88a36d25 100644 --- a/core/java/src/net/i2p/crypto/SessionKeyManager.java +++ b/core/java/src/net/i2p/crypto/SessionKeyManager.java @@ -9,6 +9,8 @@ package net.i2p.crypto; * */ +import java.io.IOException; +import java.io.Writer; import java.util.Set; import net.i2p.I2PAppContext; @@ -130,4 +132,6 @@ public class SessionKeyManager { */ public void shutdown() { // nop } + + public void renderStatusHTML(Writer out) throws IOException {} } diff --git a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java index 02be5acd578f19d634d703c2273b6d4b464f104a..e079fce5d1127933ebeb8c79780ec4cecbab86a5 100644 --- a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java +++ b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java @@ -9,7 +9,10 @@ package net.i2p.crypto; * */ +import java.io.IOException; +import java.io.Writer; import java.util.ArrayList; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -17,6 +20,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; @@ -503,57 +507,83 @@ public class TransientSessionKeyManager extends SessionKeyManager { return removed; } - public String renderStatusHTML() { + @Override + public void renderStatusHTML(Writer out) throws IOException { StringBuilder buf = new StringBuilder(1024); - buf.append("<h2>Inbound sessions</h2>"); - buf.append("<table>"); + buf.append("<h2>Inbound sessions</h2>" + + "<table>"); Set<TagSet> inbound = getInboundTagSets(); Map<SessionKey, Set<TagSet>> inboundSets = new HashMap(inbound.size()); + // Build a map of the inbound tag sets, grouped by SessionKey for (Iterator<TagSet> iter = inbound.iterator(); iter.hasNext();) { TagSet ts = iter.next(); if (!inboundSets.containsKey(ts.getAssociatedKey())) inboundSets.put(ts.getAssociatedKey(), new HashSet()); Set<TagSet> sets = inboundSets.get(ts.getAssociatedKey()); sets.add(ts); } + int total = 0; + long now = _context.clock().now(); for (Iterator<SessionKey> iter = inboundSets.keySet().iterator(); iter.hasNext();) { SessionKey skey = iter.next(); - Set<TagSet> sets = inboundSets.get(skey); - buf.append("<tr><td><b>Session key</b>: ").append(skey.toBase64()).append("</td>"); - buf.append("<td><b># Sets:</b> ").append(sets.size()).append("</td></tr>"); - buf.append("<tr><td colspan=\"2\"><ul>"); + Set<TagSet> sets = new TreeSet(new TagSetComparator()); + sets.addAll(inboundSets.get(skey)); + buf.append("<tr><td><b>Session key</b>: ").append(skey.toBase64()).append("</td>" + + "<td><b># Sets:</b> ").append(sets.size()).append("</td></tr>" + + "<tr><td colspan=\"2\"><ul>"); for (Iterator<TagSet> siter = sets.iterator(); siter.hasNext();) { TagSet ts = siter.next(); - buf.append("<li><b>Received on:</b> ").append(new Date(ts.getDate())).append(" with ") - .append(ts.getTags().size()).append(" tags remaining</li>"); + int size = ts.getTags().size(); + total += size; + buf.append("<li><b>Received:</b> ").append(DataHelper.formatDuration(now - ts.getDate())).append(" ago with "); + buf.append(size).append(" tags remaining</li>"); } - buf.append("</ul></td></tr>"); - } - buf.append("</table>"); - - buf.append("<h2><b>Outbound sessions</b></h2>"); - - buf.append("<table>"); + buf.append("</ul></td></tr>\n"); + out.write(buf.toString()); + buf.setLength(0); + } + buf.append("<tr><th colspan=\"2\">Total tags: ").append(total).append(" ("); + buf.append(DataHelper.formatSize(32*total)).append("B)</th></tr>\n" + + "</table>" + + "<h2><b>Outbound sessions</b></h2>" + + "<table>"); + total = 0; Set<OutboundSession> outbound = getOutboundSessions(); for (Iterator<OutboundSession> iter = outbound.iterator(); iter.hasNext();) { OutboundSession sess = iter.next(); - buf.append("<tr><td><b>Target key:</b> ").append(sess.getTarget().toString()).append("<br>"); - buf.append("<b>Established:</b> ").append(new Date(sess.getEstablishedDate())).append("<br>"); - buf.append("<b>Last Used:</b> ").append(new Date(sess.getLastUsedDate())).append("<br>"); - buf.append("<b># Sets:</b> ").append(sess.getTagSets().size()).append("</td></tr>"); - buf.append("<tr><td><b>Session key:</b> ").append(sess.getCurrentKey().toBase64()).append("</td></tr>"); - buf.append("<tr><td><ul>"); - for (Iterator<TagSet> siter = sess.getTagSets().iterator(); siter.hasNext();) { + Set<TagSet> sets = new TreeSet(new TagSetComparator()); + sets.addAll(sess.getTagSets()); + buf.append("<tr><td><b>Target key:</b> ").append(sess.getTarget().toBase64().substring(0, 64)).append("<br>" + + "<b>Established:</b> ").append(DataHelper.formatDuration(now - sess.getEstablishedDate())).append(" ago<br>" + + "<b>Last Used:</b> ").append(DataHelper.formatDuration(now - sess.getLastUsedDate())).append(" ago<br>" + + "<b>Session key:</b> ").append(sess.getCurrentKey().toBase64()).append("</td>" + + "<td><b># Sets:</b> ").append(sess.getTagSets().size()).append("</td></tr>" + + "<tr><td colspan=\"2\"><ul>"); + for (Iterator<TagSet> siter = sets.iterator(); siter.hasNext();) { TagSet ts = siter.next(); - buf.append("<li><b>Sent on:</b> ").append(new Date(ts.getDate())).append(" with ").append( - ts.getTags() - .size()) - .append(" tags remaining</li>"); + int size = ts.getTags().size(); + total += size; + buf.append("<li><b>Sent:</b> ").append(DataHelper.formatDuration(now - ts.getDate())).append(" ago with "); + buf.append(size).append(" tags remaining</li>"); } - buf.append("</ul></td></tr>"); + buf.append("</ul></td></tr>\n"); + out.write(buf.toString()); + buf.setLength(0); } - buf.append("</table>"); + buf.append("<tr><th colspan=\"2\">Total tags: ").append(total).append(" ("); + buf.append(DataHelper.formatSize(32*total)).append("B)</th></tr>\n" + + "</table>"); - return buf.toString(); + out.write(buf.toString()); + } + + /** + * Just for the HTML method above so we can see what's going on easier + * Earliest first + */ + private class TagSetComparator implements Comparator { + public int compare(Object l, Object r) { + return (int) (((TagSet)l).getDate() - ((TagSet)r).getDate()); + } } class OutboundSession { @@ -760,7 +790,7 @@ public class TransientSessionKeyManager extends SessionKeyManager { @Override public int hashCode() { long rv = 0; - if (_key != null) rv = rv * 7 + _key.hashCode(); + if (_key != null) rv = _key.hashCode(); rv = rv * 7 + _date; // no need to hashCode the tags, key + date should be enough return (int) rv; diff --git a/router/java/src/net/i2p/router/ClientManagerFacade.java b/router/java/src/net/i2p/router/ClientManagerFacade.java index 0ce20df6adbf00fd566b3364faa696c4df26536a..1318232879f32d20b7d60c582630d47d7158e0d3 100644 --- a/router/java/src/net/i2p/router/ClientManagerFacade.java +++ b/router/java/src/net/i2p/router/ClientManagerFacade.java @@ -85,13 +85,13 @@ public abstract class ClientManagerFacade implements Service { * * @return set of Destination objects */ - public Set listClients() { return Collections.EMPTY_SET; } + public Set<Destination> listClients() { return Collections.EMPTY_SET; } /** * Return the client's current config, or null if not connected * */ public abstract SessionConfig getClientSessionConfig(Destination dest); - public abstract SessionKeyManager getClientSessionKeyManager(Destination dest); + public abstract SessionKeyManager getClientSessionKeyManager(Hash dest); public void renderStatusHTML(Writer out) throws IOException { } } diff --git a/router/java/src/net/i2p/router/DummyClientManagerFacade.java b/router/java/src/net/i2p/router/DummyClientManagerFacade.java index 5e362e3ddb105d54e9d45b79c6c60219192a6aa4..9c0c6838e0b3f4365ff123757d4fd8218ce46ba1 100644 --- a/router/java/src/net/i2p/router/DummyClientManagerFacade.java +++ b/router/java/src/net/i2p/router/DummyClientManagerFacade.java @@ -41,7 +41,7 @@ public class DummyClientManagerFacade extends ClientManagerFacade { public void messageDeliveryStatusUpdate(Destination fromDest, MessageId id, boolean delivered) {} public SessionConfig getClientSessionConfig(Destination _dest) { return null; } - public SessionKeyManager getClientSessionKeyManager(Destination _dest) { return null; } + public SessionKeyManager getClientSessionKeyManager(Hash _dest) { return null; } public void requestLeaseSet(Hash dest, LeaseSet set) {} diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java index 5b4a4fb535ac0b1586d0308562adefa562dd084e..cbc5d778b01b4749f6e31294a774df45638c3701 100644 --- a/router/java/src/net/i2p/router/client/ClientManager.java +++ b/router/java/src/net/i2p/router/client/ClientManager.java @@ -42,8 +42,8 @@ import net.i2p.util.Log; public class ClientManager { private Log _log; private ClientListenerRunner _listener; - private final HashMap _runners; // Destination --> ClientConnectionRunner - private final Set _pendingRunners; // ClientConnectionRunner for clients w/out a Dest yet + private final HashMap<Destination, ClientConnectionRunner> _runners; // Destination --> ClientConnectionRunner + private final Set<ClientConnectionRunner> _pendingRunners; // ClientConnectionRunner for clients w/out a Dest yet private RouterContext _ctx; /** ms to wait before rechecking for inbound messages to deliver to clients */ @@ -90,21 +90,21 @@ public class ClientManager { public void shutdown() { _log.info("Shutting down the ClientManager"); _listener.stopListening(); - Set runners = new HashSet(); + Set<ClientConnectionRunner> runners = new HashSet(); synchronized (_runners) { - for (Iterator iter = _runners.values().iterator(); iter.hasNext();) { - ClientConnectionRunner runner = (ClientConnectionRunner)iter.next(); + for (Iterator<ClientConnectionRunner> iter = _runners.values().iterator(); iter.hasNext();) { + ClientConnectionRunner runner = iter.next(); runners.add(runner); } } synchronized (_pendingRunners) { - for (Iterator iter = _pendingRunners.iterator(); iter.hasNext();) { - ClientConnectionRunner runner = (ClientConnectionRunner)iter.next(); + for (Iterator<ClientConnectionRunner> iter = _pendingRunners.iterator(); iter.hasNext();) { + ClientConnectionRunner runner = iter.next(); runners.add(runner); } } - for (Iterator iter = runners.iterator(); iter.hasNext(); ) { - ClientConnectionRunner runner = (ClientConnectionRunner)iter.next(); + for (Iterator<ClientConnectionRunner> iter = runners.iterator(); iter.hasNext(); ) { + ClientConnectionRunner runner = iter.next(); runner.stopRunning(); } } @@ -131,15 +131,26 @@ public class ClientManager { } } + /** + * Add to the clients list. Check for a dup destination. + */ public void destinationEstablished(ClientConnectionRunner runner) { + Destination dest = runner.getConfig().getDestination(); if (_log.shouldLog(Log.DEBUG)) - _log.debug("DestinationEstablished called for destination " + runner.getConfig().getDestination().calculateHash().toBase64()); + _log.debug("DestinationEstablished called for destination " + dest.calculateHash().toBase64()); synchronized (_pendingRunners) { _pendingRunners.remove(runner); } + boolean fail = false; synchronized (_runners) { - _runners.put(runner.getConfig().getDestination(), runner); + fail = _runners.containsKey(dest); + if (!fail) + _runners.put(dest, runner); + } + if (fail) { + _log.log(Log.CRIT, "Client attempted to register duplicate destination " + dest.calculateHash().toBase64()); + runner.disconnectClient("Duplicate destination"); } } @@ -278,8 +289,8 @@ public class ClientManager { return true; } - public Set listClients() { - Set rv = new HashSet(); + public Set<Destination> listClients() { + Set<Destination> rv = new HashSet(); synchronized (_runners) { rv.addAll(_runners.keySet()); } @@ -293,7 +304,7 @@ public class ClientManager { long inLock = 0; synchronized (_runners) { inLock = _ctx.clock().now(); - rv = (ClientConnectionRunner)_runners.get(dest); + rv = _runners.get(dest); } long afterLock = _ctx.clock().now(); if (afterLock - beforeLock > 50) { @@ -317,9 +328,10 @@ public class ClientManager { /** * Return the client's SessionKeyManager - * + * Use this instead of the RouterContext.sessionKeyManager() + * to prevent correlation attacks across destinations */ - public SessionKeyManager getClientSessionKeyManager(Destination dest) { + public SessionKeyManager getClientSessionKeyManager(Hash dest) { ClientConnectionRunner runner = getRunner(dest); if (runner != null) return runner.getSessionKeyManager(); @@ -331,8 +343,8 @@ public class ClientManager { if (destHash == null) return null; synchronized (_runners) { - for (Iterator iter = _runners.values().iterator(); iter.hasNext(); ) { - ClientConnectionRunner cur = (ClientConnectionRunner)iter.next(); + for (Iterator<ClientConnectionRunner> iter = _runners.values().iterator(); iter.hasNext(); ) { + ClientConnectionRunner cur = iter.next(); if (cur.getDestHash().equals(destHash)) return cur; } @@ -354,8 +366,8 @@ public class ClientManager { } } - Set getRunnerDestinations() { - Set dests = new HashSet(); + Set<Destination> getRunnerDestinations() { + Set<Destination> dests = new HashSet(); long beforeLock = _ctx.clock().now(); long inLock = 0; synchronized (_runners) { @@ -390,13 +402,13 @@ public class ClientManager { StringBuilder buf = new StringBuilder(8*1024); buf.append("<u><b>Local destinations</b></u><br>"); - Map runners = null; + Map<Destination, ClientConnectionRunner> runners = null; synchronized (_runners) { runners = (Map)_runners.clone(); } - for (Iterator iter = runners.keySet().iterator(); iter.hasNext(); ) { - Destination dest = (Destination)iter.next(); - ClientConnectionRunner runner = (ClientConnectionRunner)runners.get(dest); + for (Iterator<Destination> iter = runners.keySet().iterator(); iter.hasNext(); ) { + Destination dest = iter.next(); + ClientConnectionRunner runner = runners.get(dest); buf.append("<b>*</b> ").append(dest.calculateHash().toBase64().substring(0,6)).append("<br>\n"); LeaseSet ls = runner.getLeaseSet(); if (ls == null) { diff --git a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java index 9e706beda02fcc7449cf19214a08eb722f7744fe..e90d12f53599c7facc7c17b967c3ddc7b0c5cc5d 100644 --- a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java +++ b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java @@ -194,7 +194,7 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade { * Return the client's current manager or null if not connected * */ - public SessionKeyManager getClientSessionKeyManager(Destination dest) { + public SessionKeyManager getClientSessionKeyManager(Hash dest) { if (_manager != null) return _manager.getClientSessionKeyManager(dest); else { @@ -215,7 +215,7 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade { * @return set of Destination objects */ @Override - public Set listClients() { + public Set<Destination> listClients() { if (_manager != null) return _manager.listClients(); else diff --git a/router/java/src/net/i2p/router/message/BuildTestMessageJob.java b/router/java/test/net/i2p/router/message/BuildTestMessageJob.java similarity index 100% rename from router/java/src/net/i2p/router/message/BuildTestMessageJob.java rename to router/java/test/net/i2p/router/message/BuildTestMessageJob.java diff --git a/router/java/src/net/i2p/router/message/SendGarlicJob.java b/router/java/test/net/i2p/router/message/SendGarlicJob.java similarity index 100% rename from router/java/src/net/i2p/router/message/SendGarlicJob.java rename to router/java/test/net/i2p/router/message/SendGarlicJob.java