diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
index 92746dffd1287897135f1329d4c1742b11e4af97..7a41faa2eef37b42b6e9e543a01c8aeced64fe25 100644
--- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
+++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java
@@ -943,16 +943,16 @@ class EstablishmentManager {
         _context.statManager().addRateData("udp.sendIntroRelayRequest", 1);
         List<UDPPacket> requests = _builder.buildRelayRequest(_transport, this, state, _transport.getIntroKey());
         if (requests.isEmpty()) {
-            // FIXME need a failed OB state
             if (_log.shouldLog(Log.WARN))
                 _log.warn("No valid introducers! " + state);
-            // set failed state, remove nonce, and return
+            processExpired(state);
+            return;
         }
         for (UDPPacket req : requests) {
             _transport.send(req);
         }
         if (_log.shouldLog(Log.DEBUG))
-            _log.debug("Send intro for " + state + " with our intro key as " + _transport.getIntroKey());
+            _log.debug("Send relay request for " + state + " with our intro key as " + _transport.getIntroKey());
         state.introSent();
     }
 
@@ -1043,13 +1043,13 @@ class EstablishmentManager {
 
     /**
      *  Are IP and port valid? This is only for checking the relay response.
-     *  Reject all IPv6, for now, even if we are configured for it.
+     *  Allow IPv6 as of 0.9.50.
      *  Refuse anybody in the same /16
      *  @since 0.9.3, pkg private since 0.9.45 for PacketBuider
      */
     boolean isValid(byte[] ip, int port) {
         return TransportUtil.isValidPort(port) &&
-               ip != null && ip.length == 4 &&
+               ip != null &&
                _transport.isValid(ip) &&
                (!_transport.isTooClose(ip)) &&
                (!_context.blocklist().isBlocklisted(ip));
@@ -1377,7 +1377,7 @@ class EstablishmentManager {
             boolean removed = _liveIntroductions.remove(Long.valueOf(nonce), outboundState);
             if (removed) {
                 if (_log.shouldLog(Log.DEBUG))
-                    _log.debug("Send intro for " + outboundState + " timed out");
+                    _log.debug("Relay request for " + outboundState + " timed out");
                 _context.statManager().addRateData("udp.sendIntroRelayTimeout", 1);
             }
         }
diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
index e36ceb8ff7e6643e5b593881826ca45eb59abd7f..991f832bb0e5cd4317e0e744d0dc150d31f40700 100644
--- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
+++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java
@@ -1224,7 +1224,7 @@ class PacketBuilder {
                 (Arrays.equals(iaddr.getAddress(), _transport.getExternalIP()) && !_transport.allowLocal())) {
                 if (_log.shouldLog(Log.WARN))
                     _log.warn("Cannot build a relay request for " + state.getRemoteIdentity().calculateHash()
-                               + ", as the introducer address is invalid: " + Addresses.toString(iaddr.getAddress(), iport));
+                               + ", introducer address is invalid or blocklisted: " + Addresses.toString(iaddr.getAddress(), iport));
                 // TODO implement some sort of introducer banlist
                 continue;
             }
@@ -1262,7 +1262,7 @@ class PacketBuilder {
                 rv.add(pkt);
             else if (_log.shouldWarn())
                 _log.warn("Cannot build a relay request for " + state.getRemoteIdentity().calculateHash()
-                          + ", as we don't have an IPv4 address to send to: " + Addresses.toString(iaddr.getAddress(), iport));
+                          + ", as we don't have an address to send to: " + Addresses.toString(iaddr.getAddress(), iport));
         }
         return rv;
     }
