diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/DHT.java b/apps/i2psnark/java/src/org/klomp/snark/dht/DHT.java
index 5dc1c0a62579261329e8af00741d054acb701fed..16d2edd65b3ca8f9edd9ef4463c14fe7522b6c04 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/dht/DHT.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/dht/DHT.java
@@ -44,7 +44,7 @@ public interface DHT {
      *  @param max maximum number of peers to return
      *  @param maxWait the maximum time to wait (ms) must be > 0
      *  @param annMax the number of peers to announce to
-     *  @param maxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
+     *  @param annMaxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
      *  @return possibly empty (never null)
      */
     public Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait, int annMax, long annMaxWait);
diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java
index bfaf808f8886ba0fcd54603fa64d784bc569a095..e9fca89b1f94019a66c0115a23856a07bddda23d 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/dht/KRPC.java
@@ -317,7 +317,7 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
      *  @param max maximum number of peers to return
      *  @param maxWait the maximum time to wait (ms) must be > 0
      *  @param annMax the number of peers to announce to
-     *  @param maxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
+     *  @param annMaxWait the maximum total time to wait for announces, may be 0 to return immediately without waiting for acks
      *  @return possibly empty (never null)
      */
     public Collection<Hash> getPeersAndAnnounce(byte[] ih, int max, long maxWait, int annMax, long annMaxWait) {
diff --git a/core/java/src/net/i2p/data/Destination.java b/core/java/src/net/i2p/data/Destination.java
index 76f64304489da4ef9fbaabeac3ac3ad1467216cc..1eab390bbb09925fa1bd73a153adcc2b2c91844a 100644
--- a/core/java/src/net/i2p/data/Destination.java
+++ b/core/java/src/net/i2p/data/Destination.java
@@ -108,7 +108,7 @@ public class Destination extends KeysAndCert {
     }
     
     /**
-     * @deprecated, was used only by Packet.java in streaming, now unused
+     * @deprecated was used only by Packet.java in streaming, now unused
      *
      * @throws IllegalStateException if data already set
      */
diff --git a/core/java/test/junit/net/i2p/util/LogSettings.java b/core/java/test/junit/net/i2p/util/LogSettings.java
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/core/java/test/junit/net/i2p/util/LogSettingsTest.java b/core/java/test/junit/net/i2p/util/LogSettingsTest.java
index 123d0863ddbc828810f8bd880b30b00b6debb514..5335f8c701e8c826b6816b82026c4e3c26c4779a 100644
--- a/core/java/test/junit/net/i2p/util/LogSettingsTest.java
+++ b/core/java/test/junit/net/i2p/util/LogSettingsTest.java
@@ -54,12 +54,12 @@ public class LogSettingsTest extends TestCase {
             temp.close();
         }
         DataHelper.loadProps(p, f);
-        origMinimumOnScreenLevel = p.getProperty("logger.record.net.i2p.util.LogSettings", Log.STR_ERROR);
+        origMinimumOnScreenLevel = p.getProperty("logger.record.net.i2p.util.LogSettingsTest", Log.STR_ERROR);
         origLogSettings = p.getProperty("logger.minimumOnScreenLevel", Log.STR_CRIT);
     }
 
     protected void tearDown() throws IOException{
-	    p.setProperty("logger.record.net.i2p.util.LogSettings", origMinimumOnScreenLevel);
+        p.setProperty("logger.record.net.i2p.util.LogSettingsTest", origMinimumOnScreenLevel);
         p.setProperty("logger.minimumOnScreenLevel", origLogSettings);
         DataHelper.storeProps(p, f);
         
@@ -67,7 +67,7 @@ public class LogSettingsTest extends TestCase {
     }
 
     public void testDebug() throws IOException {
-        p.setProperty("logger.record.net.i2p.util.LogSettings", Log.toLevelString(Log.DEBUG));
+        p.setProperty("logger.record.net.i2p.util.LogSettingsTest", Log.toLevelString(Log.DEBUG));
         p.setProperty("logger.minimumOnScreenLevel", Log.toLevelString(Log.DEBUG));
         
         DataHelper.storeProps(p, f);
@@ -118,7 +118,7 @@ public class LogSettingsTest extends TestCase {
     }
 
     public void testInfo() throws IOException {
-        p.setProperty("logger.record.net.i2p.util.LogSettings", Log.toLevelString(Log.INFO));
+        p.setProperty("logger.record.net.i2p.util.LogSettingsTest", Log.toLevelString(Log.INFO));
         p.setProperty("logger.minimumOnScreenLevel", Log.toLevelString(Log.DEBUG));
         
     	DataHelper.storeProps(p, f);
@@ -166,7 +166,7 @@ public class LogSettingsTest extends TestCase {
     }
 
     public void testWarn() throws IOException {
-        p.setProperty("logger.record.net.i2p.util.LogSettings", Log.toLevelString(Log.WARN));
+        p.setProperty("logger.record.net.i2p.util.LogSettingsTest", Log.toLevelString(Log.WARN));
         p.setProperty("logger.minimumOnScreenLevel", Log.toLevelString(Log.DEBUG));
         
     	DataHelper.storeProps(p, f);
@@ -211,7 +211,7 @@ public class LogSettingsTest extends TestCase {
     }
 
     public void testError() throws IOException{
-        p.setProperty("logger.record.net.i2p.util.LogSettings", Log.toLevelString(Log.ERROR));
+        p.setProperty("logger.record.net.i2p.util.LogSettingsTest", Log.toLevelString(Log.ERROR));
         p.setProperty("logger.minimumOnScreenLevel", Log.toLevelString(Log.DEBUG));
         
     	DataHelper.storeProps(p, f);
@@ -254,7 +254,7 @@ public class LogSettingsTest extends TestCase {
     }
 
     public void testCrit() throws IOException {
-        p.setProperty("logger.record.net.i2p.util.LogSettings", Log.toLevelString(Log.CRIT));
+        p.setProperty("logger.record.net.i2p.util.LogSettingsTest", Log.toLevelString(Log.CRIT));
         p.setProperty("logger.minimumOnScreenLevel", Log.toLevelString(Log.DEBUG));
         
     	DataHelper.storeProps(p, f);
diff --git a/router/java/src/net/i2p/router/ClientMessage.java b/router/java/src/net/i2p/router/ClientMessage.java
index 8a247f5f1844033ef933d492bd5dbbb4ca1c083f..42dd8fb77797af21d74876c3ee50bf0503086f59 100644
--- a/router/java/src/net/i2p/router/ClientMessage.java
+++ b/router/java/src/net/i2p/router/ClientMessage.java
@@ -16,60 +16,83 @@ import net.i2p.data.i2cp.SessionConfig;
 
 /**
  * Wrap a message either destined for a local client or received from one.
+ * Note that an outbound message may get routed as an inbound message
+ * for local-local communication.
  *
  * @author jrandom
  */
 public class ClientMessage {
-    private Payload _payload;
-    private Destination _destination;
-    private Destination _fromDestination;
+    private final Payload _payload;
+    private final Destination _destination;
+    private final Destination _fromDestination;
     //private MessageReceptionInfo _receptionInfo;
-    private SessionConfig _senderConfig;
-    private Hash _destinationHash;
-    private MessageId _messageId;
-    private long _expiration;
+    private final SessionConfig _senderConfig;
+    private final Hash _destinationHash;
+    private final MessageId _messageId;
+    private final long _expiration;
     /** only for outbound messages */
-    private int _flags;
+    private final int _flags;
     
-    public ClientMessage() {
+    /**
+     *  For outbound (locally originated)
+     *  @since 0.9.9
+     */
+    public ClientMessage(Destination toDest, Payload payload, SessionConfig config, Destination fromDest,
+                         MessageId msgID, long expiration, int flags) {
+        _destination = toDest;
+        _destinationHash = null;
+        _payload = payload;
+        _senderConfig = config;
+        _fromDestination = fromDest;
+        _messageId = msgID;
+        _expiration = expiration;
+        _flags = flags;
+    }
+    
+    /**
+     *  For inbound (from remote dest)
+     *  @since 0.9.9
+     */
+    public ClientMessage(Hash toDestHash, Payload payload) {
+        _destination = null;
+        _destinationHash = toDestHash;
+        _payload = payload;
+        _senderConfig = null;
+        _fromDestination = null;
+        _messageId = null;
+        _expiration = 0;
+        _flags = 0;
     }
     
     /**
      * Retrieve the payload of the message.  All ClientMessage objects should have
      * a payload
-     *
      */
     public Payload getPayload() { return _payload; }
-    public void setPayload(Payload payload) { _payload = payload; }
     
     /**
-     * Retrieve the destination to which this message is directed.  All ClientMessage
-     * objects should have a destination.
-     *
+     * Retrieve the destination to which this message is directed.
+     * Valid for outbound; null for inbound.
+     * If null, use getDestinationHash()
      */
     public Destination getDestination() { return _destination; }
-    public void setDestination(Destination dest) { _destination = dest; }
     
     /**
-     * 
-     *
+     * Valid for outbound; null for inbound.
      */
     public Destination getFromDestination() { return _fromDestination; }
-    public void setFromDestination(Destination dest) { _fromDestination = dest; }
     
     /**
-     * Retrieve the destination to which this message is directed.  All ClientMessage
-     * objects should have a destination.
-     *
+     * Retrieve the destination to which this message is directed.
+     * Valid for inbound; null for outbound.
+     * If null, use getDestination()
      */
     public Hash getDestinationHash() { return _destinationHash; }
-    public void setDestinationHash(Hash dest) { _destinationHash = dest; }
     
     /**
-     * 
+     * Valid for outbound; null for inbound.
      */
     public MessageId getMessageId() { return _messageId; }
-    public void setMessageId(MessageId id) { _messageId = id; }
     
     /**
      * Retrieve the information regarding how the router received this message.  Only
@@ -83,18 +106,14 @@ public class ClientMessage {
     /**
      * Retrieve the session config of the client that sent the message.  This will only be available
      * if the client was local
-     *
      */
     public SessionConfig getSenderConfig() { return _senderConfig; }
-    public void setSenderConfig(SessionConfig config) { _senderConfig = config; }
 
     /**
      * Expiration requested by the client that sent the message.  This will only be available
      * for locally originated messages.
-     *
      */
     public long getExpiration() { return _expiration; }
-    public void setExpiration(long e) { _expiration = e; }
 
     /**
      * Flags requested by the client that sent the message.  This will only be available
@@ -103,9 +122,4 @@ public class ClientMessage {
      * @since 0.8.4
      */
     public int getFlags() { return _flags; }
-
-    /**
-     * @since 0.8.4
-     */
-    public void setFlags(int f) { _flags = f; }
 }
diff --git a/router/java/src/net/i2p/router/client/ClientManager.java b/router/java/src/net/i2p/router/client/ClientManager.java
index 21cac726ad9b0c81a79100b576efbbb917196f22..e259c91aba647add67a4936438b3168795962869 100644
--- a/router/java/src/net/i2p/router/client/ClientManager.java
+++ b/router/java/src/net/i2p/router/client/ClientManager.java
@@ -244,14 +244,9 @@ class ClientManager {
                 // sender went away
                 return;
             }
-            ClientMessage msg = new ClientMessage();
-            msg.setDestination(toDest);
-            msg.setPayload(payload);
-            msg.setSenderConfig(runner.getConfig());
-            msg.setFromDestination(runner.getConfig().getDestination());
-            msg.setMessageId(msgId);
-            msg.setExpiration(expiration);
-            msg.setFlags(flags);
+            ClientMessage msg = new ClientMessage(toDest, payload, runner.getConfig(),
+                                                  runner.getConfig().getDestination(), msgId,
+                                                  expiration, flags);
             _ctx.clientMessagePool().add(msg, true);
         }
     }
diff --git a/router/java/src/net/i2p/router/transport/TransportUtil.java b/router/java/src/net/i2p/router/transport/TransportUtil.java
index 61df53e9473fab894f1e8d832b91836e592b98a2..0332a9105b4d112d1b4a039e3d7570c5335a34c2 100644
--- a/router/java/src/net/i2p/router/transport/TransportUtil.java
+++ b/router/java/src/net/i2p/router/transport/TransportUtil.java
@@ -131,25 +131,29 @@ public abstract class TransportUtil {
                 // IPv4 compat ::xxxx:xxxx
                 if (addr[0] == 0)
                     return false;
-                // disallow 2002::/16 (6to4 RFC 3056)
-                if (addr[0] == 0x20 && addr[1] == 0x02)
-                    return false;
+                if (addr[0] == 0x20) {
+                    // disallow 2002::/16 (6to4 RFC 3056)
+                    if (addr[1] == 0x02)
+                        return false;
+                    if (addr[1] == 0x01) {
+                        // disallow 2001:0::/32 (Teredo RFC 4380)
+                        if (addr[2] == 0x00 && addr[3] == 0x00)
+                            return false;
+                        // Documenation (example) RFC 3849
+                        if (addr[2] == 0x0d && (addr[3] & 0xff) == 0xb8)
+                            return false;
+                    }
+                }
                 // disallow fc00::/8 and fd00::/8 (Unique local addresses RFC 4193)
                 // not recognized as local by InetAddress
                 if ((addr[0] & 0xfe) == 0xfc)
                     return false;
-                // disallow 2001:0::/32 (Teredo RFC 4380)
-                if (addr[0] == 0x20 && addr[1] == 0x01 && addr[2] == 0x00 && addr[3] == 0x00)
-                    return false;
                 // Hamachi IPv6
                 if (addr[0] == 0x26 && addr[1] == 0x20 && addr[2] == 0x00 && (addr[3] & 0xff) == 0x9b)
                     return false;
                 // 6bone RFC 2471
                 if (addr[0] == 0x3f && (addr[1] & 0xff) == 0xfe)
                     return false;
-                // Documenation (example) RFC 3849
-                if (addr[0] == 0x20 && addr[1] == 0x01 && addr[2] == 0x0d && (addr[3] & 0xff) == 0xb8)
-                    return false;
                 try {
                     InetAddress ia = InetAddress.getByAddress(addr);
                     return
diff --git a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
index cbcc1887d5da513ccaadba6cbb9b4f398f1e89df..d886d61927c4b719c67f458ccad3995d4ba33d6b 100644
--- a/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
+++ b/router/java/src/net/i2p/router/tunnel/InboundMessageDistributor.java
@@ -223,9 +223,7 @@ class InboundMessageDistributor implements GarlicMessageReceiver.CloveReceiver {
                     DataMessage dm = (DataMessage)data;
                     Payload payload = new Payload();
                     payload.setEncryptedData(dm.getData());
-                    ClientMessage m = new ClientMessage();
-                    m.setDestinationHash(_client);
-                    m.setPayload(payload);
+                    ClientMessage m = new ClientMessage(_client, payload);
                     _context.clientManager().messageReceived(m);
                 } else {
                     if (_log.shouldLog(Log.ERROR))