Changeset cd775fa for core


Ignore:
Timestamp:
Nov 8, 2016 3:24:30 AM (5 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
b559b41
Parents:
ab064fd
Message:

Transport: Improve IPv6 selection logic
to skip temporary addresses on linux

File:
1 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/util/Addresses.java

    rab064fd rcd775fa  
    55 */
    66
     7import java.io.BufferedReader;
     8import java.io.File;
     9import java.io.FileInputStream;
     10import java.io.IOException;
     11import java.io.InputStreamReader;
    712import java.net.InetAddress;
    813import java.net.Inet4Address;
     14import java.net.Inet6Address;
    915import java.net.NetworkInterface;
    1016import java.net.SocketException;
     
    1319import java.util.Collections;
    1420import java.util.Enumeration;
     21import java.util.HashMap;
    1522import java.util.List;
    1623import java.util.Map;
     
    2229
    2330import net.i2p.I2PAppContext;
     31import net.i2p.data.DataHelper;
     32
    2433
    2534/**
     
    3140public abstract class Addresses {
    3241   
     42    private static final File IF_INET6_FILE = new File("/proc/net/if_inet6");
     43    private static final long INET6_CACHE_EXPIRE = 10*60*1000;
     44    private static final boolean INET6_CACHE_ENABLED = !SystemVersion.isMac() && !SystemVersion.isWindows() &&
     45                                                    !SystemVersion.isAndroid() && IF_INET6_FILE.exists();
     46    private static final int FLAG_PERMANENT = 0x80;
     47    private static final int FLAG_DEPRECATED = 0x20;
     48    private static final int FLAG_TEMPORARY = 0x01;
     49    private static long _ifCacheTime;
     50    private static final Map<Inet6Address, Inet6Addr> _ifCache = INET6_CACHE_ENABLED ? new HashMap<Inet6Address, Inet6Addr>(8) : null;
     51
    3352    /**
    3453     *  Do we have any non-loop, non-wildcard IPv4 address at all?
     
    102121        boolean haveIPv6 = false;
    103122        SortedSet<String> rv = new TreeSet<String>();
     123        final boolean omitDeprecated = INET6_CACHE_ENABLED && !includeSiteLocal && includeIPv6;
    104124        try {
    105125            InetAddress localhost = InetAddress.getLocalHost();
     
    107127            if (allMyIps != null) {
    108128                for (int i = 0; i < allMyIps.length; i++) {
    109                     if (allMyIps[i] instanceof Inet4Address)
     129                    boolean isv4 = allMyIps[i] instanceof Inet4Address;
     130                    if (isv4)
    110131                        haveIPv4 = true;
    111132                    else
    112133                        haveIPv6 = true;
     134                    if (omitDeprecated && !isv4) {
     135                        if (isDeprecated((Inet6Address) allMyIps[i]))
     136                            continue;
     137                    }
    113138                    if (shouldInclude(allMyIps[i], includeSiteLocal,
    114                                       includeLoopbackAndWildcard, includeIPv6))
     139                                      includeLoopbackAndWildcard, includeIPv6)) {
    115140                        rv.add(stripScope(allMyIps[i].getHostAddress()));
     141                    }
    116142                }
    117143            }
     
    125151                    for(Enumeration<InetAddress> addrs =  ifc.getInetAddresses(); addrs.hasMoreElements();) {
    126152                        InetAddress addr = addrs.nextElement();
    127                         if (addr instanceof Inet4Address)
     153                        boolean isv4 = addr instanceof Inet4Address;
     154                        if (isv4)
    128155                            haveIPv4 = true;
    129156                        else
    130157                            haveIPv6 = true;
     158                        if (omitDeprecated && !isv4) {
     159                            if (isDeprecated((Inet6Address) addr))
     160                                continue;
     161                        }
    131162                        if (shouldInclude(addr, includeSiteLocal,
    132                                           includeLoopbackAndWildcard, includeIPv6))
     163                                          includeLoopbackAndWildcard, includeIPv6)) {
    133164                            rv.add(stripScope(addr.getHostAddress()));
     165                        }
    134166                    }
    135167                }
     
    334366    /**
    335367     *  For literal IP addresses, this is the same as getIP(String).
    336      *  For host names, will return the preferred type (IPv4/v6) if available,
    337      *  else the other type if available.
     368     *  For host names, may return multiple addresses, both IPv4 and IPv6,
     369     *  even if those addresses are not reachable due to configuration or available interfaces.
    338370     *  Will resolve but not cache DNS host names.
    339371     *
     
    371403    }
    372404
     405    //////// IPv6 Cache Utils ///////
     406
     407    /**
     408     *  @since 0.9.28
     409     */
     410    private static class Inet6Addr {
     411        private final Inet6Address addr;
     412        private final boolean isDyn, isDep, isTemp;
     413
     414        public Inet6Addr(Inet6Address a, int flags) {
     415            addr = a;
     416            isDyn = (flags & FLAG_PERMANENT) == 0;
     417            isDep = (flags & FLAG_DEPRECATED) != 0;
     418            isTemp = (flags & FLAG_TEMPORARY) != 0;
     419        }
     420
     421        public Inet6Address getAddress() { return addr; }
     422        public boolean isDynamic() { return isDyn; }
     423        public boolean isDeprecated() { return isDep; }
     424        public boolean isTemporary() { return isTemp; }
     425    }
     426
     427    /**
     428     *  Only call if INET6_CACHE_ENABLED.
     429     *  Caller must sync on _ifCache.
     430     *  @since 0.9.28
     431     */
     432    private static void refreshCache() {
     433        long now = System.currentTimeMillis();
     434        if (now - _ifCacheTime < INET6_CACHE_EXPIRE)
     435            return;
     436        _ifCache.clear();
     437        BufferedReader in = null;
     438        try {
     439            in = new BufferedReader(new InputStreamReader(new FileInputStream(IF_INET6_FILE), "ISO-8859-1"), 4096);
     440            String line = null;
     441            while ( (line = in.readLine()) != null) {
     442                // http://tldp.org/HOWTO/html_single/Linux+IPv6-HOWTO/#PROC-NET
     443                // 00000000000000000000000000000001 01 80 10 80       lo
     444                String[] parts = DataHelper.split(line, " ", 6);
     445                if (parts.length < 5)
     446                    continue;
     447                String as = parts[0];
     448                if (as.length() != 32)
     449                    continue;
     450                StringBuilder buf = new StringBuilder(40);
     451                int i = 0;
     452                while(true) {
     453                    buf.append(as.substring(i, i+4));
     454                    i += 4;
     455                    if (i >= 32)
     456                        break;
     457                    buf.append(':');
     458                }
     459                Inet6Address addr;
     460                try {
     461                    addr = (Inet6Address) InetAddress.getByName(buf.toString());
     462                } catch (UnknownHostException uhe) {
     463                    continue;
     464                }
     465                int flags = FLAG_PERMANENT;
     466                try {
     467                    flags = Integer.parseInt(parts[4], 16);
     468                } catch (NumberFormatException nfe) {}
     469                Inet6Addr a = new Inet6Addr(addr, flags);
     470                _ifCache.put(addr, a);
     471            }
     472        } catch (IOException ioe) {
     473        } finally {
     474            if (in != null) try { in.close(); } catch (IOException ioe) {}
     475        }
     476        _ifCacheTime = now;
     477    }
     478
     479    /**
     480     *  Is this address dynamic?
     481     *  Returns false if unknown.
     482     *  @since 0.9.28
     483     */
     484    public static boolean isDynamic(Inet6Address addr) {
     485        if (!INET6_CACHE_ENABLED)
     486            return false;
     487        Inet6Addr a;
     488        synchronized(_ifCache) {
     489            refreshCache();
     490            a = _ifCache.get(addr);
     491        }
     492        if (a == null)
     493            return false;
     494        return a.isDynamic();
     495    }
     496
     497    /**
     498     *  Is this address deprecated?
     499     *  Returns false if unknown.
     500     *  @since 0.9.28
     501     */
     502    public static boolean isDeprecated(Inet6Address addr) {
     503        if (!INET6_CACHE_ENABLED)
     504            return false;
     505        Inet6Addr a;
     506        synchronized(_ifCache) {
     507            refreshCache();
     508            a = _ifCache.get(addr);
     509        }
     510        if (a == null)
     511            return false;
     512        return a.isDeprecated();
     513    }
     514
     515    /**
     516     *  Is this address temporary?
     517     *  Returns false if unknown.
     518     *  @since 0.9.28
     519     */
     520    public static boolean isTemporary(Inet6Address addr) {
     521        if (!INET6_CACHE_ENABLED)
     522            return false;
     523        Inet6Addr a;
     524        synchronized(_ifCache) {
     525            refreshCache();
     526            a = _ifCache.get(addr);
     527        }
     528        if (a == null)
     529            return false;
     530        return a.isTemporary();
     531    }
     532
     533    //////// End IPv6 Cache Utils ///////
     534
    373535    /**
    374536     *  @since 0.9.3
     
    378540            _IPAddress.clear();
    379541        }
     542        if (_ifCache != null) {
     543            synchronized(_ifCache) {
     544                _ifCache.clear();
     545                _ifCacheTime = 0;
     546            }
     547        }
    380548    }
    381549
     
    384552     */
    385553    public static void main(String[] args) {
    386         System.err.println("External IPv4 Addresses:");
     554        System.out.println("External IPv4 Addresses:");
    387555        Set<String> a = getAddresses(false, false, false);
    388556        for (String s : a)
    389             System.err.println(s);
    390         System.err.println("\nExternal and Local IPv4 Addresses:");
     557            System.out.println(s);
     558        System.out.println("\nExternal and Local IPv4 Addresses:");
    391559        a = getAddresses(true, false, false);
    392560        for (String s : a)
    393             System.err.println(s);
    394         System.err.println("\nAll External Addresses:");
     561            System.out.println(s);
     562        System.out.println("\nAll External Addresses:");
    395563        a = getAddresses(false, false, true);
    396564        for (String s : a)
    397             System.err.println(s);
    398         System.err.println("\nAll External and Local Addresses:");
     565            System.out.println(s);
     566        System.out.println("\nAll External and Local Addresses:");
    399567        a = getAddresses(true, false, true);
    400568        for (String s : a)
    401             System.err.println(s);
    402         System.err.println("\nAll addresses:");
     569            System.out.println(s);
     570        System.out.println("\nAll addresses:");
    403571        a = getAddresses(true, true, true);
    404572        for (String s : a)
    405             System.err.println(s);
    406         System.err.println("\nIs connected? " + isConnected());
     573            System.out.println(s);
     574        System.out.println("\nIPv6 address flags:");
     575        for (String s : a) {
     576            if (!s.contains(":"))
     577                continue;
     578            StringBuilder buf = new StringBuilder(64);
     579            buf.append(s);
     580            Inet6Address addr;
     581            try {
     582                addr = (Inet6Address) InetAddress.getByName(buf.toString());
     583                if (addr.isSiteLocalAddress())
     584                    buf.append(" host");
     585                else if (addr.isLinkLocalAddress())
     586                    buf.append(" link");
     587                else if (addr.isAnyLocalAddress())
     588                    buf.append(" wildcard");
     589                else if (addr.isLoopbackAddress())
     590                    buf.append(" loopback");
     591                else
     592                    buf.append(" global");
     593                if (isTemporary(addr))
     594                    buf.append(" temporary");
     595                if (isDeprecated(addr))
     596                    buf.append(" deprecated");
     597                if (isDynamic(addr))
     598                    buf.append(" dynamic");
     599            } catch (UnknownHostException uhe) {}
     600            System.out.println(buf.toString());
     601        }
     602        System.out.println("\nIs connected? " + isConnected());
    407603    }
    408604}
Note: See TracChangeset for help on using the changeset viewer.