diff --git a/history.txt b/history.txt
index bf03074db7dec032ef70754f695c5b01e3355306..549fa8c61d5d4d4cf549d45314f96092b92cdfd8 100644
--- a/history.txt
+++ b/history.txt
@@ -1,3 +1,9 @@
+2012-10-08 zzz
+ * SSU:
+   - Fix relay request handling bug from -10
+   - Fix peer test reply handling bug from -10
+   - Fix NPE from -6
+
 2012-10-07 zzz
  * I2PAppContext: Improved synching in constructor
  * i2ptunnel:
diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java
index 5a58b19bc22ea9b489b5610aade18177efc4505e..e36cd3b14352a16a1e79c5fea474cb2f20cbaa5c 100644
--- a/router/java/src/net/i2p/router/RouterVersion.java
+++ b/router/java/src/net/i2p/router/RouterVersion.java
@@ -18,7 +18,7 @@ public class RouterVersion {
     /** deprecated */
     public final static String ID = "Monotone";
     public final static String VERSION = CoreVersion.VERSION;
-    public final static long BUILD = 11;
+    public final static long BUILD = 12;
 
     /** for example "-test" */
     public final static String EXTRA = "";
diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java
index 2b71deb2cb1440c9f28ae0a8f582fdbfa4f19fbd..fc2e9103dbc0aa2e52703127af20d75d733577e1 100644
--- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java
@@ -327,13 +327,16 @@ class IntroductionManager {
         UDPPacketReader.RelayRequestReader rrReader = reader.getRelayRequestReader();
         long tag = rrReader.readTag();
         int ipSize = rrReader.readIPSize();
-        byte ip[] = new byte[ipSize];
-        rrReader.readIP(ip, 0);
         int port = rrReader.readPort();
 
-        if ((!isValid(ip, port)) || (!isValid(alice.getIP(), alice.getPort()))) {
-            if (_log.shouldLog(Log.WARN))
+        // ip/port inside message should be 0:0, as it's unimplemented on send -
+        // see PacketBuilder.buildRelayRequest()
+        if (!isValid(alice.getIP(), alice.getPort()) || ipSize != 0 || port != 0) {
+            if (_log.shouldLog(Log.WARN)) {
+                byte ip[] = new byte[ipSize];
+                rrReader.readIP(ip, 0);
                 _log.warn("Bad relay req from " + alice + " for " + Addresses.toString(ip, port));
+            }
             _context.statManager().addRateData("udp.relayBadIP", 1);
             return;
         }
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java
index db77b6af8835ad1f893b41e76668d30eaebe83c8..964e79332896f409869890fd9b8ac0f40ff44049 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerState.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java
@@ -1863,6 +1863,7 @@ class PeerState {
     /**
      * Transfer the basic activity/state from the old peer to the current peer
      *
+     * @param oldPeer non-null
      */
     public void loadFrom(PeerState oldPeer) {
         _rto = oldPeer._rto;
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
index 8d502d86280ef140df44d7376fb8dcd31448d312..d95202057735bf72ffca1b11c46bb5d32ec93fc2 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java
@@ -448,8 +448,8 @@ class PeerTestManager {
         }
 
         if ((testPort > 0 && (testPort < 1024 || testPort > 65535)) ||
-            (testIP != null && (Arrays.equals(testIP, _transport.getExternalIP()) ||
-                                (!_transport.isValid(testIP)) ||
+            (testIP != null &&
+                               ((!_transport.isValid(testIP)) ||
                                 _context.blocklist().isBlocklisted(testIP)))) {
             // spoof check, and don't respond to privileged ports
             if (_log.shouldLog(Log.WARN))
@@ -461,6 +461,7 @@ class PeerTestManager {
         // The from IP/port and message's IP/port are now validated.
         // EXCEPT that either the message's IP could be empty or the message's port could be 0.
         // Both of those cases should be checked in receiveXfromY() as appropriate.
+        // Also, IP could be us, check is below.
 
         long nonce = testInfo.readNonce();
         PeerTestState test = _currentTest;
@@ -472,6 +473,15 @@ class PeerTestManager {
 
         // we are Bob or Charlie
 
+        if (testIP != null && Arrays.equals(testIP, _transport.getExternalIP())) {
+            // spoof check - have to do this after receiveTestReply(), since
+            // the field should be us there
+            if (_log.shouldLog(Log.WARN))
+                _log.warn("Invalid address in PeerTest: " + Addresses.toString(testIP, testPort));
+            _context.statManager().addRateData("udp.testBadIP", 1);
+            return;
+        }
+
         PeerTestState state = _activeTests.get(Long.valueOf(nonce));
         
         if (state == null) {
@@ -600,6 +610,7 @@ class PeerTestManager {
      * The PeerTest message came from the peer referenced in the message (or there wasn't
      * any info in the message), plus we are not acting as Charlie (so we've got to be Bob).
      *
+     * testInfo IP/port ignored
      */
     private void receiveFromAliceAsBob(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) {
         // we are Bob, so pick a (potentially) Charlie and send Charlie Alice's info
@@ -692,10 +703,11 @@ class PeerTestManager {
      * The PeerTest message came from one of the Charlies picked for an existing test, so send Alice the
      * packet verifying participation.
      *
+     * testInfo IP/port ignored
      */
     private void receiveFromCharlieAsBob(RemoteHostId from, PeerTestState state) {
         state.setReceiveCharlieTime(_context.clock().now());
-        
+
         state.incrementPacketsRelayed();
         if (state.getPacketsRelayed() > MAX_RELAYED_PER_TEST) {
             if (_log.shouldLog(Log.WARN))
@@ -716,6 +728,7 @@ class PeerTestManager {
     /** 
      * We are charlie, so send Alice her PeerTest message  
      *
+     * testInfo IP/port ignored
      */
     private void receiveFromAliceAsCharlie(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce) {
         try {
@@ -723,7 +736,7 @@ class PeerTestManager {
             SessionKey aliceIntroKey = new SessionKey(new byte[SessionKey.KEYSIZE_BYTES]);
             testInfo.readIntroKey(aliceIntroKey.getData(), 0);
             UDPPacket packet = _packetBuilder.buildPeerTestToAlice(aliceIP, from.getPort(), aliceIntroKey, _transport.getIntroKey(), nonce);
-            
+
             if (_log.shouldLog(Log.DEBUG))
                 _log.debug("Receive from alice as charlie, w/ alice @ " + aliceIP + ":" + from.getPort() + " and nonce " + nonce);
             
diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
index ea81096b9c36778f2fc4f734ab4a7f436cf29d81..341977733074bdc53072a0018a2dc0dcd90c7cf8 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -892,8 +892,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
             if (_log.shouldLog(Log.WARN))
                 _log.warn("Peer already connected (PBRH): old=" + oldPeer2 + " new=" + peer);
             // transfer over the old state/inbound message fragments/etc
-            peer.loadFrom(oldPeer);
-            oldEstablishedOn = oldPeer.getKeyEstablishedTime();
+            peer.loadFrom(oldPeer2);
+            oldEstablishedOn = oldPeer2.getKeyEstablishedTime();
             oldPeer2.dropOutbound();
             _introManager.remove(oldPeer2);
             _expireEvent.remove(oldPeer2);