diff --git a/core/java/src/net/i2p/util/Addresses.java b/core/java/src/net/i2p/util/Addresses.java
index 15352975bc8bf14fdac88f634f1dcdfe0bff478b..db28be6baa8169b88402ffb1dbf6f17fc502fa38 100644
--- a/core/java/src/net/i2p/util/Addresses.java
+++ b/core/java/src/net/i2p/util/Addresses.java
@@ -4,14 +4,21 @@ package net.i2p.util;
  * public domain
  */
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.net.InetAddress;
 import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -21,6 +28,8 @@ import java.util.TreeSet;
 import org.apache.http.conn.util.InetAddressUtils;
 
 import net.i2p.I2PAppContext;
+import net.i2p.data.DataHelper;
+
 
 /**
  * Methods to get the local addresses, and other IP utilities
@@ -30,6 +39,16 @@ import net.i2p.I2PAppContext;
  */
 public abstract class Addresses {
     
+    private static final File IF_INET6_FILE = new File("/proc/net/if_inet6");
+    private static final long INET6_CACHE_EXPIRE = 10*60*1000;
+    private static final boolean INET6_CACHE_ENABLED = !SystemVersion.isMac() && !SystemVersion.isWindows() &&
+                                                    !SystemVersion.isAndroid() && IF_INET6_FILE.exists();
+    private static final int FLAG_PERMANENT = 0x80;
+    private static final int FLAG_DEPRECATED = 0x20;
+    private static final int FLAG_TEMPORARY = 0x01;
+    private static long _ifCacheTime;
+    private static final Map<Inet6Address, Inet6Addr> _ifCache = INET6_CACHE_ENABLED ? new HashMap<Inet6Address, Inet6Addr>(8) : null;
+
     /**
      *  Do we have any non-loop, non-wildcard IPv4 address at all?
      *  @since 0.9.4
@@ -101,18 +120,25 @@ public abstract class Addresses {
         boolean haveIPv4 = false;
         boolean haveIPv6 = false;
         SortedSet<String> rv = new TreeSet<String>();
+        final boolean omitDeprecated = INET6_CACHE_ENABLED && !includeSiteLocal && includeIPv6;
         try {
             InetAddress localhost = InetAddress.getLocalHost();
             InetAddress[] allMyIps = InetAddress.getAllByName(localhost.getCanonicalHostName());
             if (allMyIps != null) {
                 for (int i = 0; i < allMyIps.length; i++) {
-                    if (allMyIps[i] instanceof Inet4Address)
+                    boolean isv4 = allMyIps[i] instanceof Inet4Address;
+                    if (isv4)
                         haveIPv4 = true;
                     else
                         haveIPv6 = true;
+                    if (omitDeprecated && !isv4) {
+                        if (isDeprecated((Inet6Address) allMyIps[i]))
+                            continue;
+                    }
                     if (shouldInclude(allMyIps[i], includeSiteLocal,
-                                      includeLoopbackAndWildcard, includeIPv6))
+                                      includeLoopbackAndWildcard, includeIPv6)) {
                         rv.add(stripScope(allMyIps[i].getHostAddress()));
+                    }
                 }
             }
         } catch (UnknownHostException e) {}
@@ -124,13 +150,19 @@ public abstract class Addresses {
                     NetworkInterface ifc = ifcs.nextElement();
                     for(Enumeration<InetAddress> addrs =  ifc.getInetAddresses(); addrs.hasMoreElements();) {
                         InetAddress addr = addrs.nextElement();
-                        if (addr instanceof Inet4Address)
+                        boolean isv4 = addr instanceof Inet4Address;
+                        if (isv4)
                             haveIPv4 = true;
                         else
                             haveIPv6 = true;
+                        if (omitDeprecated && !isv4) {
+                            if (isDeprecated((Inet6Address) addr))
+                                continue;
+                        }
                         if (shouldInclude(addr, includeSiteLocal,
-                                          includeLoopbackAndWildcard, includeIPv6))
+                                          includeLoopbackAndWildcard, includeIPv6)) {
                             rv.add(stripScope(addr.getHostAddress()));
+                        }
                     }
                 }
             }
@@ -333,8 +365,8 @@ public abstract class Addresses {
 
     /**
      *  For literal IP addresses, this is the same as getIP(String).
-     *  For host names, will return the preferred type (IPv4/v6) if available,
-     *  else the other type if available.
+     *  For host names, may return multiple addresses, both IPv4 and IPv6,
+     *  even if those addresses are not reachable due to configuration or available interfaces.
      *  Will resolve but not cache DNS host names.
      *
      *  Note that order of returned results, and whether
@@ -370,6 +402,136 @@ public abstract class Addresses {
         return null;
     }
 
+    //////// IPv6 Cache Utils ///////
+
+    /**
+     *  @since 0.9.28
+     */
+    private static class Inet6Addr {
+        private final Inet6Address addr;
+        private final boolean isDyn, isDep, isTemp;
+
+        public Inet6Addr(Inet6Address a, int flags) {
+            addr = a;
+            isDyn = (flags & FLAG_PERMANENT) == 0;
+            isDep = (flags & FLAG_DEPRECATED) != 0;
+            isTemp = (flags & FLAG_TEMPORARY) != 0;
+        }
+
+        public Inet6Address getAddress() { return addr; }
+        public boolean isDynamic() { return isDyn; }
+        public boolean isDeprecated() { return isDep; }
+        public boolean isTemporary() { return isTemp; }
+    }
+
+    /**
+     *  Only call if INET6_CACHE_ENABLED.
+     *  Caller must sync on _ifCache.
+     *  @since 0.9.28
+     */
+    private static void refreshCache() {
+        long now = System.currentTimeMillis();
+        if (now - _ifCacheTime < INET6_CACHE_EXPIRE)
+            return;
+        _ifCache.clear();
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new InputStreamReader(new FileInputStream(IF_INET6_FILE), "ISO-8859-1"), 4096);
+            String line = null;
+            while ( (line = in.readLine()) != null) {
+                // http://tldp.org/HOWTO/html_single/Linux+IPv6-HOWTO/#PROC-NET
+                // 00000000000000000000000000000001 01 80 10 80       lo
+                String[] parts = DataHelper.split(line, " ", 6);
+                if (parts.length < 5)
+                    continue;
+                String as = parts[0];
+                if (as.length() != 32)
+                    continue;
+                StringBuilder buf = new StringBuilder(40);
+                int i = 0;
+                while(true) {
+                    buf.append(as.substring(i, i+4));
+                    i += 4;
+                    if (i >= 32)
+                        break;
+                    buf.append(':');
+                }
+                Inet6Address addr;
+                try {
+                    addr = (Inet6Address) InetAddress.getByName(buf.toString());
+                } catch (UnknownHostException uhe) {
+                    continue;
+                }
+                int flags = FLAG_PERMANENT;
+                try {
+                    flags = Integer.parseInt(parts[4], 16);
+                } catch (NumberFormatException nfe) {}
+                Inet6Addr a = new Inet6Addr(addr, flags);
+                _ifCache.put(addr, a);
+            }
+        } catch (IOException ioe) {
+        } finally {
+            if (in != null) try { in.close(); } catch (IOException ioe) {}
+        }
+        _ifCacheTime = now;
+    }
+
+    /**
+     *  Is this address dynamic?
+     *  Returns false if unknown.
+     *  @since 0.9.28
+     */
+    public static boolean isDynamic(Inet6Address addr) {
+        if (!INET6_CACHE_ENABLED)
+            return false;
+        Inet6Addr a;
+        synchronized(_ifCache) {
+            refreshCache();
+            a = _ifCache.get(addr);
+        }
+        if (a == null)
+            return false;
+        return a.isDynamic();
+    }
+
+    /**
+     *  Is this address deprecated?
+     *  Returns false if unknown.
+     *  @since 0.9.28
+     */
+    public static boolean isDeprecated(Inet6Address addr) {
+        if (!INET6_CACHE_ENABLED)
+            return false;
+        Inet6Addr a;
+        synchronized(_ifCache) {
+            refreshCache();
+            a = _ifCache.get(addr);
+        }
+        if (a == null)
+            return false;
+        return a.isDeprecated();
+    }
+
+    /**
+     *  Is this address temporary?
+     *  Returns false if unknown.
+     *  @since 0.9.28
+     */
+    public static boolean isTemporary(Inet6Address addr) {
+        if (!INET6_CACHE_ENABLED)
+            return false;
+        Inet6Addr a;
+        synchronized(_ifCache) {
+            refreshCache();
+            a = _ifCache.get(addr);
+        }
+        if (a == null)
+            return false;
+        return a.isTemporary();
+    }
+
+    //////// End IPv6 Cache Utils ///////
+
     /**
      *  @since 0.9.3
      */