@@ -1278,18 +1278,28 @@ class PacketBuilder {
         byte data[] = pkt.getData();
         int off = HEADER_SIZE;
         
-        // Must specify these if request is going over IPv6
+        // Must specify these if request is going over IPv6 for v4 or vice versa
         byte ourIP[];
         int ourPort;
         if (introHost instanceof Inet6Address) {
-            RouterAddress ra = _transport.getCurrentExternalAddress(false);
-            if (ra == null)
-                return null;
-            ourIP = ra.getIP();
-            if (ourIP == null)
+            RouterAddress ra = _transport.getCurrentExternalAddress(true);
+            if (ra == null) {
+                ra = _transport.getCurrentExternalAddress(false);
+                if (ra == null)
+                    return null;
+            }
+            byte[] ip = ra.getIP();
+            if (ip == null)
                 return null;
-            ourPort = _transport.getRequestedPort();
+            if (ip.length != 16) {
+                ourIP = ip;
+                ourPort = _transport.getRequestedPort();
+            } else {
+                ourIP = null;
+                ourPort = 0;
+            }
         } else {
+            // TODO IPv4 introducer, IPv6 introduction
             ourIP = null;
             ourPort = 0;
         }
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 b0d721d5bd51970fa97af48a598224602c98a712..7c1e62a5ee305659e9a3c36ec25b182002f188d3 100644
--- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
+++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java
@@ -825,7 +825,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 if (DataHelper.eq(ip, 0, myip, 0, 2))
                     return true;
             } else if (ip.length == 16) {
-                if (DataHelper.eq(ip, 0, myip, 0, 8))
+                if (DataHelper.eq(ip, 0, myip, 0, 4))
                     return true;
             }
         }
@@ -1822,7 +1822,6 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
      *  @return 1 for ipv4, 2 for ipv6, 0 for neither
      */
     private int locked_needsRebuild() {
-        if (_needsRebuild) return 1; // assume ipv4
         if (_context.router().isHidden()) return 0;
         TransportUtil.IPv6Config config = getIPv6Config();
         // IPv4
@@ -1849,6 +1848,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
      *  @since 0.9.50 split out from above
      */
     private boolean locked_needsRebuild(RouterAddress addr, boolean ipv6) {
+        if (_needsRebuild)
+            return true;
         if (introducersRequired(ipv6)) {
             UDPAddress ua = new UDPAddress(addr);
             long now = _context.clock().now();
@@ -2043,6 +2044,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 return null;
             }
 
+            if (isUnreachable(to))
+                return null;
+
             // Validate his SSU address
             RouterAddress addr = getTargetAddress(toAddress);
             if (addr == null) {
@@ -2150,11 +2154,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 }
             } else {
                 // introducers
-                if (getIPv6Config() == IPV6_ONLY)
-                    continue;
-                // TODO support IPv6 introductions
                 String caps = addr.getOption(UDPAddress.PROP_CAPACITY);
-                if (caps != null && caps.contains(CAP_IPV6)   /* && !_haveIPv6Address */  )
+                if (caps != null && caps.contains(CAP_IPV6) && !_haveIPv6Address)
                     continue;
             }
             return addr;
@@ -2340,13 +2341,14 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
     }
     
     /**
-     * Rebuild to get updated cost and introducers. IPv4 only.
+     * Rebuild to get updated cost and introducers. IPv4 only, unless configured as IPv6 only.
      * Do not tell the router (he is the one calling this)
      * @since 0.7.12
      */
     @Override
     public List<RouterAddress> updateAddress() {
-        rebuildExternalAddress(false, false);
+        boolean ipv6 = getIPv6Config() == IPV6_ONLY;
+        rebuildExternalAddress(false, ipv6);
         return getCurrentAddresses();
     }
 
@@ -2672,8 +2674,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                 addr = null;
             }
         
-            if (!isIPv6)
-                _needsRebuild = false;
+            _needsRebuild = false;
             return addr;
         } else {
             if (_log.shouldLog(Log.WARN))
@@ -3311,8 +3312,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
                     } else if ((!haveCap || !peer.isInbound()) &&
                                peer.getMayDisconnect() &&
                                peer.getMessagesReceived() <= 2 && peer.getMessagesSent() <= 2) {
-                        if (_log.shouldInfo())
-                            _log.info("Possible early disconnect for: " + peer);
+                        //if (_log.shouldInfo())
+                        //    _log.info("Possible early disconnect for: " + peer);
                         inactivityCutoff = mayDisconCutoff;
                     } else {
                         inactivityCutoff = shortInactivityCutoff;