@@ -377,32 +539,66 @@ public abstract class Addresses {
         synchronized(_IPAddress) {
             _IPAddress.clear();
         }
+        if (_ifCache != null) {
+            synchronized(_ifCache) {
+                _ifCache.clear();
+                _ifCacheTime = 0;
+            }
+        }
     }
 
     /**
      *  Print out the local addresses
      */
     public static void main(String[] args) {
-        System.err.println("External IPv4 Addresses:");
+        System.out.println("External IPv4 Addresses:");
         Set<String> a = getAddresses(false, false, false);
         for (String s : a)
-            System.err.println(s);
-        System.err.println("\nExternal and Local IPv4 Addresses:");
+            System.out.println(s);
+        System.out.println("\nExternal and Local IPv4 Addresses:");
         a = getAddresses(true, false, false);
         for (String s : a)
-            System.err.println(s);
-        System.err.println("\nAll External Addresses:");
+            System.out.println(s);
+        System.out.println("\nAll External Addresses:");
         a = getAddresses(false, false, true);
         for (String s : a)
-            System.err.println(s);
-        System.err.println("\nAll External and Local Addresses:");
+            System.out.println(s);
+        System.out.println("\nAll External and Local Addresses:");
         a = getAddresses(true, false, true);
         for (String s : a)
-            System.err.println(s);
-        System.err.println("\nAll addresses:");
+            System.out.println(s);
+        System.out.println("\nAll addresses:");
         a = getAddresses(true, true, true);
         for (String s : a)
-            System.err.println(s);
-        System.err.println("\nIs connected? " + isConnected());
+            System.out.println(s);
+        System.out.println("\nIPv6 address flags:");
+        for (String s : a) {
+            if (!s.contains(":"))
+                continue;
+            StringBuilder buf = new StringBuilder(64);
+            buf.append(s);
+            Inet6Address addr;
+            try {
+                addr = (Inet6Address) InetAddress.getByName(buf.toString());
+                if (addr.isSiteLocalAddress())
+                    buf.append(" host");
+                else if (addr.isLinkLocalAddress())
+                    buf.append(" link");
+                else if (addr.isAnyLocalAddress())
+                    buf.append(" wildcard");
+                else if (addr.isLoopbackAddress())
+                    buf.append(" loopback");
+                else
+                    buf.append(" global");
+                if (isTemporary(addr))
+                    buf.append(" temporary");
+                if (isDeprecated(addr))
+                    buf.append(" deprecated");
+                if (isDynamic(addr))
+                    buf.append(" dynamic");
+            } catch (UnknownHostException uhe) {}
+            System.out.println(buf.toString());
+        }
+        System.out.println("\nIs connected? " + isConnected());
     }
 }
diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java
index 80888ead7bf56787c6977a14b38ca1367a2dd9b2..9e6c9a953c29a27c1b7767793450abe99a057925 100644
--- a/router/java/src/net/i2p/router/transport/TransportManager.java
+++ b/router/java/src/net/i2p/router/transport/TransportManager.java
@@ -11,6 +11,7 @@ package net.i2p.router.transport;
 import java.io.IOException;
 import java.io.Writer;
 import java.net.InetAddress;
+import java.net.Inet6Address;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -165,7 +166,7 @@ public class TransportManager implements TransportEventListener {
                 // so that NTCP may bind early
                 int port = udp.getRequestedPort();
                 if (port > 0)
-                    ntcp.externalAddressReceived(SOURCE_CONFIG, null, port);
+                    ntcp.externalAddressReceived(SOURCE_CONFIG, (byte[]) null, port);
             }
         }
         if (_transports.isEmpty())
@@ -182,15 +183,52 @@ public class TransportManager implements TransportEventListener {
      */
     private void initializeAddress(Transport t) {
         Set<String> ipset = Addresses.getAddresses(false, true);  // non-local, include IPv6
+        //
+        // Avoid IPv6 temporary addresses if we have a non-temporary one
+        //
+        boolean hasNonTempV6Address = false;
+        List<InetAddress> addresses = new ArrayList<InetAddress>(4);
+        List<Inet6Address> tempV6Addresses = new ArrayList<Inet6Address>(4);
         for (String ips : ipset) {
             try {
-                InetAddress ia = InetAddress.getByName(ips);
-                byte[] ip = ia.getAddress();
-                t.externalAddressReceived(SOURCE_INTERFACE, ip, 0);
+                InetAddress addr = InetAddress.getByName(ips);
+                if (ips.contains(":") && (addr instanceof Inet6Address)) {
+                    Inet6Address v6addr = (Inet6Address) addr;
+                    // getAddresses(false, true) will not return deprecated addresses
+                    //if (Addresses.isDeprecated(v6addr)) {
+                    //    if (_log.shouldWarn())
+                    //        _log.warn("Not binding to deprecated temporary address " + bt);
+                    //    continue;
+                    //}
+                    if (Addresses.isTemporary(v6addr)) {
+                        // Save temporary addresses
+                        // we only use these if we don't have a non-temporary adress
+                        tempV6Addresses.add(v6addr);
+                        continue;
+                    }
+                    hasNonTempV6Address = true;
+                }
+                addresses.add(addr);
             } catch (UnknownHostException e) {
                 _log.error("UDP failed to bind to local address", e);
             }
         }
+        // we only use these if we don't have a non-temporary adress
+        if (!tempV6Addresses.isEmpty()) {
+            if (hasNonTempV6Address) {
+                if (_log.shouldWarn()) {
+                    for (Inet6Address addr : tempV6Addresses) {
+                        _log.warn("Not binding to temporary address " + addr.getHostAddress());
+                    }
+                }
+            } else {
+                addresses.addAll(tempV6Addresses);
+            }
+        }
+        for (InetAddress ia : addresses) {
+            byte[] ip = ia.getAddress();
+            t.externalAddressReceived(SOURCE_INTERFACE, ip, 0);
+        }
     }
 
     /**