Changeset 79f8e88


Ignore:
Timestamp:
Jun 28, 2013 4:10:49 PM (7 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
3aafea0
Parents:
bddfe3ed (diff), 34b7081 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

propagate from branch 'i2p.i2p' (head 2a2c708bf9fee43e69469bdf896dfe489c32bdea)

to branch 'i2p.i2p.zzz.ipv6' (head c33552d7026b0a445d1dd7e138bf454144130eb2)

Files:
5 added
1 deleted
61 edited

Legend:

Unmodified
Added
Removed
  • LICENSE.txt

    rbddfe3ed r79f8e88  
    208208
    209209       GeoIP Data:
    210        Copyright (c) 2008 MaxMind, Inc.  All Rights Reserved.
     210       This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/
    211211       See licenses/LICENSE-GeoIP.txt
    212212
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java

    rbddfe3ed r79f8e88  
    88import net.i2p.router.Router;
    99import net.i2p.router.transport.FIFOBandwidthRefiller;
    10 import net.i2p.router.transport.TransportImpl;
     10import net.i2p.router.transport.TransportUtil;
    1111import net.i2p.router.transport.TransportManager;
    1212import net.i2p.router.transport.udp.UDPTransport;
     
    371371            return false;
    372372        }
    373         boolean rv = TransportImpl.isPubliclyRoutable(iab);
     373        // TODO set IPv6 arg based on configuration?
     374        boolean rv = TransportUtil.isPubliclyRoutable(iab, true);
    374375        if (!rv)
    375376            addFormError(_("The hostname or IP {0} is not publicly routable", addr));
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java

    rbddfe3ed r79f8e88  
    88import net.i2p.router.Router;
    99import net.i2p.router.transport.TransportManager;
    10 import net.i2p.router.transport.udp.UDPAddress;
    1110import net.i2p.router.transport.udp.UDPTransport;
    1211import net.i2p.util.Addresses;
     
    3332    }
    3433   
    35     public String getUdpAddress() {
    36         RouterAddress addr = _context.router().getRouterInfo().getTargetAddress("SSU");
    37         if (addr == null)
    38             return _("unknown");
    39         UDPAddress ua = new UDPAddress(addr);
    40         return ua.toString();
    41     }
    42    
     34    /** @return host or "unknown" */
    4335    public String getUdpIP() {
    4436        RouterAddress addr = _context.router().getRouterInfo().getTargetAddress("SSU");
    4537        if (addr == null)
    4638            return _("unknown");
    47         UDPAddress ua = new UDPAddress(addr);
    48         if (ua.getHost() == null)
    49             return _("unknown");
    50         return ua.getHost();
     39        String rv = addr.getHost();
     40        if (rv == null)
     41            return _("unknown");
     42        return rv;
    5143    }
    5244
  • apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java

    rbddfe3ed r79f8e88  
    2525import net.i2p.router.TunnelPoolSettings;
    2626import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
    27 import net.i2p.router.transport.ntcp.NTCPAddress;
     27import net.i2p.router.transport.TransportUtil;
    2828import net.i2p.stat.Rate;
    2929import net.i2p.stat.RateStat;
     
    160160            case CommSystemFacade.STATUS_OK:
    161161                RouterAddress ra = routerInfo.getTargetAddress("NTCP");
    162                 if (ra == null || (new NTCPAddress(ra)).isPubliclyRoutable())
     162                // TODO set IPv6 arg based on configuration?
     163                if (ra == null || TransportUtil.isPubliclyRoutable(ra.getIP(), true))
    163164                    return _("OK");
    164165                return _("ERR-Private TCP Address");
  • build.xml

    rbddfe3ed r79f8e88  
    11221122        <copy file="build/addressbook.war" todir="pkg-temp/webapps/" />
    11231123        <!-- decapitalized the file in 0.7.8 -->
    1124        <copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
     1124        <copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
     1125        <!-- small enough to include for now -->
     1126        <copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
    11251127    </target>
    11261128
     
    11381140    <target name="prepgeoupdate">
    11391141        <copy file="installer/resources/geoip.txt" todir="pkg-temp/geoip/" />
     1142        <copy file="installer/resources/geoipv6.dat.gz" todir="pkg-temp/geoip/" />
    11401143        <copy file="installer/resources/countries.txt" todir="pkg-temp/geoip/" />
    11411144        <copy todir="pkg-temp/docs/icons/flags" >
     
    12931296
    12941297    <!-- unit tests -->
    1295     <target name="updateTest" depends="prepupdate">
     1298    <target name="buildTest">
    12961299        <ant dir="core/java/" target="jarTest" />
    1297         <copy file="core/java/build/i2ptest.jar" todir="pkg-temp/lib" />
    1298         <zip destfile="i2pupdate.zip" basedir="pkg-temp" />
    1299     </target>
     1300        <ant dir="router/java/" target="jarTest" />
     1301        <copy file="core/java/build/i2ptest.jar" todir="build" />
     1302        <copy file="router/java/build/routertest.jar" todir="build" />
     1303    </target>
     1304    <target name="prepTest" depends="prepupdate, buildTest">
     1305        <!-- overwrite i2p.jar and router.jar with the test versions -->
     1306        <copy file="build/i2ptest.jar" tofile="pkg-temp/lib/i2p.jar" overwrite="true" />
     1307        <copy file="build/routertest.jar" tofile="pkg-temp/lib/router.jar" overwrite="true" />
     1308    </target>
     1309    <target name="updateTest" depends="prepTest, zipit" />
    13001310    <target name="junit.test" depends="buildProperties, jbigi" >
    13011311        <ant dir="core/java/" target="junit.test" />
     
    13041314    <target name="scalatest.test" depends="buildProperties, jbigi" >
    13051315        <ant dir="core/java/" target="scalatest.test" />
     1316        <!-- note there are no router scala tests yet -->
    13061317        <ant dir="router/java/" target="scalatest.test" />
    13071318    </target>
    13081319    <target name="test" depends="buildProperties, jbigi" >
     1320        <!-- both junit and scala -->
    13091321        <ant dir="core/java/" target="test" />
    13101322        <ant dir="router/java/" target="test" />
  • core/java/src/net/i2p/data/RouterAddress.java

    rbddfe3ed r79f8e88  
    3939 */
    4040public class RouterAddress extends DataStructureImpl {
    41     private int _cost;
     41    private short _cost;
    4242    //private Date _expiration;
    4343    private String _transportStyle;
     
    5151
    5252    public RouterAddress() {
    53         _cost = -1;
    5453        _options = new OrderedProperties();
     54    }
     55
     56    /**
     57     *  For efficiency when created by a Transport.
     58     *  @param options not copied; do not reuse or modify
     59     *  @param cost 0-255
     60     *  @since IPv6
     61     */
     62    public RouterAddress(String style, OrderedProperties options, int cost) {
     63        _transportStyle = style;
     64        _options = options;
     65        if (cost < 0 || cost > 255)
     66            throw new IllegalArgumentException();
     67        _cost = (short) cost;
    5568    }
    5669
     
    6174     *
    6275     * Unused before 0.7.12
     76     * @return 0-255
    6377     */
    6478    public int getCost() {
     
    6882    /**
    6983     * Configure the weighted cost of using the address.
    70      * No value above 255 is allowed.
     84     * No value negative or above 255 is allowed.
     85     *
     86     * WARNING - do not change cost on a published address or it will break the RI sig.
     87     * There is no check here.
     88     * Rarely used, use 3-arg constructor.
    7189     *
    7290     * NTCP is set to 10 and SSU to 5 by default, unused before 0.7.12
    7391     */
    7492    public void setCost(int cost) {
    75         _cost = cost;
     93        if (cost < 0 || cost > 255)
     94            throw new IllegalArgumentException();
     95        _cost = (short) cost;
    7696    }
    7797
     
    114134     *
    115135     * @throws IllegalStateException if was already set
     136     * @deprecated unused, use 3-arg constructor
    116137     */
    117138    public void setTransportStyle(String transportStyle) {
     
    153174     * @param options non-null
    154175     * @throws IllegalStateException if was already set
     176     * @deprecated unused, use 3-arg constructor
    155177     */
    156178    public void setOptions(Properties options) {
     
    172194            return _ip;
    173195        byte[] rv = null;
    174         String host = _options.getProperty(PROP_HOST);
     196        String host = getHost();
    175197        if (host != null) {
    176198            rv = Addresses.getIP(host);
     
    182204        }
    183205        return rv;
     206    }
     207   
     208    /**
     209     *  Convenience, same as getOption("host").
     210     *  Does no parsing, so faster than getIP().
     211     *
     212     *  @return host string or null
     213     *  @since IPv6
     214     */
     215    public String getHost() {
     216        return _options.getProperty(PROP_HOST);
    184217    }
    185218   
     
    213246        if (_transportStyle != null)
    214247            throw new IllegalStateException();
    215         _cost = (int) DataHelper.readLong(in, 1);
     248        _cost = (short) DataHelper.readLong(in, 1);
    216249        //_expiration = DataHelper.readDate(in);
    217250        DataHelper.readDate(in);
     
    230263     */
    231264    public void writeBytes(OutputStream out) throws DataFormatException, IOException {
    232         if ((_cost < 0) || (_transportStyle == null))
    233             throw new DataFormatException("Not enough data to write a router address");
     265        if (_transportStyle == null)
     266            throw new DataFormatException("uninitialized");
    234267        DataHelper.writeLong(out, 1, _cost);
    235268        //DataHelper.writeDate(out, _expiration);
     
    239272    }
    240273   
     274    /**
     275     * Transport, host, and port only.
     276     * Never look at cost or other properties.
     277     */
    241278    @Override
    242279    public boolean equals(Object object) {
     
    244281        if ((object == null) || !(object instanceof RouterAddress)) return false;
    245282        RouterAddress addr = (RouterAddress) object;
    246         // let's keep this fast as we are putting an address into the RouterInfo set frequently
    247283        return
    248                _cost == addr._cost &&
     284               getPort() == addr.getPort() &&
     285               DataHelper.eq(getHost(), addr.getHost()) &&
    249286               DataHelper.eq(_transportStyle, addr._transportStyle);
    250287               //DataHelper.eq(_options, addr._options) &&
     
    253290   
    254291    /**
     292     *  Everything, including Transport, host, port, options, and cost
     293     *  @param addr may be null
     294     *  @since IPv6
     295     */
     296    public boolean deepEquals(RouterAddress addr) {
     297        return
     298               equals(addr) &&
     299               _cost == addr._cost &&
     300               _options.equals(addr._options);
     301    }
     302   
     303    /**
    255304     * Just use a few items for speed (expiration is always null).
     305     * Never look at cost or other properties.
    256306     */
    257307    @Override
     
    259309        return DataHelper.hashCode(_transportStyle) ^
    260310               DataHelper.hashCode(getIP()) ^
    261                getPort() ^
    262                _cost;
     311               getPort();
    263312    }
    264313   
     
    272321        StringBuilder buf = new StringBuilder(128);
    273322        buf.append("[RouterAddress: ");
    274         buf.append("\n\tTransportStyle: ").append(_transportStyle);
     323        buf.append("\n\tType: ").append(_transportStyle);
    275324        buf.append("\n\tCost: ").append(_cost);
    276325        //buf.append("\n\tExpiration: ").append(_expiration);
    277             buf.append("\n\tOptions: #: ").append(_options.size());
     326            buf.append("\n\tOptions (").append(_options.size()).append("):");
    278327            for (Map.Entry e : _options.entrySet()) {
    279328                String key = (String) e.getKey();
  • core/java/src/net/i2p/data/RouterInfo.java

    rbddfe3ed r79f8e88  
    6262    private volatile boolean _validated;
    6363    private volatile boolean _isValid;
    64     private volatile String _stringified;
     64    //private volatile String _stringified;
    6565    private volatile byte _byteified[];
    6666    private volatile int _hashCode;
     
    614614    @Override
    615615    public String toString() {
    616         if (_stringified != null) return _stringified;
    617         StringBuilder buf = new StringBuilder(5*1024);
     616        //if (_stringified != null) return _stringified;
     617        StringBuilder buf = new StringBuilder(1024);
    618618        buf.append("[RouterInfo: ");
    619619        buf.append("\n\tIdentity: ").append(_identity);
    620620        buf.append("\n\tSignature: ").append(_signature);
    621         buf.append("\n\tPublished on: ").append(new Date(_published));
    622         buf.append("\n\tAddresses: #: ").append(_addresses.size());
    623         for (RouterAddress addr : _addresses) {
    624             buf.append("\n\t\tAddress: ").append(addr);
    625         }
    626         Set<Hash> peers = getPeers();
    627         buf.append("\n\tPeers: #: ").append(peers.size());
    628         for (Hash hash : peers) {
    629             buf.append("\n\t\tPeer hash: ").append(hash);
    630         }
    631         buf.append("\n\tOptions: #: ").append(_options.size());
     621        buf.append("\n\tPublished: ").append(new Date(_published));
     622        if (_peers != null) {
     623            buf.append("\n\tPeers (").append(_peers.size()).append("):");
     624            for (Hash hash : _peers) {
     625                buf.append("\n\t\tPeer hash: ").append(hash);
     626            }
     627        }
     628        buf.append("\n\tOptions (").append(_options.size()).append("):");
    632629        for (Map.Entry e : _options.entrySet()) {
    633630            String key = (String) e.getKey();
     
    635632            buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
    636633        }
     634        if (!_addresses.isEmpty()) {
     635            buf.append("\n\tAddresses (").append(_addresses.size()).append("):");
     636            for (RouterAddress addr : _addresses) {
     637                buf.append("\n\t").append(addr);
     638            }
     639        }
    637640        buf.append("]");
    638         _stringified = buf.toString();
    639         return _stringified;
     641        String rv = buf.toString();
     642        //_stringified = rv;
     643        return rv;
    640644    }
    641645
  • core/java/src/net/i2p/util/Addresses.java

    rbddfe3ed r79f8e88  
    3535    }
    3636
    37     /** @return the first non-local address it finds, or null */
     37    /** @return the first non-local address IPv4 address it finds, or null */
    3838    public static String getAnyAddress() {
    3939        SortedSet<String> a = getAddresses();
     
    9696                    if (shouldInclude(allMyIps[i], includeSiteLocal,
    9797                                      includeLoopbackAndWildcard, includeIPv6))
    98                         rv.add(allMyIps[i].getHostAddress());
     98                        rv.add(stripScope(allMyIps[i].getHostAddress()));
    9999                }
    100100            }
     
    114114                        if (shouldInclude(addr, includeSiteLocal,
    115115                                          includeLoopbackAndWildcard, includeIPv6))
    116                             rv.add(addr.getHostAddress());
     116                            rv.add(stripScope(addr.getHostAddress()));
    117117                    }
    118118                }
     
    127127        }
    128128        return rv;
     129    }
     130
     131    /**
     132     *  Strip the trailing "%nn" from Inet6Address.getHostAddress()
     133     *  @since IPv6
     134     */
     135    private static String stripScope(String ip) {
     136        int pct = ip.indexOf("%");
     137        if (pct > 0)
     138            ip = ip.substring(0, pct);
     139        return ip;
    129140    }
    130141
  • installer/resources/blocklist.txt

    rbddfe3ed r79f8e88  
    4747<a href="http://www.team-cymru.org/Services/Bogons/http.html">The Team Cymru Bogon List v6.8 03 FEB 2011</a>:192.0.0.0/24
    4848<a href="http://www.team-cymru.org/Services/Bogons/http.html">The Team Cymru Bogon List v6.8 03 FEB 2011</a>:192.0.2.0/24
     49<a href="http://tools.ietf.org/html/rfc3068">6to4 Anycast</a>:192.88.99.0/24
    4950<a href="http://www.team-cymru.org/Services/Bogons/http.html">The Team Cymru Bogon List v6.8 03 FEB 2011</a>:192.168.0.0/16
    5051<a href="http://www.team-cymru.org/Services/Bogons/http.html">The Team Cymru Bogon List v6.8 03 FEB 2011</a>:198.18.0.0/15
  • licenses/LICENSE-GeoIP.txt

    rbddfe3ed r79f8e88  
    1 OPEN DATA LICENSE (GeoLite Country and GeoLite City databases)
     1The GeoLite databases are distributed under the
     2Creative Commons Attribution-ShareAlike 3.0 Unported License
     3http://creativecommons.org/licenses/by-sa/3.0/ .
     4The attribution requirement may be met by including the following in
     5all advertising and documentation mentioning features of or use of this database:
    26
    3 Copyright (c) 2008 MaxMind, Inc.  All Rights Reserved.
    4 
    5 All advertising materials and documentation mentioning features or use of
    6 this database must display the following acknowledgment:
    77"This product includes GeoLite data created by MaxMind, available from
    8 http://maxmind.com/"
    9 
    10 Redistribution and use with or without modification, are permitted provided
    11 that the following conditions are met:
    12 1. Redistributions must retain the above copyright notice, this list of
    13 conditions and the following disclaimer in the documentation and/or other
    14 materials provided with the distribution.
    15 2. All advertising materials and documentation mentioning features or use of
    16 this database must display the following acknowledgement:
    17 "This product includes GeoLite data created by MaxMind, available from
    18 http://maxmind.com/"
    19 3. "MaxMind" may not be used to endorse or promote products derived from this
    20 database without specific prior written permission.
    21 
    22 THIS DATABASE IS PROVIDED BY MAXMIND, INC ``AS IS'' AND ANY
    23 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    25 DISCLAIMED. IN NO EVENT SHALL MAXMIND BE LIABLE FOR ANY
    26 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    29 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    31 DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    32 
     8http://www.maxmind.com/"
  • router/java/build.xml

    rbddfe3ed r79f8e88  
    259259        </replaceregexp>
    260260    </target>
     261
     262    <!-- both junit and scala, but we have no scala tests yet -->
    261263    <target name="test" depends="junit.test"/>
     264
    262265    <!-- test reports -->
    263266    <target name="scalatest.report">
  • router/java/src/net/i2p/router/Blocklist.java

    rbddfe3ed r79f8e88  
    1212import java.io.InputStreamReader;
    1313import java.io.Writer;
     14import java.math.BigInteger;
    1415import java.net.InetAddress;
    1516import java.net.UnknownHostException;
    1617import java.util.ArrayList;
    1718import java.util.Arrays;
     19import java.util.Collections;
    1820import java.util.HashMap;
    1921import java.util.HashSet;
     
    3234import net.i2p.util.Addresses;
    3335import net.i2p.util.ConcurrentHashSet;
     36import net.i2p.util.LHMCache;
    3437import net.i2p.util.Log;
    3538import net.i2p.util.Translate;
     
    6366 * entry so we can add the reason to the banlist text.
    6467 *
     68 * On-disk blocklist supports IPv4 only.
     69 * In-memory supports both IPv4 and IPv6.
    6570 */
    6671public class Blocklist {
     
    7378    private final Set<Hash> _inProcess = new HashSet(4);
    7479    private Map<Hash, String> _peerBlocklist = new HashMap(4);
     80
     81    /**
     82     *  Limits of transient (in-memory) blocklists.
     83     *  Note that it's impossible to prevent clogging up
     84     *  the tables by a determined attacker, esp. on IPv6
     85     */
     86    private static final int MAX_IPV4_SINGLES = 256;
     87    private static final int MAX_IPV6_SINGLES = 512;
     88
    7589    private final Set<Integer> _singleIPBlocklist = new ConcurrentHashSet(4);
    76    
     90    private final Map<BigInteger, Object> _singleIPv6Blocklist = new LHMCache(MAX_IPV6_SINGLES);
     91
     92    private static final Object DUMMY = Integer.valueOf(0);   
     93
    7794    public Blocklist(RouterContext context) {
    7895        _context = context;
     
    438455     * This is used for new additions, NOT for the main list
    439456     * of IP ranges read in from the file.
     457     *
     458     * @param ip IPv4 or IPv6
    440459     */
    441460    public void add(String ip) {
     
    449468     * This is used for new additions, NOT for the main list
    450469     * of IP ranges read in from the file.
     470     *
     471     * @param ip IPv4 or IPv6
    451472     */
    452473    public void add(byte ip[]) {
    453         if (ip.length != 4)
    454             return;
    455         if (add(toInt(ip)))
    456             if (_log.shouldLog(Log.WARN))
    457                 _log.warn("Adding IP to blocklist: " + Addresses.toString(ip));
     474        boolean rv;
     475        if (ip.length == 4)
     476            rv = add(toInt(ip));
     477        else if (ip.length == 16)
     478            rv = add(new BigInteger(1, ip));
     479        else
     480            rv = false;
     481        if (rv && _log.shouldLog(Log.WARN))
     482            _log.warn("Adding IP to blocklist: " + Addresses.toString(ip));
    458483    }
    459484
    460485    private boolean add(int ip) {
     486        if (_singleIPBlocklist.size() >= MAX_IPV4_SINGLES)
     487            return false;
    461488        return _singleIPBlocklist.add(Integer.valueOf(ip));
    462489    }
     
    467494
    468495    /**
    469      * this tries to not return duplicates
    470      * but I suppose it could.
     496     * @param ip IPv6 non-negative
     497     * @since IPv6
     498     */
     499    private boolean add(BigInteger ip) {
     500        synchronized(_singleIPv6Blocklist) {
     501            return _singleIPv6Blocklist.put(ip, DUMMY) == null;
     502        }
     503    }
     504
     505    /**
     506     * @param ip IPv6 non-negative
     507     * @since IPv6
     508     */
     509    private boolean isOnSingleList(BigInteger ip) {
     510        synchronized(_singleIPv6Blocklist) {
     511            return _singleIPv6Blocklist.get(ip) != null;
     512        }
     513    }
     514
     515    /**
     516     * Will not contain duplicates.
    471517     */
    472518    private List<byte[]> getAddresses(Hash peer) {
    473         List<byte[]> rv = new ArrayList(1);
    474519        RouterInfo pinfo = _context.netDb().lookupRouterInfoLocally(peer);
    475         if (pinfo == null) return rv;
    476         byte[] oldpib = null;
     520        if (pinfo == null)
     521            return Collections.EMPTY_LIST;
     522        List<byte[]> rv = new ArrayList(4);
    477523        // for each peer address
    478524        for (RouterAddress pa : pinfo.getAddresses()) {
    479525            byte[] pib = pa.getIP();
    480526            if (pib == null) continue;
    481             if (DataHelper.eq(oldpib, pib)) continue;
    482             oldpib = pib;
     527            // O(n**2)
     528            for (int i = 0; i < rv.size(); i++) {
     529                if (DataHelper.eq(rv.get(i), pib)) continue;
     530            }
    483531            rv.add(pib);
    484532         }
     
    492540    public boolean isBlocklisted(Hash peer) {
    493541        List<byte[]> ips = getAddresses(peer);
    494         for (Iterator<byte[]> iter = ips.iterator(); iter.hasNext(); ) {
    495             byte ip[] = iter.next();
     542        if (ips.isEmpty())
     543            return false;
     544        for (byte[] ip : ips) {
    496545            if (isBlocklisted(ip)) {
    497546                if (! _context.banlist().isBanlisted(peer))
     
    506555    /**
    507556     * calling this externally won't banlist the peer, this is just an IP check
     557     *
     558     * @param ip IPv4 or IPv6
    508559     */
    509560    public boolean isBlocklisted(String ip) {
     
    515566    /**
    516567     * calling this externally won't banlist the peer, this is just an IP check
     568     *
     569     * @param ip IPv4 or IPv6
    517570     */
    518571    public boolean isBlocklisted(byte ip[]) {
    519         if (ip.length != 4)
    520             return false;
    521         return isBlocklisted(toInt(ip));
     572        if (ip.length == 4)
     573            return isBlocklisted(toInt(ip));
     574        if (ip.length == 16)
     575            return isOnSingleList(new BigInteger(1, ip));
     576        return false;
    522577    }
    523578
     
    761816        Set<Integer> singles = new TreeSet();
    762817        singles.addAll(_singleIPBlocklist);
    763         if (!singles.isEmpty()) {
     818        if (!(singles.isEmpty() && _singleIPv6Blocklist.isEmpty())) {
    764819            out.write("<table><tr><th align=\"center\" colspan=\"2\"><b>");
    765820            out.write(_("IPs Banned Until Restart"));
     
    782837                 out.write(toStr(ip));
    783838                 out.write("</td><td width=\"50%\">&nbsp;</td></tr>\n");
     839            }
     840            // then IPv6
     841            if (!_singleIPv6Blocklist.isEmpty()) {
     842                List<BigInteger> s6;
     843                synchronized(_singleIPv6Blocklist) {
     844                    s6 = new ArrayList(_singleIPv6Blocklist.keySet());
     845                }
     846                Collections.sort(s6);
     847                for (BigInteger bi : s6) {
     848                     out.write("<tr><td align=\"center\" width=\"50%\">");
     849                     out.write(Addresses.toString(toIPBytes(bi)));
     850                     out.write("</td><td width=\"50%\">&nbsp;</td></tr>\n");
     851                }
    784852            }
    785853            out.write("</table>");
     
    834902
    835903    /**
     904     *  Convert a (non-negative) two's complement IP to exactly 16 bytes
     905     *  @since IPv6
     906     */
     907    private static byte[] toIPBytes(BigInteger bi) {
     908        byte[] ba = bi.toByteArray();
     909        int len = ba.length;
     910        if (len == 16)
     911            return ba;
     912        byte[] rv = new byte[16];
     913        if (len < 16)
     914            System.arraycopy(ba, 0, rv, 16 - len, len);
     915        else
     916            System.arraycopy(ba, len - 16, rv, 0, 16);
     917        return rv;
     918    }
     919
     920    /**
    836921     *  Mark a string for extraction by xgettext and translation.
    837922     *  Use this only in static initializers.
  • router/java/src/net/i2p/router/CommSystemFacade.java

    rbddfe3ed r79f8e88  
    2929    public void renderStatusHTML(Writer out) throws IOException { renderStatusHTML(out, null, 0); }
    3030   
    31     /** Create the set of RouterAddress structures based on the router's config */
    32     public Set<RouterAddress> createAddresses() { return Collections.EMPTY_SET; }
     31    /** Create the list of RouterAddress structures based on the router's config */
     32    public List<RouterAddress> createAddresses() { return Collections.EMPTY_LIST; }
    3333   
    3434    public int countActivePeers() { return 0; }
  • router/java/src/net/i2p/router/MessageHistory.java

    rbddfe3ed r79f8e88  
    9292    public synchronized void initialize(boolean forceReinitialize) {
    9393        if (!forceReinitialize) return;
    94 
    95         if (_context.router().getRouterInfo() == null) {
     94        Router router = _context.router();
     95        if (router == null) {
     96            // unit testing, presumably
     97            return;
     98        }
     99
     100        if (router.getRouterInfo() == null) {
    96101            _reinitializeJob.getTiming().setStartAfter(_context.clock().now() + 15*1000);
    97102            _context.jobQueue().addJob(_reinitializeJob);
  • router/java/src/net/i2p/router/NetworkDatabaseFacade.java

    rbddfe3ed r79f8e88  
    7878    /** @since 0.9 */
    7979    public ReseedChecker reseedChecker() { return null; };
     80
     81    /**
     82     *  For convenience, so users don't have to cast to FNDF, and unit tests using
     83     *  Dummy NDF will work.
     84     *
     85     *  @return false; FNDF overrides to return actual setting
     86     *  @since IPv6
     87     */
     88    public boolean floodfillEnabled() { return false; };
    8089}
  • router/java/src/net/i2p/router/Router.java

    rbddfe3ed r79f8e88  
    602602       
    603603        // if prop set to true, don't tell people we are ff even if we are
    604         if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context) &&
     604        if (_context.netDb().floodfillEnabled() &&
    605605            !_context.getBooleanProperty("router.hideFloodfillParticipant"))
    606606            ri.addCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL);
  • router/java/src/net/i2p/router/RouterContext.java

    rbddfe3ed r79f8e88  
    3939public class RouterContext extends I2PAppContext {
    4040    private final Router _router;
    41     private ClientManagerFacadeImpl _clientManagerFacade;
     41    private ClientManagerFacade _clientManagerFacade;
     42    private InternalClientManager _internalClientManager;
    4243    private ClientMessagePool _clientMessagePool;
    4344    private JobQueue _jobQueue;
     
    153154
    154155
     156    /**
     157     *  The following properties may be used to replace various parts
     158     *  of the context with dummy implementations for testing, by setting
     159     *  the property to "true":
     160     *<pre>
     161     *  i2p.dummyClientFacade
     162     *  i2p.dummyNetDb
     163     *  i2p.dummyPeerManager
     164     *  i2p.dummyTunnelManager
     165     *  i2p.vmCommSystem (transport)
     166     *</pre>
     167     */
    155168    public synchronized void initAll() {
    156169        if (_initialized)
    157170            throw new IllegalStateException();
    158         if (getBooleanProperty("i2p.dummyClientFacade"))
    159             System.err.println("i2p.dummyClientFacade currently unsupported");
    160         _clientManagerFacade = new ClientManagerFacadeImpl(this);
    161         // removed since it doesn't implement InternalClientManager for now
    162         //else
    163         //    _clientManagerFacade = new DummyClientManagerFacade(this);
     171        if (!getBooleanProperty("i2p.dummyClientFacade")) {
     172            ClientManagerFacadeImpl cmfi = new ClientManagerFacadeImpl(this);
     173            _clientManagerFacade = cmfi;
     174            _internalClientManager = cmfi;
     175        } else {
     176            _clientManagerFacade = new DummyClientManagerFacade(this);
     177            // internal client manager is null
     178        }
    164179        _clientMessagePool = new ClientMessagePool(this);
    165180        _jobQueue = new JobQueue(this);
     
    169184        _messageRegistry = new OutboundMessageRegistry(this);
    170185        //_messageStateMonitor = new MessageStateMonitor(this);
    171         if ("false".equals(getProperty("i2p.dummyNetDb", "false")))
     186        if (!getBooleanProperty("i2p.dummyNetDb"))
    172187            _netDb = new FloodfillNetworkDatabaseFacade(this); // new KademliaNetworkDatabaseFacade(this);
    173188        else
    174189            _netDb = new DummyNetworkDatabaseFacade(this);
    175190        _keyManager = new KeyManager(this);
    176         if ("false".equals(getProperty("i2p.vmCommSystem", "false")))
     191        if (!getBooleanProperty("i2p.vmCommSystem"))
    177192            _commSystem = new CommSystemFacadeImpl(this);
    178193        else
    179194            _commSystem = new VMCommSystem(this);
    180195        _profileOrganizer = new ProfileOrganizer(this);
    181         if ("false".equals(getProperty("i2p.dummyPeerManager", "false")))
     196        if (!getBooleanProperty("i2p.dummyPeerManager"))
    182197            _peerManagerFacade = new PeerManagerFacadeImpl(this);
    183198        else
     
    185200        _profileManager = new ProfileManagerImpl(this);
    186201        _bandwidthLimiter = new FIFOBandwidthLimiter(this);
    187         if ("false".equals(getProperty("i2p.dummyTunnelManager", "false")))
     202        if (!getBooleanProperty("i2p.dummyTunnelManager"))
    188203            _tunnelManager = new TunnelPoolManager(this);
    189204        else
     
    530545    @Override
    531546    public InternalClientManager internalClientManager() {
    532         return _clientManagerFacade;
     547        return _internalClientManager;
    533548    }
    534549
  • router/java/src/net/i2p/router/RouterVersion.java

    rbddfe3ed r79f8e88  
    2222
    2323    /** for example "-test" */
    24     public final static String EXTRA = "";
     24    public final static String EXTRA = "-ipv6";
    2525    public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
    2626    public static void main(String args[]) {
  • router/java/src/net/i2p/router/networkdb/kademlia/ExploreKeySelectorJob.java

    rbddfe3ed r79f8e88  
    3939    public String getName() { return "Explore Key Selector Job"; }
    4040    public void runJob() {
    41         if (((FloodfillNetworkDatabaseFacade)_facade).floodfillEnabled()) {
     41        if (_facade.floodfillEnabled()) {
    4242            requeue(30*RERUN_DELAY_MS);
    4343            return;
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillNetworkDatabaseFacade.java

    rbddfe3ed r79f8e88  
    262262    }
    263263
     264    @Override
    264265    public boolean floodfillEnabled() { return _floodfillEnabled; }
    265     public static boolean floodfillEnabled(RouterContext ctx) {
    266         return ((FloodfillNetworkDatabaseFacade)ctx.netDb()).floodfillEnabled();
    267     }
    268266   
    269267    /**
  • router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java

    rbddfe3ed r79f8e88  
    304304      */
    305305    private Set<Integer> maskedIPSet(Hash peer, RouterInfo pinfo, int mask) {
    306         Set<Integer> rv = new HashSet(2);
     306        Set<Integer> rv = new HashSet(4);
    307307        byte[] commIP = _context.commSystem().getIP(peer);
    308308        if (commIP != null)
     
    323323    /**
    324324     * generate an arbitrary unique value for this ip/mask (mask = 1-4)
     325     * If IPv6, force mask = 8.
    325326     * @since 0.9.5 copied from ProfileOrganizer
    326327     */
    327328    private static Integer maskedIP(byte[] ip, int mask) {
    328         int rv = 0;
    329         for (int i = 0; i < mask; i++)
    330              rv = (rv << 8) | (ip[i] & 0xff);
     329        int rv = ip[0];
     330        if (ip.length == 16) {
     331            for (int i = 1; i < 8; i++) {
     332                rv <<= i * 4;
     333                rv ^= ip[i];
     334            }
     335        } else {
     336            for (int i = 1; i < mask; i++) {
     337                rv <<= 8;
     338                rv ^= ip[i];
     339            }
     340        }
    331341        return Integer.valueOf(rv);
    332342    }
  • router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseLookupMessageJob.java

    rbddfe3ed r79f8e88  
    3939    @Override
    4040    protected boolean answerAllQueries() {
    41         if (!FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) return false;
     41        if (!getContext().netDb().floodfillEnabled()) return false;
    4242        return FloodfillNetworkDatabaseFacade.isFloodfill(getContext().router().getRouterInfo());
    4343    }
     
    5353
    5454        // go away, you got the wrong guy, send our RI back unsolicited
    55         if (!FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext())) {
     55        if (!getContext().netDb().floodfillEnabled()) {
    5656            // We could just call sendData(myhash, myri, toPeer, replyTunnel) but
    5757            // that would increment the netDb.lookupsHandled and netDb.lookupsMatched stats
  • router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java

    rbddfe3ed r79f8e88  
    188188        // flood it
    189189        if (invalidMessage == null &&
    190             FloodfillNetworkDatabaseFacade.floodfillEnabled(getContext()) &&
     190            getContext().netDb().floodfillEnabled() &&
    191191            _message.getReplyToken() > 0) {
    192192            if (wasNew) {
  • router/java/src/net/i2p/router/networkdb/kademlia/KademliaNetworkDatabaseFacade.java

    rbddfe3ed r79f8e88  
    764764        // flushing some from memory, while keeping all on disk.
    765765        long adjustedExpiration;
    766         if (FloodfillNetworkDatabaseFacade.floodfillEnabled(_context))
     766        if (floodfillEnabled())
    767767            adjustedExpiration = ROUTER_INFO_EXPIRATION_FLOODFILL;
    768768        else
  • router/java/src/net/i2p/router/networkdb/kademlia/SearchJob.java

    rbddfe3ed r79f8e88  
    135135        // have been commented out.
    136136        // Returning false essentially enables kademlia as a backup to floodfill for search responses.
    137         if (FloodfillNetworkDatabaseFacade.floodfillEnabled(ctx))
     137        if (ctx.netDb().floodfillEnabled())
    138138            return false;
    139139        return ctx.getProperty("netDb.floodfillOnly", DEFAULT_FLOODFILL_ONLY);
  • router/java/src/net/i2p/router/networkdb/kademlia/StartExplorersJob.java

    rbddfe3ed r79f8e88  
    5252    public String getName() { return "Start Explorers Job"; }
    5353    public void runJob() {
    54         if (! (((FloodfillNetworkDatabaseFacade)_facade).floodfillEnabled() ||
     54        if (! (_facade.floodfillEnabled() ||
    5555               getContext().router().gracefulShutdownInProgress())) {
    5656            int num = MAX_PER_RUN;
     
    9494    private long getNextRunDelay() {
    9595        // we don't explore if floodfill
    96         if (((FloodfillNetworkDatabaseFacade)_facade).floodfillEnabled())
     96        if (_facade.floodfillEnabled())
    9797            return MAX_RERUN_DELAY_MS;
    9898
  • router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java

    rbddfe3ed r79f8e88  
    12651265      */
    12661266    private Set<Integer> maskedIPSet(Hash peer, int mask) {
    1267         Set<Integer> rv = new HashSet(2);
     1267        Set<Integer> rv = new HashSet(4);
    12681268        byte[] commIP = _context.commSystem().getIP(peer);
    12691269        if (commIP != null)
     
    12831283    }
    12841284
    1285     /** generate an arbitrary unique value for this ip/mask (mask = 1-4) */
     1285    /**
     1286     * generate an arbitrary unique value for this ip/mask (mask = 1-4)
     1287     * If IPv6, force mask = 8.
     1288     */
    12861289    private static Integer maskedIP(byte[] ip, int mask) {
    1287         int rv = 0;
    1288         for (int i = 0; i < mask; i++)
    1289              rv = (rv << 8) | (ip[i] & 0xff);
     1290        int rv = ip[0];
     1291        if (ip.length == 16) {
     1292            for (int i = 1; i < 8; i++) {
     1293                rv <<= i * 4;
     1294                rv ^= ip[i];
     1295            }
     1296        } else {
     1297            for (int i = 1; i < mask; i++) {
     1298                rv <<= 8;
     1299                rv ^= ip[i];
     1300            }
     1301        }
    12901302        return Integer.valueOf(rv);
    12911303    }
  • router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java

    rbddfe3ed r79f8e88  
    1111import java.io.IOException;
    1212import java.io.Writer;
     13import java.util.ArrayList;
    1314import java.util.Collections;
    1415import java.util.HashMap;
    15 import java.util.HashSet;
    1616import java.util.Iterator;
    1717import java.util.List;
     
    1919import java.util.Map;
    2020import java.util.Properties;
    21 import java.util.Set;
    2221import java.util.Vector;
    2322
     
    2827import net.i2p.router.OutNetMessage;
    2928import net.i2p.router.RouterContext;
    30 import net.i2p.router.transport.ntcp.NTCPAddress;
    31 import net.i2p.router.transport.ntcp.NTCPTransport;
    32 import net.i2p.router.transport.udp.UDPAddress;
    3329import net.i2p.router.transport.udp.UDPTransport;
    3430import net.i2p.util.Addresses;
     
    4642    private volatile boolean _netMonitorStatus;
    4743    private boolean _wasStarted;
     44
     45    /**
     46     *  Disable connections for testing
     47     *  @since IPv6
     48     */
     49    private static final String PROP_DISABLED = "i2np.disable";
    4850   
    4951    public CommSystemFacadeImpl(RouterContext context) {
     
    126128    }
    127129   
    128     public List<TransportBid> getBids(OutNetMessage msg) {
    129         return _manager.getBids(msg);
    130     }
    131     public TransportBid getBid(OutNetMessage msg) {
    132         return _manager.getBid(msg);
    133     }
    134     public TransportBid getNextBid(OutNetMessage msg) {
    135         return _manager.getNextBid(msg);
    136     }
    137     int getTransportCount() { return _manager.getTransportCount(); }
    138    
    139130    /** Send the message out */
    140131    public void processMessage(OutNetMessage msg) {     
     132        if (isDummy()) {
     133            // testing
     134            GetBidsJob.fail(_context, msg);
     135            return;
     136        }
    141137        //GetBidsJob j = new GetBidsJob(_context, this, msg);
    142138        //j.runJob();
    143139        //long before = _context.clock().now();
    144         GetBidsJob.getBids(_context, this, msg);
     140        GetBidsJob.getBids(_context, _manager, msg);
    145141        // < 0.4 ms
    146142        //_context.statManager().addRateData("transport.getBidsJobTime", _context.clock().now() - before);
     
    168164   
    169165    @Override
    170     public List getMostRecentErrorMessages() {
     166    public List<String> getMostRecentErrorMessages() {
    171167        return _manager.getMostRecentErrorMessages();
    172168    }
     
    191187    /** @return non-null, possibly empty */
    192188    @Override
    193     public Set<RouterAddress> createAddresses() {
     189    public List<RouterAddress> createAddresses() {
    194190        // No, don't do this, it makes it almost impossible to build inbound tunnels
    195191        //if (_context.router().isHidden())
    196192        //    return Collections.EMPTY_SET;
    197         Map<String, RouterAddress> addresses = _manager.getAddresses();
    198         boolean newCreated = false;
    199        
    200         if (!addresses.containsKey(NTCPTransport.STYLE)) {
    201             RouterAddress addr = createNTCPAddress(_context);
    202             if (_log.shouldLog(Log.INFO))
    203                 _log.info("NTCP address: " + addr);
    204             if (addr != null) {
    205                 addresses.put(NTCPTransport.STYLE, addr);
    206                 newCreated = true;
    207             }
    208         }
    209        
     193        List<RouterAddress> addresses = new ArrayList(_manager.getAddresses());
    210194        if (_log.shouldLog(Log.INFO))
    211             _log.info("Creating addresses: " + addresses + " isNew? " + newCreated, new Exception("creator"));
    212         return new HashSet(addresses.values());
    213     }
    214    
    215     public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname";
    216     public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port";
    217     public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoport";
    218     public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoip";
    219    
    220     /**
    221      * This only creates an address if the hostname AND port are set in router.config,
    222      * which should be rare.
    223      * Otherwise, notifyReplaceAddress() below takes care of it.
    224      * Note this is called both from above and from NTCPTransport.startListening()
     195            _log.info("Creating addresses: " + addresses, new Exception("creator"));
     196        return addresses;
     197    }
     198   
     199    /**
     200     * UDP changed addresses, tell NTCP and restart
    225201     *
    226      * This should really be moved to ntcp/NTCPTransport.java, why is it here?
    227      */
    228     public static RouterAddress createNTCPAddress(RouterContext ctx) {
    229         if (!TransportManager.isNTCPEnabled(ctx)) return null;
    230         String name = ctx.router().getConfigSetting(PROP_I2NP_NTCP_HOSTNAME);
    231         String port = ctx.router().getConfigSetting(PROP_I2NP_NTCP_PORT);
    232         /*
    233         boolean isNew = false;
    234         if (name == null) {
    235             name = "localhost";
    236             isNew = true;
    237         }
    238         if (port == null) {
    239             port = String.valueOf(ctx.random().nextInt(10240)+1024);
    240             isNew = true;
    241         }
    242          */
    243         if ( (name == null) || (port == null) || (name.trim().length() <= 0) || ("null".equals(name)) )
    244             return null;
    245         try {
    246             int p = Integer.parseInt(port);
    247             if ( (p <= 0) || (p > 64*1024) )
    248                 return null;
    249         } catch (NumberFormatException nfe) {
    250             return null;
    251         }
    252         Properties props = new Properties();
    253         props.setProperty(NTCPAddress.PROP_HOST, name);
    254         props.setProperty(NTCPAddress.PROP_PORT, port);
    255         RouterAddress addr = new RouterAddress();
    256         addr.setCost(NTCPAddress.DEFAULT_COST);
    257         //addr.setExpiration(null);
    258         addr.setOptions(props);
    259         addr.setTransportStyle(NTCPTransport.STYLE);
    260         //if (isNew) {
    261             // why save the same thing?
    262             Map<String, String> changes = new HashMap();
    263             changes.put(PROP_I2NP_NTCP_HOSTNAME, name);
    264             changes.put(PROP_I2NP_NTCP_PORT, port);
    265             ctx.router().saveConfig(changes, null);
    266         //}
    267         return addr;
    268     }
    269 
    270     /**
    271      * UDP changed addresses, tell NTCP and restart
    272      * This should really be moved to ntcp/NTCPTransport.java, why is it here?
    273      */
    274     @Override
    275     public synchronized void notifyReplaceAddress(RouterAddress udpAddr) {
    276         if (udpAddr == null)
    277             return;
    278         NTCPTransport t = (NTCPTransport) _manager.getTransport(NTCPTransport.STYLE);
    279         if (t == null)
    280             return;
    281         RouterAddress oldAddr = t.getCurrentAddress();
    282         if (_log.shouldLog(Log.INFO))
    283             _log.info("Changing NTCP Address? was " + oldAddr);
    284         RouterAddress newAddr = new RouterAddress();
    285         newAddr.setTransportStyle(NTCPTransport.STYLE);
    286         Properties newProps = new Properties();
    287         if (oldAddr == null) {
    288             newAddr.setCost(NTCPAddress.DEFAULT_COST);
    289         } else {
    290             newAddr.setCost(oldAddr.getCost());
    291             newProps.putAll(oldAddr.getOptionsMap());
    292         }
    293 
    294         boolean changed = false;
    295 
    296         // Auto Port Setting
    297         // old behavior (<= 0.7.3): auto-port defaults to false, and true trumps explicit setting
    298         // new behavior (>= 0.7.4): auto-port defaults to true, but explicit setting trumps auto
    299         // TODO rewrite this to operate on ints instead of strings
    300         String oport = newProps.getProperty(NTCPAddress.PROP_PORT);
    301         String nport = null;
    302         String cport = _context.getProperty(PROP_I2NP_NTCP_PORT);
    303         if (cport != null && cport.length() > 0) {
    304             nport = cport;
    305         } else if (_context.getBooleanPropertyDefaultTrue(PROP_I2NP_NTCP_AUTO_PORT)) {
    306             // 0.9.6 change
    307             // This wasn't quite right, as udpAddr is the EXTERNAL port and we really
    308             // want NTCP to bind to the INTERNAL port the first time,
    309             // because if they are different, the NAT is changing them, and
    310             // it probably isn't mapping UDP and TCP the same.
     202     * All the work moved to NTCPTransport.externalAddressReceived()
     203     *
     204     * @param udpAddr may be null; or udpAddr's host/IP may be null
     205     */
     206    @Override
     207    public void notifyReplaceAddress(RouterAddress udpAddr) {
     208        byte[] ip = udpAddr != null ? udpAddr.getIP() : null;
     209        int port = udpAddr != null ? udpAddr.getPort() : 0;
     210        if (port < 0) {
    311211            Transport udp = _manager.getTransport(UDPTransport.STYLE);
    312             if (udp != null) {
    313                 int udpIntPort = udp.getRequestedPort();
    314                 if (udpIntPort > 0)
    315                     // should always be true
    316                     nport = Integer.toString(udpIntPort);
    317             }
    318             if (nport == null)
    319                 // fallback
    320                 nport = udpAddr.getOption(UDPAddress.PROP_PORT);
    321         }
    322         if (_log.shouldLog(Log.INFO))
    323             _log.info("old: " + oport + " config: " + cport + " new: " + nport);
    324         if (nport == null || nport.length() <= 0)
    325             return;
    326         // 0.9.6 change
    327         // Don't have NTCP "chase" SSU's external port,
    328         // as it may change, possibly frequently.
    329         //if (oport == null || ! oport.equals(nport)) {
    330         if (oport == null) {
    331             newProps.setProperty(NTCPAddress.PROP_PORT, nport);
    332             changed = true;
    333         }
    334 
    335         // Auto IP Setting
    336         // old behavior (<= 0.7.3): auto-ip defaults to false, and trumps configured hostname,
    337         //                          and ignores reachability status - leading to
    338         //                          "firewalled with inbound TCP enabled" warnings.
    339         // new behavior (>= 0.7.4): auto-ip defaults to true, and explicit setting trumps auto,
    340         //                          and only takes effect if reachability is OK.
    341         //                          And new "always" setting ignores reachability status, like
    342         //                          "true" was in 0.7.3
    343         String ohost = newProps.getProperty(NTCPAddress.PROP_HOST);
    344         String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "true").toLowerCase(Locale.US);
    345         String name = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
    346         // hostname config trumps auto config
    347         if (name != null && name.length() > 0)
    348             enabled = "false";
    349         Transport udp = _manager.getTransport(UDPTransport.STYLE);
    350         short status = STATUS_UNKNOWN;
    351         if (udp != null)
    352             status = udp.getReachabilityStatus();
    353         if (_log.shouldLog(Log.INFO))
    354             _log.info("old: " + ohost + " config: " + name + " auto: " + enabled + " status: " + status);
    355         if (enabled.equals("always") ||
    356             (Boolean.parseBoolean(enabled) && status == STATUS_OK)) {
    357             String nhost = udpAddr.getOption(UDPAddress.PROP_HOST);
    358             if (_log.shouldLog(Log.INFO))
    359                 _log.info("old: " + ohost + " config: " + name + " new: " + nhost);
    360             if (nhost == null || nhost.length() <= 0)
    361                 return;
    362             if (ohost == null || ! ohost.equalsIgnoreCase(nhost)) {
    363                 newProps.setProperty(NTCPAddress.PROP_HOST, nhost);
    364                 changed = true;
    365             }
    366         } else if (enabled.equals("false") &&
    367                    name != null && name.length() > 0 &&
    368                    !name.equals(ohost) &&
    369                    nport != null) {
    370             // Host name is configured, and we have a port (either auto or configured)
    371             // but we probably only get here if the port is auto,
    372             // otherwise createNTCPAddress() would have done it already
    373             if (_log.shouldLog(Log.INFO))
    374                 _log.info("old: " + ohost + " config: " + name + " new: " + name);
    375             newProps.setProperty(NTCPAddress.PROP_HOST, name);
    376             changed = true;
    377         } else if (ohost == null || ohost.length() <= 0) {
    378             return;
    379         } else if (Boolean.parseBoolean(enabled) && status != STATUS_OK) {
    380             // UDP transitioned to not-OK, turn off NTCP address
    381             // This will commonly happen at startup if we were initially OK
    382             // because UPnP was successful, but a subsequent SSU Peer Test determines
    383             // we are still firewalled (SW firewall, bad UPnP indication, etc.)
    384             if (_log.shouldLog(Log.INFO))
    385                 _log.info("old: " + ohost + " config: " + name + " new: null");
    386             newAddr = null;
    387             changed = true;
    388         }
    389 
    390         if (!changed) {
    391             if (oldAddr != null) {
    392                 int oldCost = oldAddr.getCost();
    393                 int newCost = NTCPAddress.DEFAULT_COST;
    394                 if (TransportImpl.ADJUST_COST && !t.haveCapacity())
    395                     newCost++;
    396                 if (newCost != oldCost) {
    397                     oldAddr.setCost(newCost);
    398                     if (_log.shouldLog(Log.WARN))
    399                         _log.warn("Changing NTCP cost from " + oldCost + " to " + newCost);
    400                 } else {
    401                     _log.info("No change to NTCP Address");
    402                 }
    403             } else {
    404                 _log.info("No change to NTCP Address");
    405             }
    406             return;
    407         }
    408 
    409         // stopListening stops the pumper, readers, and writers, so required even if
    410         // oldAddr == null since startListening starts them all again
    411         //
    412         // really need to fix this so that we can change or create an inbound address
    413         // without tearing down everything
    414         // Especially on disabling the address, we shouldn't tear everything down.
    415         //
    416         _log.warn("Halting NTCP to change address");
    417         t.stopListening();
    418         if (newAddr != null)
    419             newAddr.setOptions(newProps);
    420         // Wait for NTCP Pumper to stop so we don't end up with two...
    421         while (t.isAlive()) {
    422             try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
    423         }
    424         t.restartListening(newAddr);
    425         _log.warn("Changed NTCP Address and started up, address is now " + newAddr);
    426         return;         
     212            if (udp != null)
     213                port = udp.getRequestedPort();
     214        }
     215        _manager.externalAddressReceived(Transport.AddressSource.SOURCE_SSU, ip, port);
    427216    }
    428217   
     
    452241                if (ri == null)
    453242                    continue;
    454                 String host = getIPString(ri);
    455                 if (host == null)
     243                byte[] ip = getIP(ri);
     244                if (ip == null)
    456245                    continue;
    457                 _geoIP.add(host);
     246                _geoIP.add(ip);
    458247            }
    459248            _context.simpleScheduler().addPeriodicEvent(new Lookup(), 5000, LOOKUP_TIME);
     
    492281    /**
    493282     *  Uses the transport IP first because that lookup is fast,
    494      *  then the SSU IP from the netDb.
     283     *  then the IP from the netDb.
    495284     *
    496285     *  @return two-letter lower-case country code or null
     
    499288    public String getCountry(Hash peer) {
    500289        byte[] ip = TransportImpl.getIP(peer);
     290        //if (ip != null && ip.length == 4)
    501291        if (ip != null)
    502292            return _geoIP.get(ip);
     
    504294        if (ri == null)
    505295            return null;
    506         String s = getIPString(ri);
    507         if (s != null)
    508             return _geoIP.get(s);
     296        ip = getIP(ri);
     297        if (ip != null)
     298            return _geoIP.get(ip);
    509299        return null;
    510300    }
    511301
    512     private String getIPString(RouterInfo ri) {
    513         // use SSU only, it is likely to be an IP not a hostname,
    514         // we don't want to generate a lot of DNS queries at startup
    515         RouterAddress ra = ri.getTargetAddress("SSU");
    516         if (ra == null)
    517             return null;
    518         return ra.getOption("host");
     302    private static byte[] getIP(RouterInfo ri) {
     303        // Return first IP (v4 or v6) we find, any transport
     304        // Assume IPv6 doesn't have geoIP for now
     305        for (RouterAddress ra : ri.getAddresses()) {
     306            byte[] rv = ra.getIP();
     307            //if (rv != null && rv.length == 4)
     308            if (rv != null)
     309                return rv;
     310        }
     311        return null;
    519312    }
    520313
     
    557350    }
    558351
    559     /** @since 0.8.13 */
    560     @Override
    561     public boolean isDummy() { return false; }
     352    /**
     353     *  Is everything disabled for testing?
     354     *  @since 0.8.13
     355     */
     356    @Override
     357    public boolean isDummy() {
     358        return _context.getBooleanProperty(PROP_DISABLED);
     359    }
    562360
    563361    /**
  • router/java/src/net/i2p/router/transport/GeoIP.java

    rbddfe3ed r79f8e88  
    4949    /** code to itself to prevent String proliferation */
    5050    private final Map<String, String> _codeCache;
     51
     52    // In the following structures, an IPv4 IP is stored as a non-negative long, 0 to 2**32 - 1,
     53    // and the first 8 bytes of an IPv6 IP are stored as a signed long.
    5154    private final Map<Long, String> _IPToCountry;
    5255    private final Set<Long> _pendingSearch;
     56    private final Set<Long> _pendingIPv6Search;
    5357    private final Set<Long> _notFound;
    5458    private final AtomicBoolean _lock;
     
    5963        _context = context;
    6064        _log = context.logManager().getLog(GeoIP.class);
    61         _codeToName = new ConcurrentHashMap(256);
    62         _codeCache = new ConcurrentHashMap(256);
     65        _codeToName = new ConcurrentHashMap(512);
     66        _codeCache = new ConcurrentHashMap(512);
    6367        _IPToCountry = new ConcurrentHashMap();
    6468        _pendingSearch = new ConcurrentHashSet();
     69        _pendingIPv6Search = new ConcurrentHashSet();
    6570        _notFound = new ConcurrentHashSet();
    6671        _lock = new AtomicBoolean();
     
    8287        _IPToCountry.clear();
    8388        _pendingSearch.clear();
     89        _pendingIPv6Search.clear();
    8490        _notFound.clear();
    8591    }
     
    108114        if (! _context.getBooleanPropertyDefaultTrue(PROP_GEOIP_ENABLED)) {
    109115            _pendingSearch.clear();
     116            _pendingIPv6Search.clear();
    110117            return;
    111118        }
     
    133140                if (((++_lookupRunCount) % CLEAR) == 0)
    134141                    _notFound.clear();
     142                // IPv4
    135143                Long[] search = _pendingSearch.toArray(new Long[_pendingSearch.size()]);
    136                 if (search.length <= 0)
    137                     return;
    138144                _pendingSearch.clear();
    139                 Arrays.sort(search);
    140                 String[] countries = readGeoIPFile(search);
    141    
    142                 for (int i = 0; i < countries.length; i++) {
    143                     if (countries[i] != null)
    144                         _IPToCountry.put(search[i], countries[i]);
    145                     else
    146                         _notFound.add(search[i]);
     145                if (search.length > 0) {
     146                    String[] countries = readGeoIPFile(search);
     147                    for (int i = 0; i < countries.length; i++) {
     148                        if (countries[i] != null)
     149                            _IPToCountry.put(search[i], countries[i]);
     150                        else
     151                            _notFound.add(search[i]);
     152                    }
     153                }
     154                // IPv6
     155                search = _pendingSearch.toArray(new Long[_pendingIPv6Search.size()]);
     156                _pendingIPv6Search.clear();
     157                if (search.length > 0) {
     158                    String[] countries = GeoIPv6.readGeoIPFile(_context, search, _codeCache);
     159                    for (int i = 0; i < countries.length; i++) {
     160                        if (countries[i] != null)
     161                            _IPToCountry.put(search[i], countries[i]);
     162                        else
     163                            _notFound.add(search[i]);
     164                    }
    147165                }
    148166            } finally {
     
    170188    */
    171189    private void readCountryFile() {
    172         File GeoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
    173         GeoFile = new File(GeoFile, COUNTRY_FILE_DEFAULT);
    174         if (!GeoFile.exists()) {
     190        File geoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
     191        geoFile = new File(geoFile, COUNTRY_FILE_DEFAULT);
     192        if (!geoFile.exists()) {
    175193            if (_log.shouldLog(Log.WARN))
    176                 _log.warn("Country file not found: " + GeoFile.getAbsolutePath());
     194                _log.warn("Country file not found: " + geoFile.getAbsolutePath());
    177195            return;
    178196        }
    179197        FileInputStream in = null;
    180198        try {
    181             in = new FileInputStream(GeoFile);
     199            in = new FileInputStream(geoFile);
    182200            BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8"));
    183201            String line = null;
     
    229247    */
    230248    private String[] readGeoIPFile(Long[] search) {
    231         File GeoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
    232         GeoFile = new File(GeoFile, GEOIP_FILE_DEFAULT);
    233         if (!GeoFile.exists()) {
     249        File geoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT);
     250        geoFile = new File(geoFile, GEOIP_FILE_DEFAULT);
     251        if (!geoFile.exists()) {
    234252            if (_log.shouldLog(Log.WARN))
    235                 _log.warn("GeoIP file not found: " + GeoFile.getAbsolutePath());
     253                _log.warn("GeoIP file not found: " + geoFile.getAbsolutePath());
    236254            return new String[0];
    237255        }
     
    241259        FileInputStream in = null;
    242260        try {
    243             in = new FileInputStream(GeoFile);
     261            in = new FileInputStream(geoFile);
    244262            String buf = null;
    245263            BufferedReader br = new BufferedReader(new InputStreamReader(in, "ISO-8859-1"));
     
    269287        } catch (IOException ioe) {
    270288            if (_log.shouldLog(Log.ERROR))
    271                 _log.error("Error reading the GeoFile", ioe);
     289                _log.error("Error reading the geoFile", ioe);
    272290        } finally {
    273291            if (in != null) try { in.close(); } catch (IOException ioe) {}
     
    308326    /**
    309327     * Add to the list needing lookup
     328     * @param ip IPv4 or IPv6
    310329     */
    311330    public void add(String ip) {
     
    315334    }
    316335
     336    /**
     337     * Add to the list needing lookup
     338     * @param ip IPv4 or IPv6
     339     */
    317340    public void add(byte ip[]) {
    318         if (ip.length != 4)
    319             return;
    320341        add(toLong(ip));
    321342    }
    322343
     344    /** see above for ip-to-long mapping */
    323345    private void add(long ip) {
    324346        Long li = Long.valueOf(ip);
    325         if (!(_IPToCountry.containsKey(li) || _notFound.contains(li)))
    326             _pendingSearch.add(li);
     347        if (!(_IPToCountry.containsKey(li) || _notFound.contains(li))) {
     348            if (ip >= 0 && ip < (1L << 32))
     349                _pendingSearch.add(li);
     350            else
     351                _pendingIPv6Search.add(li);
     352        }
    327353    }
    328354
    329355    /**
    330356     * Get the country for an IP from the cache.
     357     * @param ip IPv4 or IPv6
    331358     * @return lower-case code, generally two letters, or null.
    332359     */
     
    339366    /**
    340367     * Get the country for an IP from the cache.
     368     * @param ip IPv4 or IPv6
    341369     * @return lower-case code, generally two letters, or null.
    342370     */
    343371    public String get(byte ip[]) {
    344         if (ip.length != 4)
    345             return null;
    346372        return get(toLong(ip));
    347373    }
    348374
     375    /** see above for ip-to-long mapping */
    349376    private String get(long ip) {
    350377        return _IPToCountry.get(Long.valueOf(ip));
    351378    }
    352379
     380    /** see above for ip-to-long mapping */
    353381    private static long toLong(byte ip[]) {
    354382        int rv = 0;
    355         for (int i = 0; i < 4; i++)
    356             rv |= (ip[i] & 0xff) << ((3-i)*8);
    357         return rv & 0xffffffffl;
     383        if (ip.length == 16) {
     384            for (int i = 0; i < 8; i++)
     385                rv |= (ip[i] & 0xffL) << ((7-i)*8);
     386            return rv;
     387        } else {
     388            for (int i = 0; i < 4; i++)
     389                rv |= (ip[i] & 0xff) << ((3-i)*8);
     390            return rv & 0xffffffffl;
     391        }
    358392    }
    359393
  • router/java/src/net/i2p/router/transport/GetBidsJob.java

    rbddfe3ed r79f8e88  
    2424class GetBidsJob extends JobImpl {
    2525    private final Log _log;
    26     private final CommSystemFacadeImpl _facade;
     26    private final TransportManager _tmgr;
    2727    private final OutNetMessage _msg;
    2828   
    29     public GetBidsJob(RouterContext ctx, CommSystemFacadeImpl facade, OutNetMessage msg) {
     29    /**
     30     *  @deprecated unused, see static getBids()
     31     */
     32    public GetBidsJob(RouterContext ctx, TransportManager tmgr, OutNetMessage msg) {
    3033        super(ctx);
    3134        _log = ctx.logManager().getLog(GetBidsJob.class);
    32         _facade = facade;
     35        _tmgr = tmgr;
    3336        _msg = msg;
    3437    }
     
    3639    public String getName() { return "Fetch bids for a message to be delivered"; }
    3740    public void runJob() {
    38         getBids(getContext(), _facade, _msg);
     41        getBids(getContext(), _tmgr, _msg);
    3942    }
    4043   
    41     static void getBids(RouterContext context, CommSystemFacadeImpl facade, OutNetMessage msg) {
     44    static void getBids(RouterContext context, TransportManager tmgr, OutNetMessage msg) {
    4245        Log log = context.logManager().getLog(GetBidsJob.class);
    4346        Hash to = msg.getTarget().getIdentity().getHash();
     
    6265        }
    6366       
    64         TransportBid bid = facade.getNextBid(msg);
     67        TransportBid bid = tmgr.getNextBid(msg);
    6568        if (bid == null) {
    6669            int failedCount = msg.getFailedTransports().size();
     
    6972                // This used to be "no common transports" but it is almost always no transports at all
    7073                context.banlist().banlistRouter(to, _x("No transports (hidden or starting up?)"));
    71             } else if (failedCount >= facade.getTransportCount()) {
     74            } else if (failedCount >= tmgr.getTransportCount()) {
    7275                context.statManager().addRateData("transport.bidFailAllTransports", msg.getLifetime());
    7376                // fail after all transports were unsuccessful
     
    8386   
    8487   
    85     private static void fail(RouterContext context, OutNetMessage msg) {
     88    static void fail(RouterContext context, OutNetMessage msg) {
    8689        if (msg.getOnFailedSendJob() != null) {
    8790            context.jobQueue().addJob(msg.getOnFailedSendJob());
  • router/java/src/net/i2p/router/transport/Transport.java

    rbddfe3ed r79f8e88  
    3333     */
    3434    public void send(OutNetMessage msg);
    35     public RouterAddress startListening();
     35    public void startListening();
    3636    public void stopListening();
    37     public RouterAddress getCurrentAddress();
    38     public RouterAddress updateAddress();
    39     public static final String SOURCE_UPNP = "upnp";
    40     public static final String SOURCE_INTERFACE = "local";
    41     public static final String SOURCE_CONFIG = "config"; // unused
    42     public void externalAddressReceived(String source, byte[] ip, int port);
    43     public void forwardPortStatus(int port, int externalPort, boolean success, String reason);
     37
     38    /**
     39     *  What addresses are we currently listening to?
     40     *  Replaces getCurrentAddress()
     41     *  @return all addresses, non-null
     42     *  @since IPv6
     43     */
     44    public List<RouterAddress> getCurrentAddresses();
     45
     46    /**
     47     *  Do we have any current address?
     48     *  @since IPv6
     49     */
     50    public boolean hasCurrentAddress();
     51
     52    /**
     53     *  Ask the transport to update its addresses based on current information and return them
     54     *  @return all addresses, non-null
     55     */
     56    public List<RouterAddress> updateAddress();
     57
     58    /**
     59     *  @since IPv6
     60     */
     61    public enum AddressSource {
     62        SOURCE_UPNP("upnp"),
     63        SOURCE_INTERFACE("local"),
     64        /** unused */
     65        SOURCE_CONFIG("config"),
     66        SOURCE_SSU("ssu");
     67
     68        private final String cfgstr;
     69
     70        AddressSource(String cfgstr) {
     71            this.cfgstr = cfgstr;
     72        }
     73
     74        public String toConfigString() {
     75            return cfgstr;
     76        }
     77    }
     78
     79    /**
     80     *  Notify a transport of an external address change.
     81     *  This may be from a local interface, UPnP, a config change, etc.
     82     *  This should not be called if the ip didn't change
     83     *  (from that source's point of view), or is a local address.
     84     *  May be called multiple times for IPv4 or IPv6.
     85     *  The transport should also do its own checking on whether to accept
     86     *  notifications from this source.
     87     *
     88     *  This can be called before startListening() to set an initial address,
     89     *  or after the transport is running.
     90     *
     91     *  @param source defined in Transport.java
     92     *  @param ip typ. IPv4 or IPv6 non-local; may be null to indicate IPv4 failure or port info only
     93     *  @param port 0 for unknown or unchanged
     94     */
     95    public void externalAddressReceived(AddressSource source, byte[] ip, int port);
     96
     97    /**
     98     *  Notify a transport of the results of trying to forward a port.
     99     *
     100     *  @param ip may be null
     101     *  @param port the internal port
     102     *  @param externalPort the external port, which for now should always be the same as
     103     *                      the internal port if the forwarding was successful.
     104     */
     105    public void forwardPortStatus(byte[] ip, int port, int externalPort, boolean success, String reason);
     106
     107    /**
     108     * What INTERNAL port would the transport like to have forwarded by UPnP.
     109     * This can't be passed via getCurrentAddress(), as we have to open the port
     110     * before we can publish the address, and that's the external port anyway.
     111     *
     112     * @return port or -1 for none or 0 for any
     113     */
    44114    public int getRequestedPort();
     115
     116    /** Who to notify on message availability */
    45117    public void setListener(TransportEventListener listener);
     118
    46119    public String getStyle();
    47120   
     
    52125    public boolean haveCapacity(int pct);
    53126    public Vector getClockSkews();
    54     public List getMostRecentErrorMessages();
     127    public List<String> getMostRecentErrorMessages();
    55128   
    56129    public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException;
     
    58131    public void recheckReachability();
    59132    public boolean isBacklogged(Hash dest);
     133
     134    /**
     135     * Was the peer UNreachable (outbound only) the last time we tried it?
     136     * This is NOT reset if the peer contacts us and it is never expired.
     137     */
    60138    public boolean wasUnreachable(Hash dest);
    61139   
  • router/java/src/net/i2p/router/transport/TransportImpl.java

    rbddfe3ed r79f8e88  
    1111import java.io.IOException;
    1212import java.io.Writer;
     13import java.net.InetAddress;
    1314import java.util.ArrayList;
     15import java.util.Collection;
    1416import java.util.Collections;
     17import java.util.Comparator;
    1518import java.util.Date;
    1619import java.util.HashMap;
     
    2427import java.util.concurrent.ArrayBlockingQueue;
    2528import java.util.concurrent.BlockingQueue;
     29import java.util.concurrent.CopyOnWriteArrayList;
    2630
    2731import net.i2p.data.DataHelper;
     
    3741import net.i2p.router.Router;
    3842import net.i2p.router.RouterContext;
    39 import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade;
    4043import net.i2p.util.ConcurrentHashSet;
    4144import net.i2p.util.LHMCache;
     
    5255    private final Log _log;
    5356    private TransportEventListener _listener;
    54     private RouterAddress _currentAddress;
     57    protected final List<RouterAddress> _currentAddresses;
    5558    // Only used by NTCP. SSU does not use. See send() below.
    5659    private final BlockingQueue<OutNetMessage> _sendPool;
     
    5962    private final Map<Hash, Long>  _unreachableEntries;
    6063    private final Set<Hash> _wasUnreachableEntries;
     64    private final Set<InetAddress> _localAddresses;
    6165    /** global router ident -> IP */
    6266    private static final Map<Hash, byte[]> _IPMap;
     
    8993        //_context.statManager().createRateStat("transport.sendProcessingTime." + getStyle(), "Time to process and send a message (ms)", "Transport", new long[] { 60*1000l });
    9094        _context.statManager().createRateStat("transport.expiredOnQueueLifetime", "How long a message that expires on our outbound queue is processed", "Transport", new long[] { 60*1000l, 10*60*1000l, 60*60*1000l, 24*60*60*1000l } );
     95
     96        _currentAddresses = new CopyOnWriteArrayList();
    9197        if (getStyle().equals("NTCP"))
    9298            _sendPool = new ArrayBlockingQueue(8);
     
    95101        _unreachableEntries = new HashMap(16);
    96102        _wasUnreachableEntries = new ConcurrentHashSet(16);
     103        _localAddresses = new ConcurrentHashSet(4);
    97104        _context.simpleScheduler().addPeriodicEvent(new CleanupUnreachable(), 2 * UNREACHABLE_PERIOD, UNREACHABLE_PERIOD / 2);
    98105    }
     
    120127    /** Per-transport connection limit */
    121128    public int getMaxConnections() {
     129        if (_context.commSystem().isDummy())
     130            // testing
     131            return 0;
    122132        String style = getStyle();
    123133        // object churn
     
    136146                def *= (1 + bw - Router.CAPABILITY_BW12);
    137147        }
    138         if (((FloodfillNetworkDatabaseFacade)_context.netDb()).floodfillEnabled()) {
     148        if (_context.netDb().floodfillEnabled()) {
    139149            // && !SystemVersion.isWindows()) {
    140150            def *= 17; def /= 10;  // 425 for Class O ff
     
    168178    public Vector getClockSkews() { return new Vector(); }
    169179
    170     public List getMostRecentErrorMessages() { return Collections.EMPTY_LIST; }
     180    public List<String> getMostRecentErrorMessages() { return Collections.EMPTY_LIST; }
    171181
    172182    /**
     
    464474
    465475    /** Do we increase the advertised cost when approaching conn limits? */
    466     public static final boolean ADJUST_COST = true;
    467 
    468     /** What addresses are we currently listening to? */
    469     public RouterAddress getCurrentAddress() {
    470         return _currentAddress;
     476    protected static final boolean ADJUST_COST = true;
     477    /** TODO change to 2 */
     478    protected static final int CONGESTION_COST_ADJUSTMENT = 1;
     479
     480    /**
     481     *  What addresses are we currently listening to?
     482     *  Replaces getCurrentAddress()
     483     *  @return all addresses, non-null
     484     *  @since IPv6
     485     */
     486    public List<RouterAddress> getCurrentAddresses() {
     487        return _currentAddresses;
     488    }
     489
     490    /**
     491     *  What address are we currently listening to?
     492     *  Replaces getCurrentAddress()
     493     *  @param ipv6 true for IPv6 only; false for IPv4 only
     494     *  @return first matching address or null
     495     *  @since IPv6
     496     */
     497    public RouterAddress getCurrentAddress(boolean ipv6) {
     498        for (RouterAddress ra : _currentAddresses) {
     499            if (ipv6 == TransportUtil.isIPv6(ra))
     500                return ra;
     501        }
     502        return null;
     503    }
     504
     505    /**
     506     *  Do we have any current address?
     507     *  @since IPv6
     508     */
     509    public boolean hasCurrentAddress() {
     510        return !_currentAddresses.isEmpty();
    471511    }
    472512
     
    474514     * Ask the transport to update its address based on current information and return it
    475515     * Transports should override.
     516     * @return all addresses, non-null
    476517     * @since 0.7.12
    477518     */
    478     public RouterAddress updateAddress() {
    479         return _currentAddress;
    480     }
    481 
    482     /**
    483      * Replace any existing addresses for the current transport with the given
    484      * one.
     519    public List<RouterAddress> updateAddress() {
     520        return _currentAddresses;
     521    }
     522
     523    /**
     524     *  Replace any existing addresses for the current transport
     525     *  with the same IP length (4 or 16) with the given one.
     526     *  TODO: Allow multiple addresses of the same length.
     527     *  Calls listener.transportAddressChanged()
     528     *
     529     *  @param address null to remove all
    485530     */
    486531    protected void replaceAddress(RouterAddress address) {
    487         // _log.error("Replacing address for " + getStyle() + " was " + _currentAddress + " now " + address);
    488         _currentAddress = address;
     532        if (_log.shouldLog(Log.WARN))
     533             _log.warn("Replacing address with " + address, new Exception());
     534        if (address == null) {
     535            _currentAddresses.clear();
     536        } else {
     537            boolean isIPv6 = TransportUtil.isIPv6(address);
     538            for (RouterAddress ra : _currentAddresses) {
     539                if (isIPv6 == TransportUtil.isIPv6(ra))
     540                    _currentAddresses.remove(ra);
     541            }
     542            _currentAddresses.add(address);
     543        }
     544        if (_log.shouldLog(Log.WARN))
     545             _log.warn(getStyle() + " now has " + _currentAddresses.size() + " addresses");
    489546        if (_listener != null)
    490547            _listener.transportAddressChanged();
     548    }
     549
     550    /**
     551     *  Save a local address we were notified about before we started.
     552     *
     553     *  @since IPv6
     554     */
     555    protected void saveLocalAddress(InetAddress address) {
     556        _localAddresses.add(address);
     557    }
     558
     559    /**
     560     *  Return and then clear all saved local addresses.
     561     *
     562     *  @since IPv6
     563     */
     564    protected Collection<InetAddress> getSavedLocalAddresses() {
     565        List<InetAddress> rv = new ArrayList(_localAddresses);
     566        _localAddresses.clear();
     567        return rv;
     568    }
     569
     570    /**
     571     *  Get all available address we can use,
     572     *  shuffled and then sorted by cost/preference.
     573     *  Lowest cost (most preferred) first.
     574     *  @return non-null, possibly empty
     575     *  @since IPv6
     576     */
     577    protected List<RouterAddress> getTargetAddresses(RouterInfo target) {
     578        List<RouterAddress> rv = target.getTargetAddresses(getStyle());
     579        // Shuffle so everybody doesn't use the first one
     580        if (rv.size() > 1) {
     581            Collections.shuffle(rv, _context.random());
     582            TransportUtil.IPv6Config config = getIPv6Config();
     583            int adj;
     584            switch (config) {
     585              case IPV6_DISABLED:
     586                adj = 10; break;
     587              case IPV6_NOT_PREFERRED:
     588                adj = 1; break;
     589              default:
     590              case IPV6_ENABLED:
     591                adj = 0; break;
     592              case IPV6_PREFERRED:
     593                adj = -1; break;
     594              case IPV6_ONLY:
     595                adj = -10; break;
     596            }
     597            Collections.sort(rv, new AddrComparator(adj));
     598        }
     599        return rv;
     600    }
     601
     602    /**
     603     *  Compare based on published cost, adjusting for our IPv6 preference.
     604     *  Lowest cost (most preferred) first.
     605     *  @since IPv6
     606     */
     607    private static class AddrComparator implements Comparator<RouterAddress> {
     608        private final int adj;
     609
     610        public AddrComparator(int ipv6Adjustment) {
     611            adj = ipv6Adjustment;
     612        }
     613
     614        public int compare(RouterAddress l, RouterAddress r) {
     615            int lc = l.getCost();
     616            int rc = r.getCost();
     617            byte[] lip = l.getIP();
     618            byte[] rip = r.getIP();
     619            if (lip == null)
     620                lc += 20;
     621            else if (lip.length == 16)
     622                lc += adj;
     623            if (rip == null)
     624                rc += 20;
     625            else if (rip.length == 16)
     626                rc += adj;
     627            if (lc > rc)
     628                return 1;
     629            if (lc < rc)
     630                return -1;
     631            return 0;
     632        }
    491633    }
    492634
     
    495637     *  This may be from a local interface, UPnP, a config change, etc.
    496638     *  This should not be called if the ip didn't change
    497      *  (from that source's point of view), or is a local address,
    498      *  or if the ip is IPv6, but the transport should check anyway.
     639     *  (from that source's point of view), or is a local address.
     640     *  May be called multiple times for IPv4 or IPv6.
    499641     *  The transport should also do its own checking on whether to accept
    500642     *  notifications from this source.
     
    503645     *  or after the transport is running.
    504646     *
     647     *  This implementation does nothing. Transports should override if they want notification.
     648     *
    505649     *  @param source defined in Transport.java
    506      *  @param ip typ. IPv4 non-local
     650     *  @param ip typ. IPv4 or IPv6 non-local; may be null to indicate IPv4 failure or port info only
    507651     *  @param port 0 for unknown or unchanged
    508652     */
    509     public void externalAddressReceived(String source, byte[] ip, int port) {}
     653    public void externalAddressReceived(AddressSource source, byte[] ip, int port) {}
    510654
    511655    /**
    512656     *  Notify a transport of the results of trying to forward a port.
     657     *
     658     *  This implementation does nothing. Transports should override if they want notification.
     659     *
     660     *  @param ip may be null
    513661     *  @param port the internal port
    514662     *  @param externalPort the external port, which for now should always be the same as
    515663     *                      the internal port if the forwarding was successful.
    516664     */
    517     public void forwardPortStatus(int port, int externalPort, boolean success, String reason) {}
    518 
    519     /**
    520      * What port would the transport like to have forwarded by UPnP.
     665    public void forwardPortStatus(byte[] ip, int port, int externalPort, boolean success, String reason) {}
     666
     667    /**
     668     * What INTERNAL port would the transport like to have forwarded by UPnP.
    521669     * This can't be passed via getCurrentAddress(), as we have to open the port
    522      * before we can publish the address.
     670     * before we can publish the address, and that's the external port anyway.
    523671     *
    524672     * @return port or -1 for none or 0 for any
     
    532680    public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException { renderStatusHTML(out); }
    533681
    534     public RouterContext getContext() { return _context; }
    535682    public short getReachabilityStatus() { return CommSystemFacade.STATUS_UNKNOWN; }
    536683    public void recheckReachability() {}
     
    539686
    540687    private static final long UNREACHABLE_PERIOD = 5*60*1000;
     688
    541689    public boolean isUnreachable(Hash peer) {
    542690        long now = _context.clock().now();
     
    552700        }
    553701    }
     702
    554703    /** called when we can't reach a peer */
    555704    /** This isn't very useful since it is cleared when they contact us */
     
    561710        markWasUnreachable(peer, true);
    562711    }
     712
    563713    /** called when we establish a peer connection (outbound or inbound) */
    564714    public void markReachable(Hash peer, boolean isInbound) {
     
    606756            _wasUnreachableEntries.remove(peer);
    607757        if (_log.shouldLog(Log.INFO))
    608             _log.info(this.getStyle() + " setting wasUnreachable to " + yes + " for " + peer);
    609     }
    610 
     758            _log.info(this.getStyle() + " setting wasUnreachable to " + yes + " for " + peer,
     759                      yes ? new Exception() : null);
     760    }
     761
     762    /**
     763     * IP of the peer from the last connection (in or out, any transport).
     764     *
     765     * @param IPv4 or IPv6, non-null
     766     */
    611767    public void setIP(Hash peer, byte[] ip) {
    612768        byte[] old;
     
    618774    }
    619775
     776    /**
     777     * IP of the peer from the last connection (in or out, any transport).
     778     *
     779     * @return IPv4 or IPv6 or null
     780     */
    620781    public static byte[] getIP(Hash peer) {
    621782        synchronized (_IPMap) {
     
    633794    }
    634795
    635     /** @param addr non-null */
    636     public static boolean isPubliclyRoutable(byte addr[]) {
    637         if (addr.length == 4) {
    638             int a0 = addr[0] & 0xFF;
    639             if (a0 == 127) return false;
    640             if (a0 == 10) return false;
    641             int a1 = addr[1] & 0xFF;
    642             if (a0 == 172 && a1 >= 16 && a1 <= 31) return false;
    643             if (a0 == 192 && a1 == 168) return false;
    644             if (a0 >= 224) return false; // no multicast
    645             if (a0 == 0) return false;
    646             if (a0 == 169 && a1 == 254) return false;
    647             // 5/8 allocated to RIPE (30 November 2010)
    648             //if ((addr[0]&0xFF) == 5) return false;  // Hamachi
    649             return true; // or at least possible to be true
    650         } else if (addr.length == 16) {
    651             return false;
    652         } else {
    653             // ipv?
    654             return false;
    655         }
     796    /**
     797     *  @since IPv6
     798     */
     799    protected TransportUtil.IPv6Config getIPv6Config() {
     800        return TransportUtil.getIPv6Config(_context, getStyle());
     801    }
     802
     803    /**
     804     *  Allows IPv6 only if the transport is configured for it.
     805     *  Caller must check if we actually have a public IPv6 address.
     806     *  @param addr non-null
     807     */
     808    protected boolean isPubliclyRoutable(byte addr[]) {
     809        return TransportUtil.isPubliclyRoutable(addr,
     810                                                getIPv6Config() != TransportUtil.IPv6Config.IPV6_DISABLED);
    656811    }
    657812}
  • router/java/src/net/i2p/router/transport/TransportManager.java

    rbddfe3ed r79f8e88  
    1515import java.util.ArrayList;
    1616import java.util.HashMap;
     17import java.util.HashSet;
    1718import java.util.Iterator;
    1819import java.util.List;
     
    3031import net.i2p.router.OutNetMessage;
    3132import net.i2p.router.RouterContext;
     33import static net.i2p.router.transport.Transport.AddressSource.*;
    3234import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
    3335import net.i2p.router.transport.ntcp.NTCPTransport;
     
    8688    private void configTransports() {
    8789        boolean enableUDP = _context.getBooleanPropertyDefaultTrue(PROP_ENABLE_UDP);
     90        Transport udp = null;
    8891        if (enableUDP) {
    89             UDPTransport udp = new UDPTransport(_context, _dhThread);
     92            udp = new UDPTransport(_context, _dhThread);
    9093            addTransport(udp);
    9194            initializeAddress(udp);
    9295        }
    93         if (isNTCPEnabled(_context))
    94             addTransport(new NTCPTransport(_context, _dhThread));
     96        if (isNTCPEnabled(_context)) {
     97            Transport ntcp = new NTCPTransport(_context, _dhThread);
     98            addTransport(ntcp);
     99            initializeAddress(ntcp);
     100            if (udp != null) {
     101                // pass along the port SSU is probably going to use
     102                // so that NTCP may bind early
     103                int port = udp.getRequestedPort();
     104                if (port > 0)
     105                    ntcp.externalAddressReceived(SOURCE_CONFIG, null, port);
     106            }
     107        }
    95108        if (_transports.isEmpty())
    96109            _log.log(Log.CRIT, "No transports are enabled");
     
    101114    }
    102115   
     116    /**
     117     *  Notify transport of ALL routable interface addresses, including IPv6.
     118     *  It's the transport's job to ignore what it can't handle.
     119     */
    103120    private void initializeAddress(Transport t) {
    104         String ips = Addresses.getAnyAddress();
    105         if (ips == null)
    106             return;
    107         InetAddress ia;
    108         try {
    109             ia = InetAddress.getByName(ips);
    110         } catch (UnknownHostException e) {
    111             _log.error("UDP failed to bind to local address", e);
    112             return;
    113         }
    114         byte[] ip = ia.getAddress();
    115         t.externalAddressReceived(Transport.SOURCE_INTERFACE, ip, 0);
    116     }
    117 
    118     /**
    119      * callback from UPnP
    120      * Only tell SSU, it will tell NTCP
     121        Set<String> ipset = Addresses.getAddresses(false, true);  // non-local, include IPv6
     122        for (String ips : ipset) {
     123            try {
     124                InetAddress ia = InetAddress.getByName(ips);
     125                byte[] ip = ia.getAddress();
     126                t.externalAddressReceived(SOURCE_INTERFACE, ip, 0);
     127            } catch (UnknownHostException e) {
     128                _log.error("UDP failed to bind to local address", e);
     129            }
     130        }
     131    }
     132
     133    /**
     134     * Initialize from interfaces, and callback from UPnP or SSU.
     135     * Tell all transports... but don't loop
    121136     *
    122137     */
    123     public void externalAddressReceived(String source, byte[] ip, int port) {
    124         Transport t = getTransport(UDPTransport.STYLE);
    125         if (t != null)
    126             t.externalAddressReceived(source, ip, port);
     138    public void externalAddressReceived(Transport.AddressSource source, byte[] ip, int port) {
     139        for (Transport t : _transports.values()) {
     140            // don't loop
     141            if (!(source == SOURCE_SSU && t.getStyle().equals(UDPTransport.STYLE)))
     142                t.externalAddressReceived(source, ip, port);
     143        }
    127144    }
    128145
     
    131148     *
    132149     */
    133     public void forwardPortStatus(String style, int port, int externalPort, boolean success, String reason) {
     150    public void forwardPortStatus(String style, byte[] ip, int port, int externalPort, boolean success, String reason) {
    134151        Transport t = getTransport(style);
    135152        if (t != null)
    136             t.forwardPortStatus(port, externalPort, success, reason);
     153            t.forwardPortStatus(ip, port, externalPort, success, reason);
    137154    }
    138155
     
    149166        configTransports();
    150167        _log.debug("Starting up the transport manager");
    151         for (Transport t : _transports.values()) {
     168        // Let's do this in a predictable order to make testing easier
     169        // Start NTCP first so it can get notified from SSU
     170        List<Transport> tps = new ArrayList();
     171        Transport tp = getTransport(NTCPTransport.STYLE);
     172        if (tp != null)
     173            tps.add(tp);
     174        tp = getTransport(UDPTransport.STYLE);
     175        if (tp != null)
     176            tps.add(tp);
     177        //for (Transport t : _transports.values()) {
     178        for (Transport t : tps) {
    152179            t.startListening();
    153180            if (_log.shouldLog(Log.DEBUG))
     
    249276    public boolean haveInboundCapacity(int pct) {
    250277        for (Transport t : _transports.values()) {
    251             if (t.getCurrentAddress() != null && t.haveCapacity(pct))
     278            if (t.hasCurrentAddress() && t.haveCapacity(pct))
    252279                return true;
    253280        }
     
    267294            skews.addAll(tempSkews);
    268295        }
    269         if (_log.shouldLog(Log.DEBUG))
    270             _log.debug("Transport manager returning " + skews.size() + " peer clock skews.");
     296        //if (_log.shouldLog(Log.DEBUG))
     297        //    _log.debug("Transport manager returning " + skews.size() + " peer clock skews.");
    271298        return skews;
    272299    }
     
    325352     * For blocking purposes, etc. it's worth checking both
    326353     * the netDb addresses and this address.
     354     *
     355     * @return IPv4 or IPv6 or null
    327356     */
    328357    public byte[] getIP(Hash dest) {
     
    333362     *  This forces a rebuild
    334363     */
    335     public Map<String, RouterAddress> getAddresses() {
    336         Map<String, RouterAddress> rv = new HashMap(_transports.size());
     364    public List<RouterAddress> getAddresses() {
     365        List<RouterAddress> rv = new ArrayList(4);
    337366        // do this first since SSU may force a NTCP change
    338367        for (Transport t : _transports.values())
    339368            t.updateAddress();
    340369        for (Transport t : _transports.values()) {
    341             if (t.getCurrentAddress() != null)
    342                 rv.put(t.getStyle(), t.getCurrentAddress());
     370            rv.addAll(t.getCurrentAddresses());
    343371        }
    344372        return rv;
     
    346374   
    347375    /**
    348      * The actual or requested INTERNAL ports, for each transport,
    349      * which we will pass along to UPnP to be forwarded.
    350      */
    351     private Map<String, Integer> getPorts() {
    352         Map<String, Integer> rv = new HashMap(_transports.size());
     376     *  @since IPv6
     377     */
     378    static class Port {
     379        public final String style;
     380        public final int port;
     381
     382        public Port(String style, int port) {
     383            this.style = style;
     384            this.port = port;
     385        }
     386
     387        @Override
     388        public int hashCode() {
     389            return style.hashCode() ^ port;
     390        }
     391
     392        @Override
     393        public boolean equals(Object o) {
     394            if (o == null)
     395                return false;
     396            if (! (o instanceof Port))
     397                return false;
     398            Port p = (Port) o;
     399            return port == p.port && style.equals(p.style);
     400        }
     401    }
     402
     403    /**
     404     * Include the published port, or the requested port, for each transport
     405     * which we will pass along to UPnP
     406     */
     407    private Set<Port> getPorts() {
     408        Set<Port> rv = new HashSet(4);
    353409        for (Transport t : _transports.values()) {
    354410            int port = t.getRequestedPort();
    355411            // Use UDP port for NTCP too - see comment in NTCPTransport.getRequestedPort() for why this is here
    356412            if (t.getStyle().equals(NTCPTransport.STYLE) && port <= 0 &&
    357                 _context.getBooleanProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_AUTO_PORT)) {
     413                _context.getBooleanProperty(NTCPTransport.PROP_I2NP_NTCP_AUTO_PORT)) {
    358414                Transport udp = getTransport(UDPTransport.STYLE);
    359415                if (udp != null)
     
    361417            }
    362418            if (port > 0)
    363                 rv.put(t.getStyle(), Integer.valueOf(port));
     419                rv.add(new Port(t.getStyle(), port));
    364420        }
    365421        return rv;
     
    462518    public void messageReceived(I2NPMessage message, RouterIdentity fromRouter, Hash fromRouterHash) {
    463519        if (_log.shouldLog(Log.DEBUG))
    464             _log.debug("I2NPMessage received: " + message.getClass().getName(), new Exception("Where did I come from again?"));
     520            _log.debug("I2NPMessage received: " + message.getClass().getSimpleName() /*, new Exception("Where did I come from again?") */ );
    465521        try {
    466522            _context.inNetMessagePool().add(message, fromRouter, fromRouterHash);
    467             if (_log.shouldLog(Log.DEBUG))
    468                 _log.debug("Added to in pool");
     523            //if (_log.shouldLog(Log.DEBUG))
     524            //    _log.debug("Added to in pool");
    469525        } catch (IllegalArgumentException iae) {
    470526            if (_log.shouldLog(Log.WARN))
     
    478534    }
    479535
    480     public List getMostRecentErrorMessages() {
    481         List rv = new ArrayList(16);
     536    public List<String> getMostRecentErrorMessages() {
     537        List<String> rv = new ArrayList(16);
    482538        for (Transport t : _transports.values()) {
    483539            rv.addAll(t.getMostRecentErrorMessages());
     
    503559        buf.append("<h3>").append(_("Router Transport Addresses")).append("</h3><pre>\n");
    504560        for (Transport t : _transports.values()) {
    505             if (t.getCurrentAddress() != null)
    506                 buf.append(t.getCurrentAddress());
    507             else
     561            if (t.hasCurrentAddress()) {
     562                for (RouterAddress ra : t.getCurrentAddresses()) {
     563                    buf.append(ra.toString());
     564                    buf.append("\n\n");
     565                }
     566            } else {
    508567                buf.append(_("{0} is used for outbound connections only", t.getStyle()));
    509             buf.append("\n\n");
     568                buf.append("\n\n");
     569            }
    510570        }
    511571        buf.append("</pre>\n");
  • router/java/src/net/i2p/router/transport/UPnP.java

    rbddfe3ed r79f8e88  
    5353 * @see "http://www.upnp.org/"
    5454 * @see "http://en.wikipedia.org/wiki/Universal_Plug_and_Play"
     55 * @since 0.7.4
    5556 */
    5657
     
    148149
    149150                        short status = DetectedIP.NOT_SUPPORTED;
    150                         thinksWeAreDoubleNatted = !TransportImpl.isPubliclyRoutable(detectedIP.getAddress());
     151                        thinksWeAreDoubleNatted = !TransportUtil.isPubliclyRoutable(detectedIP.getAddress(), false);
    151152                        // If we have forwarded a port AND we don't have a private address
    152153                        if (_log.shouldLog(Log.WARN))
     
    844845                                }
    845846                                Map map = Collections.singletonMap(port, fps);
    846                                 forwardCallback.portForwardStatus(map);
     847                                try {
     848                                        forwardCallback.portForwardStatus(map);
     849                                } catch (Exception e) {
     850                                    _log.error("UPnP RPT error", e);
     851                                }
    847852                        }
    848853                }
  • router/java/src/net/i2p/router/transport/UPnPManager.java

    rbddfe3ed r79f8e88  
    1212
    1313import net.i2p.router.RouterContext;
     14import static net.i2p.router.transport.Transport.AddressSource.SOURCE_UPNP;
    1415import net.i2p.util.Addresses;
    1516import net.i2p.util.Log;
     
    2627 * the freenet data structures
    2728 *
     29 * @since 0.7.4
    2830 * @author zzz
    2931 */
     
    107109     * that should be ok.
    108110     */
    109     public void update(Map<String, Integer> ports) {
     111    public void update(Set<TransportManager.Port> ports) {
    110112        if (_log.shouldLog(Log.DEBUG))
    111113            _log.debug("UPnP Update with " + ports.size() + " ports");
     
    122124
    123125        Set<ForwardPort> forwards = new HashSet(ports.size());
    124         for (Map.Entry<String, Integer> entry : ports.entrySet()) {
    125             String style = entry.getKey();
    126             int port = entry.getValue().intValue();
     126        for (TransportManager.Port entry : ports) {
     127            String style = entry.style;
     128            int port = entry.port;
    127129            int protocol = -1;
    128130            if ("SSU".equals(style))
     
    152154                 _log.debug("UPnP Callback:");
    153155
     156            byte[] ipaddr = null;
    154157            DetectedIP[] ips = _upnp.getAddress();
    155158            if (ips != null) {
    156159                for (DetectedIP ip : ips) {
    157160                    // store the first public one and tell the transport manager if it changed
    158                     if (TransportImpl.isPubliclyRoutable(ip.publicAddress.getAddress())) {
     161                    if (TransportUtil.isPubliclyRoutable(ip.publicAddress.getAddress(), false)) {
    159162                        if (_log.shouldLog(Log.DEBUG))
    160163                            _log.debug("External address: " + ip.publicAddress + " type: " + ip.natType);
    161164                        if (!ip.publicAddress.equals(_detectedAddress)) {
    162165                            _detectedAddress = ip.publicAddress;
    163                             _manager.externalAddressReceived(Transport.SOURCE_UPNP, _detectedAddress.getAddress(), 0);
     166                            _manager.externalAddressReceived(SOURCE_UPNP, _detectedAddress.getAddress(), 0);
    164167                        }
     168                        ipaddr = ip.publicAddress.getAddress();
    165169                        break;
    166170                    }
     
    185189                    continue;
    186190                boolean success = fps.status >= ForwardPortStatus.MAYBE_SUCCESS;
    187                 _manager.forwardPortStatus(style, fp.portNumber, fps.externalPort, success, fps.reasonString);
     191                _manager.forwardPortStatus(style, ipaddr, fp.portNumber, fps.externalPort, success, fps.reasonString);
    188192            }
    189193        }
  • router/java/src/net/i2p/router/transport/ntcp/EstablishState.java

    rbddfe3ed r79f8e88  
    262262            // ok, we are onto the encrypted area
    263263            while (src.hasRemaining() && !_corrupt) {
    264                 if (_log.shouldLog(Log.DEBUG))
    265                     _log.debug(prefix()+"Encrypted bytes available (" + src.hasRemaining() + ")");
     264                //if (_log.shouldLog(Log.DEBUG))
     265                //    _log.debug(prefix()+"Encrypted bytes available (" + src.hasRemaining() + ")");
    266266                while (_curEncryptedOffset < _curEncrypted.length && src.hasRemaining()) {
    267267                    _curEncrypted[_curEncryptedOffset++] = src.get();
     
    300300                            if (_log.shouldLog(Log.ERROR)) _log.error(prefix()+"Error writing to the baos?", ioe);
    301301                        }
    302                         if (_log.shouldLog(Log.DEBUG))
    303                             _log.debug(prefix()+"subsequent block decrypted (" + _sz_aliceIdent_tsA_padding_aliceSig.size() + ")");
     302                        //if (_log.shouldLog(Log.DEBUG))
     303                        //    _log.debug(prefix()+"subsequent block decrypted (" + _sz_aliceIdent_tsA_padding_aliceSig.size() + ")");
    304304
    305305                        if (_sz_aliceIdent_tsA_padding_aliceSig.size() >= _sz_aliceIdent_tsA_padding_aliceSigSize) {
  • router/java/src/net/i2p/router/transport/ntcp/EventPumper.java

    rbddfe3ed r79f8e88  
    2121
    2222import net.i2p.I2PAppContext;
     23import net.i2p.data.RouterAddress;
    2324import net.i2p.data.RouterIdentity;
    2425import net.i2p.router.CommSystemFacade;
     
    780781                con.setKey(key);
    781782                try {
    782                     NTCPAddress naddr = con.getRemoteAddress();
    783                             if (naddr.getPort() <= 0)
    784                                 throw new IOException("Invalid NTCP address: " + naddr);
     783                    RouterAddress naddr = con.getRemoteAddress();
     784                    if (naddr.getPort() <= 0)
     785                        throw new IOException("Invalid NTCP address: " + naddr);
    785786                    InetSocketAddress saddr = new InetSocketAddress(naddr.getHost(), naddr.getPort());
    786787                    boolean connected = con.getChannel().connect(saddr);
  • router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java

    rbddfe3ed r79f8e88  
    22
    33import java.io.IOException;
     4import java.net.Inet6Address;
    45import java.nio.ByteBuffer;
    56import java.nio.channels.SelectionKey;
     
    1718import net.i2p.data.ByteArray;
    1819import net.i2p.data.DataHelper;
     20import net.i2p.data.RouterAddress;
    1921import net.i2p.data.RouterIdentity;
    2022import net.i2p.data.RouterInfo;
     
    8789    private final boolean _isInbound;
    8890    private volatile boolean _closed;
    89     private NTCPAddress _remAddr;
     91    private final RouterAddress _remAddr;
    9092    private RouterIdentity _remotePeer;
    9193    private long _clockSkew; // in seconds
     
    166168        _created = System.currentTimeMillis();
    167169        _transport = transport;
     170        _remAddr = null;
    168171        _chan = chan;
    169172        _readBufs = new ConcurrentLinkedQueue();
     
    188191     *
    189192     */
    190     public NTCPConnection(RouterContext ctx, NTCPTransport transport, RouterIdentity remotePeer, NTCPAddress remAddr) {
     193    public NTCPConnection(RouterContext ctx, NTCPTransport transport, RouterIdentity remotePeer, RouterAddress remAddr) {
    191194        _context = ctx;
    192195        _log = ctx.logManager().getLog(getClass());
     
    217220        _transport.establishing(this);
    218221    }
    219    
     222
     223    /**
     224     *  Valid for inbound; valid for outbound shortly after creation
     225     */
    220226    public SocketChannel getChannel() { return _chan; }
     227
     228    /**
     229     *  Valid for inbound; valid for outbound shortly after creation
     230     */
    221231    public SelectionKey getKey() { return _conKey; }
    222232    public void setChannel(SocketChannel chan) { _chan = chan; }
     
    224234    public boolean isInbound() { return _isInbound; }
    225235    public boolean isEstablished() { return _established; }
     236
     237    /**
     238     *  @since IPv6
     239     */
     240    public boolean isIPv6() {
     241        return _chan != null &&
     242               _chan.socket().getInetAddress() instanceof Inet6Address;
     243    }
     244
     245    /**
     246     *  Only valid during establishment; null later
     247     */
    226248    public EstablishState getEstablishState() { return _establishState; }
    227     public NTCPAddress getRemoteAddress() { return _remAddr; }
     249
     250    /**
     251     *  Only valid for outbound; null for inbound
     252     */
     253    public RouterAddress getRemoteAddress() { return _remAddr; }
     254
     255    /**
     256     *  Valid for outbound; valid for inbound after handshake
     257     */
    228258    public RouterIdentity getRemotePeer() { return _remotePeer; }
    229259    public void setRemotePeer(RouterIdentity ident) { _remotePeer = ident; }
  • router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java

    rbddfe3ed r79f8e88  
    44import java.net.InetSocketAddress;
    55import java.net.InetAddress;
     6import java.net.Inet6Address;
    67import java.net.UnknownHostException;
    78import java.nio.channels.ServerSocketChannel;
     
    910import java.text.DecimalFormat;
    1011import java.text.NumberFormat;
     12import java.util.ArrayList;
    1113import java.util.Collections;
    1214import java.util.Comparator;
    1315import java.util.HashMap;
     16import java.util.HashSet;
    1417import java.util.Iterator;
    1518import java.util.List;
     
    3134import net.i2p.router.transport.CommSystemFacadeImpl;
    3235import net.i2p.router.transport.Transport;
     36import static net.i2p.router.transport.Transport.AddressSource.*;
    3337import net.i2p.router.transport.TransportBid;
    3438import net.i2p.router.transport.TransportImpl;
     39import net.i2p.router.transport.TransportUtil;
     40import static net.i2p.router.transport.TransportUtil.IPv6Config.*;
    3541import net.i2p.router.transport.crypto.DHSessionKeyBuilder;
     42import net.i2p.router.transport.udp.UDPTransport;
    3643import net.i2p.util.Addresses;
    3744import net.i2p.util.ConcurrentHashSet;
    3845import net.i2p.util.Log;
     46import net.i2p.util.OrderedProperties;
    3947import net.i2p.util.Translate;
    4048
     
    5361    private final Object _conLock;
    5462    private final Map<Hash, NTCPConnection> _conByIdent;
    55     private NTCPAddress _myAddress;
    5663    private final EventPumper _pumper;
    5764    private final Reader _reader;
    5865    private net.i2p.router.transport.ntcp.Writer _writer;
     66    private int _ssuPort;
     67    /** synch on this */
     68    private final Set<InetSocketAddress> _endpoints;
     69
    5970    /**
    6071     * list of NTCPConnection of connections not yet established that we
     
    6374    private final Set<NTCPConnection> _establishing;
    6475
     76    public final static String PROP_I2NP_NTCP_HOSTNAME = "i2np.ntcp.hostname";
     77    public final static String PROP_I2NP_NTCP_PORT = "i2np.ntcp.port";
     78    public final static String PROP_I2NP_NTCP_AUTO_PORT = "i2np.ntcp.autoport";
     79    public final static String PROP_I2NP_NTCP_AUTO_IP = "i2np.ntcp.autoip";
     80    public static final int DEFAULT_COST = 10;
     81   
    6582    /** this is rarely if ever used, default is to bind to wildcard address */
    6683    public static final String PROP_BIND_INTERFACE = "i2np.ntcp.bindInterface";
     
    148165        //_context.statManager().createRateStat("ntcp.write", "", "ntcp", RATES);
    149166        _context.statManager().createRateStat("ntcp.writeError", "", "ntcp", RATES);
     167        _endpoints = new HashSet(4);
    150168        _establishing = new ConcurrentHashSet(16);
    151169        _conLock = new Object();
     
    196214                    RouterAddress addr = getTargetAddress(target);
    197215                    if (addr != null) {
    198                         NTCPAddress naddr = new NTCPAddress(addr);
    199                         con = new NTCPConnection(_context, this, ident, naddr);
     216                        con = new NTCPConnection(_context, this, ident, addr);
    200217                        if (_log.shouldLog(Log.DEBUG))
    201                             _log.debug("Send on a new con: " + con + " at " + addr + " for " + ih.toBase64());
     218                            _log.debug("Send on a new con: " + con + " at " + addr + " for " + ih);
    202219                        _conByIdent.put(ih, con);
    203220                    } else {
     
    319336            _log.debug("slow bid when trying to send to " + peer);
    320337        if (haveCapacity()) {
    321             if (addr.getCost() > NTCPAddress.DEFAULT_COST)
     338            if (addr.getCost() > DEFAULT_COST)
    322339                return _slowCostBid;
    323340            else
    324341                return _slowBid;
    325342        } else {
    326             if (addr.getCost() > NTCPAddress.DEFAULT_COST)
     343            if (addr.getCost() > DEFAULT_COST)
    327344                return _nearCapacityCostBid;
    328345            else
     
    337354     */
    338355    private RouterAddress getTargetAddress(RouterInfo target) {
    339         List<RouterAddress> addrs = target.getTargetAddresses(STYLE);
     356        List<RouterAddress> addrs = getTargetAddresses(target);
    340357        for (int i = 0; i < addrs.size(); i++) {
    341358            RouterAddress addr = addrs.get(i);
     
    459476     *  Unfortunately TransportManager doesn't do that, so we
    460477     *  check here to prevent two pumpers.
    461      *  @return appears to be ignored by caller
    462      */
    463     public synchronized RouterAddress startListening() {
     478     */
     479    public synchronized void startListening() {
    464480        // try once again to prevent two pumpers which is fatal
    465481        if (_pumper.isAlive())
    466             return _myAddress != null ? _myAddress.toRouterAddress() : null;
     482            return;
    467483        if (_log.shouldLog(Log.WARN)) _log.warn("Starting ntcp transport listening");
    468484
    469485        startIt();
    470         configureLocalAddress();
    471         return bindAddress();
    472     }
    473 
    474     /**
    475      *  Only called by CSFI.
    476      *  Caller should stop the transport first, then
    477      *  verify stopped with isAlive()
    478      *  @return appears to be ignored by caller
    479      */
    480     public synchronized RouterAddress restartListening(RouterAddress addr) {
    481         // try once again to prevent two pumpers which is fatal
    482         // we could just return null since the return value is ignored
    483         if (_pumper.isAlive())
    484             return _myAddress != null ? _myAddress.toRouterAddress() : null;
    485         if (_log.shouldLog(Log.WARN)) _log.warn("Restarting ntcp transport listening");
    486 
    487         startIt();
    488         if (addr == null)
    489             _myAddress = null;
     486        RouterAddress addr = configureLocalAddress();
     487        int port;
     488        if (addr != null)
     489            // probably not set
     490            port = addr.getPort();
    490491        else
    491             _myAddress = new NTCPAddress(addr);
    492         return bindAddress();
     492            // received by externalAddressReceived() from TransportManager
     493            port = _ssuPort;
     494        RouterAddress myAddress = bindAddress(port);
     495        if (myAddress != null) {
     496            // fixed interface, or bound to the specified host
     497            replaceAddress(myAddress);
     498        } else if (addr != null) {
     499            // specified host, bound to wildcard
     500            replaceAddress(addr);
     501        } else if (port > 0) {
     502            // all detected interfaces
     503            for (InetAddress ia : getSavedLocalAddresses()) {
     504                OrderedProperties props = new OrderedProperties();
     505                props.setProperty(RouterAddress.PROP_HOST, ia.getHostAddress());
     506                props.setProperty(RouterAddress.PROP_PORT, Integer.toString(port));
     507                int cost = getDefaultCost(ia instanceof Inet6Address);
     508                myAddress = new RouterAddress(STYLE, props, cost);
     509                replaceAddress(myAddress);
     510            }
     511        }
     512        // TransportManager.startListening() calls router.rebuildRouterInfo()
     513    }
     514
     515    /**
     516     *  Only called by externalAddressReceived().
     517     *
     518     *  Doesn't actually restart unless addr is non-null and
     519     *  the port is different from the current listen port.
     520     *
     521     *  If we had interface addresses before, we lost them.
     522     *
     523     *  @param addr may be null
     524     */
     525    private synchronized void restartListening(RouterAddress addr) {
     526        if (addr != null) {
     527            RouterAddress myAddress = bindAddress(addr.getPort());
     528            if (myAddress != null)
     529                replaceAddress(myAddress);
     530            else
     531                replaceAddress(addr);
     532            // UDPTransport.rebuildExternalAddress() calls router.rebuildRouterInfo()
     533        }
    493534    }
    494535
     
    521562    }
    522563
    523     /** call from synchronized method */
    524     private RouterAddress bindAddress() {
    525         if (_myAddress != null) {
     564    /**
     565     *  Only does something if myPort > 0 and myPort != current bound port
     566     *  (or there's no current port, or the configured interface or hostname changed).
     567     *  If we are changing the bound port, this restarts everything, which takes a long time.
     568     *
     569     *  call from synchronized method
     570     *
     571     *  @param myPort does nothing if <= 0
     572     *  @return new address ONLY if bound to specific address, otherwise null
     573     */
     574    private RouterAddress bindAddress(int port) {
     575        RouterAddress myAddress = null;
     576        if (port > 0) {
    526577            InetAddress bindToAddr = null;
    527578            String bindTo = _context.getProperty(PROP_BIND_INTERFACE);
     
    531582                // AND it's one of our local interfaces,
    532583                // bind only to that.
    533                 boolean isFixed = _context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_AUTO_IP, "true")
    534                                   .toLowerCase(Locale.US).equals("false");
    535                 String fixedHost = _context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_HOSTNAME);
    536                 if (isFixed && fixedHost != null) {
    537                     try {
    538                         String testAddr = InetAddress.getByName(fixedHost).getHostAddress();
    539                         if (Addresses.getAddresses().contains(testAddr))
    540                             bindTo = testAddr;
    541                     } catch (UnknownHostException uhe) {}
    542                 }
     584                bindTo = getFixedHost();
    543585            }
    544586
     
    547589                    bindToAddr = InetAddress.getByName(bindTo);
    548590                } catch (UnknownHostException uhe) {
    549                     _log.log(Log.CRIT, "Invalid NTCP bind interface specified [" + bindTo + "]", uhe);
     591                    _log.error("Invalid NTCP bind interface specified [" + bindTo + "]", uhe);
    550592                    // this can be implemented later, just updates some stats
    551593                    // see udp/UDPTransport.java
    552594                    //setReachabilityStatus(CommSystemFacade.STATUS_HOSED);
    553                     return null;
     595                    //return null;
     596                    // fall thru
    554597                }
    555598            }
    556599
    557600            try {
    558                 ServerSocketChannel chan = ServerSocketChannel.open();
    559                 chan.configureBlocking(false);
    560 
    561                 int port = _myAddress.getPort();
    562                 if (port > 0 && port < 1024)
    563                     _log.logAlways(Log.WARN, "Specified NTCP port is " + port + ", ports lower than 1024 not recommended");
    564                 InetSocketAddress addr = null;
    565                 if(bindToAddr==null) {
     601                InetSocketAddress addr;
     602                if (bindToAddr == null) {
    566603                    addr = new InetSocketAddress(port);
    567604                } else {
     
    569606                    if (_log.shouldLog(Log.WARN))
    570607                        _log.warn("Binding only to " + bindToAddr);
     608                    OrderedProperties props = new OrderedProperties();
     609                    props.setProperty(RouterAddress.PROP_HOST, bindTo);
     610                    props.setProperty(RouterAddress.PROP_PORT, Integer.toString(port));
     611                    int cost = getDefaultCost(false);
     612                    myAddress = new RouterAddress(STYLE, props, cost);
    571613                }
     614                if (!_endpoints.isEmpty()) {
     615                    // If we are already bound to the new address, OR
     616                    // if the host is specified and we are bound to the wildcard on the same port,
     617                    // do nothing. Changing config from wildcard to a specified host will
     618                    // require a restart.
     619                    if (_endpoints.contains(addr) ||
     620                        (bindToAddr != null && _endpoints.contains(new InetSocketAddress(port)))) {
     621                        if (_log.shouldLog(Log.WARN))
     622                            _log.warn("Already listening on " + addr);
     623                        return null;
     624                    }
     625                    // FIXME support multiple binds
     626                    // FIXME just close and unregister
     627                    stopWaitAndRestart();
     628                }
     629                if (port < 1024)
     630                    _log.logAlways(Log.WARN, "Specified NTCP port is " + port + ", ports lower than 1024 not recommended");
     631                ServerSocketChannel chan = ServerSocketChannel.open();
     632                chan.configureBlocking(false);
    572633                chan.socket().bind(addr);
     634                _endpoints.add(addr);
    573635                if (_log.shouldLog(Log.INFO))
    574636                    _log.info("Listening on " + addr);
     
    576638            } catch (IOException ioe) {
    577639                _log.error("Error listening", ioe);
     640                myAddress = null;
    578641            }
    579642        } else {
     
    581644                _log.info("Outbound NTCP connections only - no listener configured");
    582645        }
    583 
    584         if (_myAddress != null) {
    585             RouterAddress rv = _myAddress.toRouterAddress();
    586             if (rv != null)
    587                 replaceAddress(rv);
    588             return rv;
    589         } else {
    590             return null;
    591         }
    592     }
    593 
     646        return myAddress;
     647    }
     648
     649    /**
     650     *  @return configured host or null. Must be one of our local interfaces.
     651     *  @since IPv6 moved from bindAddress()
     652     */
     653    private String getFixedHost() {
     654        boolean isFixed = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "true")
     655                          .toLowerCase(Locale.US).equals("false");
     656        String fixedHost = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
     657        if (isFixed && fixedHost != null) {
     658            try {
     659                String testAddr = InetAddress.getByName(fixedHost).getHostAddress();
     660                // FIXME range of IPv6 addresses
     661                if (Addresses.getAddresses().contains(testAddr))
     662                    return testAddr;
     663            } catch (UnknownHostException uhe) {}
     664        }
     665        return null;
     666    }
     667
     668    /**
     669     *  Caller must sync
     670     *  @since IPv6 moved from externalAddressReceived()
     671     */
     672    private void stopWaitAndRestart() {
     673        if (_log.shouldLog(Log.WARN))
     674            _log.warn("Halting NTCP to change address");
     675        stopListening();
     676        // Wait for NTCP Pumper to stop so we don't end up with two...
     677        while (isAlive()) {
     678            try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
     679        }
     680        if (_log.shouldLog(Log.WARN))
     681            _log.warn("Restarting NTCP transport listening");
     682        startIt();
     683    }
     684
     685    /**
     686     *  Hook for NTCPConnection
     687     */
    594688    Reader getReader() { return _reader; }
     689
     690    /**
     691     *  Hook for NTCPConnection
     692     */
    595693    net.i2p.router.transport.ntcp.Writer getWriter() { return _writer; }
     694
    596695    public String getStyle() { return STYLE; }
     696
     697    /**
     698     *  Hook for NTCPConnection
     699     */
    597700    EventPumper getPumper() { return _pumper; }
    598701
     
    639742    //private boolean bindAllInterfaces() { return true; }
    640743
    641     /** caller must synch on this */
    642     private void configureLocalAddress() {
    643         RouterContext ctx = getContext();
    644         if (ctx == null) {
    645             System.err.println("NIO transport has no context?");
    646         } else {
     744    /**
     745     *  Generally returns null
     746     *  caller must synch on this
     747     */
     748    private RouterAddress configureLocalAddress() {
    647749            // this generally returns null -- see javadoc
    648             RouterAddress ra = CommSystemFacadeImpl.createNTCPAddress(ctx);
    649             if (ra != null) {
    650                 NTCPAddress addr = new NTCPAddress(ra);
     750            RouterAddress addr = createNTCPAddress();
     751            if (addr != null) {
    651752                if (addr.getPort() <= 0) {
    652                     _myAddress = null;
     753                    addr = null;
    653754                    if (_log.shouldLog(Log.ERROR))
    654755                        _log.error("NTCP address is outbound only, since the NTCP configuration is invalid");
    655756                } else {
    656                     _myAddress = addr;
    657                     replaceAddress(ra);
    658757                    if (_log.shouldLog(Log.INFO))
    659                         _log.info("NTCP address configured: " + _myAddress);
     758                        _log.info("NTCP address configured: " + addr);
    660759                }
    661760            } else {
     
    663762                    _log.info("NTCP address is outbound only");
    664763            }
    665         }
    666     }
     764            return addr;
     765    }
     766
     767    /**
     768     * This only creates an address if the hostname AND port are set in router.config,
     769     * which should be rare.
     770     * Otherwise, notifyReplaceAddress() below takes care of it.
     771     * Note this is called both from above and from NTCPTransport.startListening()
     772     *
     773     * @since IPv6 moved from CSFI
     774     */
     775    private RouterAddress createNTCPAddress() {
     776        // Fixme doesn't check PROP_BIND_INTERFACE
     777        String name = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
     778        if ( (name == null) || (name.trim().length() <= 0) || ("null".equals(name)) )
     779            return null;
     780        int p = _context.getProperty(PROP_I2NP_NTCP_PORT, -1);
     781        if (p <= 0 || p >= 64*1024)
     782            return null;
     783        OrderedProperties props = new OrderedProperties();
     784        props.setProperty(RouterAddress.PROP_HOST, name);
     785        props.setProperty(RouterAddress.PROP_PORT, Integer.toString(p));
     786        int cost = getDefaultCost(false);
     787        RouterAddress addr = new RouterAddress(STYLE, props, cost);
     788        return addr;
     789    }
     790   
     791    private int getDefaultCost(boolean isIPv6) {
     792        int rv = DEFAULT_COST;
     793        if (isIPv6) {
     794            TransportUtil.IPv6Config config = getIPv6Config();
     795            if (config == IPV6_PREFERRED)
     796                rv--;
     797            else if (config == IPV6_NOT_PREFERRED)
     798                rv++;
     799        }
     800        return rv;
     801    }
     802
     803    /**
     804     *  UDP changed addresses, tell NTCP and (possibly) restart
     805     *
     806     *  @since IPv6 moved from CSFI.notifyReplaceAddress()
     807     */
     808    @Override
     809    public void externalAddressReceived(AddressSource source, byte[] ip, int port) {
     810        if (_log.shouldLog(Log.WARN))
     811            _log.warn("Received address: " + Addresses.toString(ip, port) + " from: " + source);
     812        if (ip != null && !isPubliclyRoutable(ip)) {
     813            if (_log.shouldLog(Log.WARN))
     814                _log.warn("Invalid address: " + Addresses.toString(ip, port) + " from: " + source);
     815            return;
     816        }
     817        if (!isAlive()) {
     818            if (source == SOURCE_INTERFACE || source == SOURCE_UPNP) {
     819                try {
     820                    InetAddress ia = InetAddress.getByAddress(ip);
     821                    saveLocalAddress(ia);
     822                } catch (UnknownHostException uhe) {}
     823            } else if (source == SOURCE_CONFIG) {
     824                // save for startListening()
     825                _ssuPort = port;
     826            }
     827            return;
     828        }
     829        // ignore UPnP for now, get everything from SSU
     830        if (source != SOURCE_SSU)
     831            return;
     832        externalAddressReceived(ip, port);
     833    }
     834   
     835    /**
     836     *  UDP changed addresses, tell NTCP and restart.
     837     *  Port may be set to indicate requested port even if ip is null.
     838     *
     839     *  @param ip previously validated
     840     *  @since IPv6 moved from CSFI.notifyReplaceAddress()
     841     */
     842    private synchronized void externalAddressReceived(byte[] ip, int port) {
     843        // FIXME just take first IPv4 address for now
     844        // FIXME if SSU set to hostname, NTCP will be set to IP
     845        RouterAddress oldAddr = getCurrentAddress(false);
     846        if (_log.shouldLog(Log.INFO))
     847            _log.info("Changing NTCP Address? was " + oldAddr);
     848
     849        OrderedProperties newProps = new OrderedProperties();
     850        int cost;
     851        if (oldAddr == null) {
     852            cost = getDefaultCost(ip != null && ip.length == 16);
     853        } else {
     854            cost = oldAddr.getCost();
     855            newProps.putAll(oldAddr.getOptionsMap());
     856        }
     857        RouterAddress newAddr = new RouterAddress(STYLE, newProps, cost);
     858
     859        boolean changed = false;
     860
     861        // Auto Port Setting
     862        // old behavior (<= 0.7.3): auto-port defaults to false, and true trumps explicit setting
     863        // new behavior (>= 0.7.4): auto-port defaults to true, but explicit setting trumps auto
     864        // TODO rewrite this to operate on ints instead of strings
     865        String oport = newProps.getProperty(RouterAddress.PROP_PORT);
     866        String nport = null;
     867        String cport = _context.getProperty(PROP_I2NP_NTCP_PORT);
     868        if (cport != null && cport.length() > 0) {
     869            nport = cport;
     870        } else if (_context.getBooleanPropertyDefaultTrue(PROP_I2NP_NTCP_AUTO_PORT)) {
     871            // 0.9.6 change
     872            // This wasn't quite right, as udpAddr is the EXTERNAL port and we really
     873            // want NTCP to bind to the INTERNAL port the first time,
     874            // because if they are different, the NAT is changing them, and
     875            // it probably isn't mapping UDP and TCP the same.
     876            if (port > 0)
     877                // should always be true
     878                nport = Integer.toString(port);
     879        }
     880        if (_log.shouldLog(Log.INFO))
     881            _log.info("old: " + oport + " config: " + cport + " new: " + nport);
     882        if (nport == null || nport.length() <= 0)
     883            return;
     884        // 0.9.6 change
     885        // Don't have NTCP "chase" SSU's external port,
     886        // as it may change, possibly frequently.
     887        //if (oport == null || ! oport.equals(nport)) {
     888        if (oport == null) {
     889            newProps.setProperty(RouterAddress.PROP_PORT, nport);
     890            changed = true;
     891        }
     892
     893        // Auto IP Setting
     894        // old behavior (<= 0.7.3): auto-ip defaults to false, and trumps configured hostname,
     895        //                          and ignores reachability status - leading to
     896        //                          "firewalled with inbound TCP enabled" warnings.
     897        // new behavior (>= 0.7.4): auto-ip defaults to true, and explicit setting trumps auto,
     898        //                          and only takes effect if reachability is OK.
     899        //                          And new "always" setting ignores reachability status, like
     900        //                          "true" was in 0.7.3
     901        String ohost = newProps.getProperty(RouterAddress.PROP_HOST);
     902        String enabled = _context.getProperty(PROP_I2NP_NTCP_AUTO_IP, "true").toLowerCase(Locale.US);
     903        String name = _context.getProperty(PROP_I2NP_NTCP_HOSTNAME);
     904        // hostname config trumps auto config
     905        if (name != null && name.length() > 0)
     906            enabled = "false";
     907
     908        // assume SSU is happy if the address is non-null
     909        // TODO is this sufficient?
     910        boolean ssuOK = ip != null;
     911        if (_log.shouldLog(Log.INFO))
     912            _log.info("old: " + ohost + " config: " + name + " auto: " + enabled + " ssuOK? " + ssuOK);
     913        if (enabled.equals("always") ||
     914            (Boolean.parseBoolean(enabled) && ssuOK)) {
     915            // ip non-null
     916            String nhost = Addresses.toString(ip);
     917            if (_log.shouldLog(Log.INFO))
     918                _log.info("old: " + ohost + " config: " + name + " new: " + nhost);
     919            if (nhost == null || nhost.length() <= 0)
     920                return;
     921            if (ohost == null || ! ohost.equalsIgnoreCase(nhost)) {
     922                newProps.setProperty(RouterAddress.PROP_HOST, nhost);
     923                changed = true;
     924            }
     925        } else if (enabled.equals("false") &&
     926                   name != null && name.length() > 0 &&
     927                   !name.equals(ohost) &&
     928                   nport != null) {
     929            // Host name is configured, and we have a port (either auto or configured)
     930            // but we probably only get here if the port is auto,
     931            // otherwise createNTCPAddress() would have done it already
     932            if (_log.shouldLog(Log.INFO))
     933                _log.info("old: " + ohost + " config: " + name + " new: " + name);
     934            newProps.setProperty(RouterAddress.PROP_HOST, name);
     935            changed = true;
     936        } else if (ohost == null || ohost.length() <= 0) {
     937            return;
     938        } else if (Boolean.parseBoolean(enabled) && !ssuOK) {
     939            // UDP transitioned to not-OK, turn off NTCP address
     940            // This will commonly happen at startup if we were initially OK
     941            // because UPnP was successful, but a subsequent SSU Peer Test determines
     942            // we are still firewalled (SW firewall, bad UPnP indication, etc.)
     943            if (_log.shouldLog(Log.INFO))
     944                _log.info("old: " + ohost + " config: " + name + " new: null");
     945            newAddr = null;
     946            changed = true;
     947        }
     948
     949        if (!changed) {
     950            if (oldAddr != null) {
     951                // change cost only?
     952                int oldCost = oldAddr.getCost();
     953                int newCost = getDefaultCost(ohost != null && ohost.contains(":"));
     954                if (ADJUST_COST && !haveCapacity())
     955                    newCost += CONGESTION_COST_ADJUSTMENT;
     956                if (newCost != oldCost) {
     957                    newAddr.setCost(newCost);
     958                    if (_log.shouldLog(Log.WARN))
     959                        _log.warn("Changing NTCP cost from " + oldCost + " to " + newCost);
     960                    // fall thru and republish
     961                } else {
     962                    _log.info("No change to NTCP Address");
     963                    return;
     964                }
     965            } else {
     966                _log.info("No change to NTCP Address");
     967                return;
     968            }
     969        }
     970
     971        // stopListening stops the pumper, readers, and writers, so required even if
     972        // oldAddr == null since startListening starts them all again
     973        //
     974        // really need to fix this so that we can change or create an inbound address
     975        // without tearing down everything
     976        // Especially on disabling the address, we shouldn't tear everything down.
     977        //
     978        //if (_log.shouldLog(Log.WARN))
     979        //    _log.warn("Halting NTCP to change address");
     980        //stopListening();
     981        // Wait for NTCP Pumper to stop so we don't end up with two...
     982        //while (isAlive()) {
     983        //    try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
     984        //}
     985        restartListening(newAddr);
     986        if (_log.shouldLog(Log.WARN))
     987            _log.warn("Updating NTCP Address with " + newAddr);
     988        return;         
     989    }
     990   
     991
    667992
    668993    /**
     
    6771002     */
    6781003    @Override
    679     public void forwardPortStatus(int port, int externalPort, boolean success, String reason) {
     1004    public void forwardPortStatus(byte[] ip, int port, int externalPort, boolean success, String reason) {
    6801005        if (_log.shouldLog(Log.WARN)) {
    6811006            if (success)
    682                 _log.warn("UPnP has opened the NTCP port: " + port);
     1007                _log.warn("UPnP has opened the NTCP port: " + port + " via " + Addresses.toString(ip, externalPort));
    6831008            else
    6841009                _log.warn("UPnP has failed to open the NTCP port: " + port + " reason: " + reason);
     
    6871012
    6881013    /**
    689      *  @return current port, else NTCP configured port, else -1 (but not UDP port if auto)
     1014     *  @return current IPv4 port, else NTCP configured port, else -1 (but not UDP port if auto)
    6901015     */
    6911016    @Override
    6921017    public int getRequestedPort() {
    693         NTCPAddress addr = _myAddress;
     1018        RouterAddress addr = getCurrentAddress(false);
    6941019        if (addr != null) {
    6951020            int port = addr.getPort();
     
    7011026        // if (Boolean.valueOf(_context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_AUTO_PORT)).booleanValue())
    7021027        //    return foo;
    703         return _context.getProperty(CommSystemFacadeImpl.PROP_I2NP_NTCP_PORT, -1);
     1028        return _context.getProperty(PROP_I2NP_NTCP_PORT, -1);
    7041029    }
    7051030
     
    7151040    @Override
    7161041    public short getReachabilityStatus() {
    717         if (isAlive() && _myAddress != null) {
     1042        // If we have an IPv4 address
     1043        if (isAlive() && getCurrentAddress(false) != null) {
    7181044                for (NTCPConnection con : _conByIdent.values()) {
    7191045                    if (con.isInbound())
     
    7341060        _reader.stopReading();
    7351061        _finisher.stop();
    736         Map cons = null;
     1062        List<NTCPConnection> cons;
    7371063        synchronized (_conLock) {
    738             cons = new HashMap(_conByIdent);
     1064            cons = new ArrayList(_conByIdent.values());
    7391065            _conByIdent.clear();
    7401066        }
    741         for (Iterator iter = cons.values().iterator(); iter.hasNext(); ) {
    742             NTCPConnection con = (NTCPConnection)iter.next();
     1067        for (NTCPConnection con : cons) {
    7431068            con.close();
    7441069        }
    7451070        NTCPConnection.releaseResources();
    746         // will this work?
    7471071        replaceAddress(null);
     1072        _endpoints.clear();
    7481073    }
    7491074
     
    7541079    @Override
    7551080    public void renderStatusHTML(java.io.Writer out, String urlBase, int sortFlags) throws IOException {
    756         TreeSet peers = new TreeSet(getComparator(sortFlags));
     1081        TreeSet<NTCPConnection> peers = new TreeSet(getComparator(sortFlags));
    7571082        peers.addAll(_conByIdent.values());
    7581083
     
    7721097                   "<tr><th><a href=\"#def.peer\">").append(_("Peer")).append("</a></th>" +
    7731098                   "<th>").append(_("Dir")).append("</th>" +
     1099                   "<th>").append(_("IPv6")).append("</th>" +
    7741100                   "<th align=\"right\"><a href=\"#def.idle\">").append(_("Idle")).append("</a></th>" +
    7751101                   "<th align=\"right\"><a href=\"#def.rate\">").append(_("In/Out")).append("</a></th>" +
     
    7841110        out.write(buf.toString());
    7851111        buf.setLength(0);
    786         for (Iterator iter = peers.iterator(); iter.hasNext(); ) {
    787             NTCPConnection con = (NTCPConnection)iter.next();
     1112        for (NTCPConnection con : peers) {
    7881113            buf.append("<tr><td class=\"cells\" align=\"left\" nowrap>");
    7891114            buf.append(_context.commSystem().renderPeerHTML(con.getRemotePeer().calculateHash()));
     
    7961121            else
    7971122                buf.append("<img src=\"/themes/console/images/outbound.png\" alt=\"Outbound\" title=\"").append(_("Outbound")).append("\"/>");
     1123            buf.append("</td><td class=\"cells\" align=\"center\">");
     1124            if (con.isIPv6())
     1125                buf.append("&#x2713;");
     1126            else
     1127                buf.append("&nbsp;");
    7981128            buf.append("</td><td class=\"cells\" align=\"right\">");
    7991129            buf.append(DataHelper.formatDuration2(con.getTimeSinceReceive()));
     
    8441174        if (!peers.isEmpty()) {
    8451175//            buf.append("<tr> <td colspan=\"11\"><hr></td></tr>\n");
    846             buf.append("<tr class=\"tablefooter\"><td align=\"center\"><b>").append(peers.size()).append(' ').append(_("peers")).append("</b></td><td>&nbsp;</td><td>&nbsp;");
     1176            buf.append("<tr class=\"tablefooter\"><td colspan=\"4\" align=\"left\"><b>").append(_("SUMMARY"))
     1177               .append("</b>");
    8471178            buf.append("</td><td align=\"center\"><b>").append(formatRate(bpsRecv/1024)).append(THINSP).append(formatRate(bpsSend/1024)).append("</b>");
    8481179            buf.append("</td><td align=\"center\"><b>").append(DataHelper.formatDuration2(totalUptime/peers.size()));
  • router/java/src/net/i2p/router/transport/udp/ACKSender.java

    rbddfe3ed r79f8e88  
    6363    public synchronized void shutdown() {
    6464        _alive = false;
    65         PeerState poison = new PeerState(_context, _transport, null, 0, null, false);
     65        PeerState poison = new PeerState(_context, _transport, new byte[4], 0, null, false);
    6666        poison.setTheyRelayToUsAs(POISON_PS);
    6767        _peersToACK.offer(poison);
  • router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java

    rbddfe3ed r79f8e88  
    250250
    251251            if ((!_transport.isValid(maybeTo.getIP())) ||
    252                 Arrays.equals(maybeTo.getIP(), _transport.getExternalIP())) {
     252                (Arrays.equals(maybeTo.getIP(), _transport.getExternalIP()) && !_transport.allowLocal())) {
    253253                _transport.failed(msg, "Remote peer's IP isn't valid");
    254254                _transport.markUnreachable(toHash);
     
    448448                if (!_transport.allowConnection())
    449449                    return; // drop the packet
    450                 state = new InboundEstablishState(_context, from.getIP(), from.getPort(), _transport.getExternalPort(),
     450                byte[] fromIP = from.getIP();
     451                state = new InboundEstablishState(_context, fromIP, from.getPort(),
     452                                                  _transport.getExternalPort(fromIP.length == 16),
    451453                                                  _transport.getDHBuilder());
    452454                state.receiveSessionRequest(reader.getSessionRequestReader());
     
    460462        if (isNew) {
    461463            // Don't offer to relay to privileged ports.
     464            // Only offer for an IPv4 session.
    462465            // TODO if already we have their RI, only offer if they need it (no 'C' cap)
    463             if (_transport.canIntroduce() && state.getSentPort() >= 1024) {
     466            if (_transport.canIntroduce() && state.getSentPort() >= 1024 &&
     467                state.getSentIP().length == 4) {
    464468                // ensure > 0
    465469                long tag = 1 + _context.random().nextLong(MAX_TAG_VALUE);
     
    674678                if (smtu != null) {
    675679                    try {
    676                         int mtu = MTU.rectify(Integer.parseInt(smtu));
     680                        boolean isIPv6 = state.getSentIP().length == 16;
     681                        int mtu = MTU.rectify(isIPv6, Integer.parseInt(smtu));
    677682                        peer.setHisMTU(mtu);
    678683                    } catch (NumberFormatException nfe) {}
     
    834839            return;
    835840        }
    836         _transport.send(_builder.buildSessionCreatedPacket(state, _transport.getExternalPort(), _transport.getIntroKey()));
     841        _transport.send(_builder.buildSessionCreatedPacket(state,
     842                                                           _transport.getExternalPort(state.getSentIP().length == 16),
     843                                                           _transport.getIntroKey()));
    837844        state.createdPacketSent();
    838845    }
     
    885892    }
    886893
     894    /**
     895     *  We are Alice, we sent a RelayRequest to Bob and got a response back.
     896     */
    887897    void receiveRelayResponse(RemoteHostId bob, UDPPacketReader reader) {
    888898        long nonce = reader.getRelayResponseReader().readNonce();
     
    894904        }
    895905       
     906        // Note that we ignore the Alice (us) IP/Port in the RelayResponse
    896907        int sz = reader.getRelayResponseReader().readCharlieIPSize();
    897908        byte ip[] = new byte[sz];
     
    941952
    942953    /**
    943      *  Are IP and port valid?
     954     *  Are IP and port valid? This is only for checking the relay response.
     955     *  Reject all IPv6, for now, even if we are configured for it.
    944956     *  Refuse anybody in the same /16
    945957     *  @since 0.9.3
    946958     */
    947959    private boolean isValid(byte[] ip, int port) {
    948         return port >= 1024 &&
     960        return port >= UDPTransport.MIN_PEER_PORT &&
    949961               port <= 65535 &&
     962               ip != null && ip.length == 4 &&
    950963               _transport.isValid(ip) &&
    951                (!DataHelper.eq(ip, 0, _transport.getExternalIP(), 0, 2)) &&
     964               (!_transport.isTooClose(ip)) &&
    952965               (!_context.blocklist().isBlocklisted(ip));
    953966    }
  • router/java/src/net/i2p/router/transport/udp/IPThrottler.java

    rbddfe3ed r79f8e88  
    44import net.i2p.util.SimpleScheduler;
    55import net.i2p.util.SimpleTimer;
     6import net.i2p.util.SipHash;
    67
    78/**
     
    2223    /**
    2324     *  Increments before checking
    24      *  @return true if ip.length != 4
    2525     */
    2626    public boolean shouldThrottle(byte[] ip) {
    27         if (ip.length != 4)
    28             return true;
    29         return _counter.increment(toInt(ip)) > _max;
     27        // for IPv4 we simply use the IP;
     28        // for IPv6 we use a secure hash as an attacker could select the lower bytes
     29        Integer key;
     30        if (ip.length == 4)
     31            key = toInt(ip);
     32        else
     33            key = Integer.valueOf(SipHash.hashCode(ip));
     34        return _counter.increment(key) > _max;
    3035    }
    3136
  • router/java/src/net/i2p/router/transport/udp/InboundMessageFragments.java

    rbddfe3ed r79f8e88  
    6767        _messageReceiver.shutdown();
    6868    }
     69
    6970    public boolean isAlive() { return _alive; }
    7071
  • router/java/src/net/i2p/router/transport/udp/IntroductionManager.java

    rbddfe3ed r79f8e88  
    2424/**
    2525 *  Keep track of inbound and outbound introductions.
     26 *
     27 *  IPv6 info: Alice-Bob communication may be via IPv4 or IPv6.
     28 *  Bob-Charlie communication must be via established IPv4 session as that's the only way
     29 *  that Bob knows Charlie's IPv4 address to give it to Alice.
     30 *  Alice-Charlie communication is via IPv4.
     31 *  If Alice-Bob is over IPv6, Alice must include her IPv4 address in
     32 *  the RelayRequest message.
     33 *
     34 *  From udp.html on the website:
     35
     36<p>Indirect session establishment by means of a third party introduction
     37is necessary for efficient NAT traversal.  Charlie, a router behind a
     38NAT or firewall which does not allow unsolicited inbound UDP packets,
     39first contacts a few peers, choosing some to serve as introducers.  Each
     40of these peers (Bob, Bill, Betty, etc) provide Charlie with an introduction
     41tag - a 4 byte random number - which he then makes available to the public
     42as methods of contacting him.  Alice, a router who has Charlie's published
     43contact methods, first sends a RelayRequest packet to one or more of the
     44introducers, asking each to introduce her to Charlie (offering the
     45introduction tag to identify Charlie).  Bob then forwards a RelayIntro
     46packet to Charlie including Alice's public IP and port number, then sends
     47Alice back a RelayResponse packet containing Charlie's public IP and port
     48number.  When Charlie receives the RelayIntro packet, he sends off a small
     49random packet to Alice's IP and port (poking a hole in his NAT/firewall),
     50and when Alice receives Bob's RelayResponse packet, she begins a new
     51full direction session establishment with the specified IP and port.</p>
     52<p>
     53Alice first connects to introducer Bob, who relays the request to Charlie.
     54</p>
     55<pre>
     56        Alice                         Bob                  Charlie
     57    RelayRequest ----------------------&gt;
     58         &lt;-------------- RelayResponse    RelayIntro -----------&gt;
     59         &lt;-------------------------------------------- HolePunch (data ignored)
     60    SessionRequest --------------------------------------------&gt;
     61         &lt;-------------------------------------------- SessionCreated
     62    SessionConfirmed ------------------------------------------&gt;
     63         &lt;-------------------------------------------- DeliveryStatusMessage
     64         &lt;-------------------------------------------- DatabaseStoreMessage
     65    DatabaseStoreMessage --------------------------------------&gt;
     66    Data &lt;--------------------------------------------------&gt; Data
     67</pre>
     68
     69<p>
     70After the hole punch, the session is established between Alice and Charlie as in a direct establishment.
     71</p>
    2672 */
    2773class IntroductionManager {
     
    77123        // let's not use an introducer on a privileged port, sounds like trouble
    78124        if (peer.getRemotePort() < 1024)
     125            return;
     126        // Only allow relay as Bob or Charlie if the Bob-Charlie session is IPv4
     127        if (peer.getRemoteIP().length != 4)
    79128            return;
    80129        if (_log.shouldLog(Log.DEBUG))
     
    137186                continue;
    138187            }
     188            // FIXME we can include all his addresses including IPv6 even if we don't support IPv6 (isValid() is false)
     189            // but requires RelayRequest support, see below
    139190            RouterAddress ra = _transport.getTargetAddress(ri);
    140191            if (ra == null) {
     
    160211                continue;
    161212            }
     213            // FIXME we can include all his addresses including IPv6 even if we don't support IPv6 (isValid() is false)
     214            // but requires RelayRequest support, see below
    162215            byte[] ip = cur.getRemoteIP();
    163216            int port = cur.getRemotePort();
     
    332385        // ip/port inside message should be 0:0, as it's unimplemented on send -
    333386        // see PacketBuilder.buildRelayRequest()
     387        // and we don't read it here.
     388        // FIXME implement for getting Alice's IPv4 in RelayRequest sent over IPv6?
     389        // or is that just too easy to spoof?
    334390        if (!isValid(alice.getIP(), alice.getPort()) || ipSize != 0 || port != 0) {
    335391            if (_log.shouldLog(Log.WARN)) {
     
    369425    /**
    370426     *  Are IP and port valid?
     427     *  Reject all IPv6, for now, even if we are configured for it.
    371428     *  Refuse anybody in the same /16
    372429     *  @since 0.9.3
    373430     */
    374431    private boolean isValid(byte[] ip, int port) {
    375         return port >= 1024 &&
     432        return port >= UDPTransport.MIN_PEER_PORT &&
    376433               port <= 65535 &&
     434               ip != null && ip.length == 4 &&
    377435               _transport.isValid(ip) &&
    378                (!DataHelper.eq(ip, 0, _transport.getExternalIP(), 0, 2)) &&
     436               (!_transport.isTooClose(ip)) &&
    379437               (!_context.blocklist().isBlocklisted(ip));
    380438    }
  • router/java/src/net/i2p/router/transport/udp/MTU.java

    rbddfe3ed r79f8e88  
    22
    33import java.net.InetAddress;
     4import java.net.Inet6Address;
    45import java.net.NetworkInterface;
    56import java.net.SocketException;
     
    4243                            // testing
    4344                            //return ifc.getMTU();
    44                             return rectify(ifc.getMTU());
     45                            boolean isIPv6 = addr instanceof Inet6Address;
     46                            return rectify(isIPv6, ifc.getMTU());
    4547                        } catch (SocketException se) {
    4648                            // ignore
     
    5961    /**
    6062     * @return min of PeerState.MIN_MTU, max of PeerState.LARGE_MTU,
    61      *         rectified so rv % 16 == 12
     63     *         rectified so rv % 16 == 12 (IPv4)
     64     *         or rv % 16 == 0 (IPv6)
    6265     */
    63     public static int rectify(int mtu) {
     66    public static int rectify(boolean isIPv6, int mtu) {
    6467        int rv = mtu;
    6568        int mod = rv % 16;
     69        if (isIPv6) {
     70            rv -= mod;
     71            return Math.max(PeerState.MIN_IPV6_MTU, Math.min(PeerState.MAX_IPV6_MTU, rv));
     72        }
    6673        if (mod > 12)
    6774            rv -= mod - 12;
     
    7380/****
    7481    public static void main(String args[]) {
     82        System.out.println("Cmd line interfaces:");
     83        for (int i = 0; i < args.length; i++) {
     84            try {
     85                InetAddress test = InetAddress.getByName(args[i]);
     86                System.out.println("MTU of " + args[i] + " is " + getMTU(test));
     87            } catch (Exception e) {
     88                e.printStackTrace();
     89            }
     90        }
     91        System.out.println("All interfaces:");
    7592        try {
    76             InetAddress test = InetAddress.getByName(args[0]);
    77             System.out.println("MTU is " + getMTU(test));
    78         } catch (Exception e) {
    79             e.printStackTrace();
     93            Enumeration<NetworkInterface> ifcs = NetworkInterface.getNetworkInterfaces();
     94            if (ifcs != null) {
     95                while (ifcs.hasMoreElements()) {
     96                    NetworkInterface ifc = ifcs.nextElement();
     97                    for(Enumeration<InetAddress> addrs =  ifc.getInetAddresses(); addrs.hasMoreElements();) {
     98                        InetAddress addr = addrs.nextElement();
     99                        System.out.println("MTU of " + addr.getHostAddress() + " is " + getMTU(addr));
     100                    }
     101                }
     102            }
     103        } catch (SocketException se) {
     104             System.out.println("no interfaces");
    80105        }
    81106    }
  • router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java

    rbddfe3ed r79f8e88  
    310310                        // gets called regularly
    311311                        int toWait = Math.min(Math.max(nextSendDelay, 10), MAX_WAIT);
    312                         if (_log.shouldLog(Log.DEBUG))
    313                             _log.debug("wait for " + toWait);
     312                        //if (_log.shouldLog(Log.DEBUG))
     313                        //    _log.debug("wait for " + toWait);
    314314                        // wait.. or somethin'
    315315                        synchronized (_activePeers) {
  • router/java/src/net/i2p/router/transport/udp/PacketBuilder.java

    rbddfe3ed r79f8e88  
    142142    public static final int MIN_DATA_PACKET_OVERHEAD = IP_HEADER_SIZE + UDP_HEADER_SIZE + DATA_HEADER_SIZE;
    143143
     144    public static final int IPV6_HEADER_SIZE = 40;
     145    /** 94 */
     146    public static final int MIN_IPV6_DATA_PACKET_OVERHEAD = IPV6_HEADER_SIZE + UDP_HEADER_SIZE + DATA_HEADER_SIZE;
     147
    144148    /** one byte field */
    145149    public static final int ABSOLUTE_MAX_ACKS = 255;
     
    159163    private static final String PROP_PADDING = "i2np.udp.padding";
    160164
     165    /**
     166     *  @param transport may be null for unit testing only
     167     */
    161168    public PacketBuilder(I2PAppContext ctx, UDPTransport transport) {
    162169        _context = ctx;
     
    245252
    246253        int currentMTU = peer.getMTU();
    247         int availableForAcks = currentMTU - MIN_DATA_PACKET_OVERHEAD - dataSize;
     254        int availableForAcks = currentMTU - dataSize;
     255        int ipHeaderSize;
     256        if (peer.getRemoteIP().length == 4) {
     257            availableForAcks -= MIN_DATA_PACKET_OVERHEAD;
     258            ipHeaderSize = IP_HEADER_SIZE;
     259        } else {
     260            availableForAcks -= MIN_IPV6_DATA_PACKET_OVERHEAD;
     261            ipHeaderSize = IPV6_HEADER_SIZE;
     262        }
    248263        int availableForExplicitAcks = availableForAcks;
    249264
     
    401416       
    402417        if (_log.shouldLog(Log.INFO)) {
    403             msg.append(" pkt size ").append(off + (IP_HEADER_SIZE + UDP_HEADER_SIZE));
     418            msg.append(" pkt size ").append(off + (ipHeaderSize + UDP_HEADER_SIZE));
    404419            _log.info(msg.toString());
    405420        }
    406421        // the packet could have been built before the current mtu got lowered, so
    407422        // compare to LARGE_MTU
    408         if (off + (IP_HEADER_SIZE + UDP_HEADER_SIZE) > PeerState.LARGE_MTU) {
     423        if (off + (ipHeaderSize + UDP_HEADER_SIZE) > PeerState.LARGE_MTU) {
    409424            _log.error("Size is " + off + " for " + packet +
    410425                       " fragment " + fragment +
    411426                       " data size " + dataSize +
    412                        " pkt size " + (off + (IP_HEADER_SIZE + UDP_HEADER_SIZE)) +
     427                       " pkt size " + (off + (ipHeaderSize + UDP_HEADER_SIZE)) +
    413428                       " MTU " + currentMTU +
    414429                       ' ' + availableForAcks + " for all acks " +
     
    562577       
    563578        byte sentIP[] = state.getSentIP();
    564         if ( (sentIP == null) || (sentIP.length <= 0) || ( (_transport != null) && (!_transport.isValid(sentIP)) ) ) {
     579        if ( (sentIP == null) || (sentIP.length <= 0) || (!_transport.isValid(sentIP))) {
    565580            if (_log.shouldLog(Log.ERROR))
    566581                _log.error("How did our sent IP become invalid? " + state);
     
    643658
    644659        byte toIP[] = state.getSentIP();
    645         if ( (_transport !=null) && (!_transport.isValid(toIP)) ) {
     660        if (!_transport.isValid(toIP)) {
    646661            packet.release();
    647662            return null;
     
    10521067    // specify these if we know what our external receive ip/port is and if its different
    10531068    // from what bob is going to think
     1069    // FIXME IPv4 addr must be specified when sent over IPv6
    10541070    private byte[] getOurExplicitIP() { return null; }
    10551071    private int getOurExplicitPort() { return 0; }
     
    10711087            if (ikey == null || iport < 1024 || iport > 65535 ||
    10721088                iaddr == null || tag <= 0 ||
     1089                // must be IPv4 for now as we don't send Alice IP/port, see below
     1090                iaddr.getAddress().length != 4 ||
    10731091                (!_transport.isValid(iaddr.getAddress())) ||
    1074                 Arrays.equals(iaddr.getAddress(), _transport.getExternalIP())) {
     1092                (Arrays.equals(iaddr.getAddress(), _transport.getExternalIP()) && !_transport.allowLocal())) {
    10751093                if (_log.shouldLog(_log.WARN))
    10761094                    _log.warn("Cannot build a relay request to " + state.getRemoteIdentity().calculateHash()
     
    10841102    }
    10851103   
     1104    /**
     1105     *  TODO Alice IP/port in packet will always be null/0, must be fixed to
     1106     *  send a RelayRequest over IPv6
     1107     *
     1108     */
    10861109    private UDPPacket buildRelayRequest(InetAddress introHost, int introPort, byte introKey[],
    10871110                                        long introTag, SessionKey ourIntroKey, long introNonce, boolean encrypt) {
     
    10911114        int off = HEADER_SIZE;
    10921115       
     1116        // FIXME must specify these if request is going over IPv6
    10931117        byte ourIP[] = getOurExplicitIP();
    10941118        int ourPort = getOurExplicitPort();
     
    12121236        off += 2;
    12131237       
     1238        // Alice IP/Port currently ignored on receive - see UDPPacketReader
    12141239        byte aliceIP[] = alice.getIP();
    12151240        DataHelper.toLong(data, off, 1, aliceIP.length);
     
    12341259   
    12351260    /**
    1236      *  Sends an empty unauthenticated packet for hole punching.
     1261     *  Creates an empty unauthenticated packet for hole punching.
    12371262     *  Parameters must be validated previously.
    12381263     */
     
    12481273       
    12491274        packet.setMessageType(TYPE_PUNCH);
     1275        return packet;
     1276    }
     1277   
     1278    /**
     1279     *  TESTING ONLY.
     1280     *  Creates an arbitrary packet for unit testing.
     1281     *  Null transport in constructor OK.
     1282     *
     1283     *  @param type 0-15
     1284     *  @since IPv6
     1285     */
     1286    public UDPPacket buildPacket(byte[] data, InetAddress to, int port) {
     1287        UDPPacket packet = UDPPacket.acquire(_context, false);
     1288        byte d[] = packet.getPacket().getData();
     1289        System.arraycopy(data, 0, d, 0, data.length);
     1290        packet.getPacket().setLength(data.length);
     1291        setTo(packet, to, port);
    12501292        return packet;
    12511293    }
  • router/java/src/net/i2p/router/transport/udp/PacketHandler.java

    rbddfe3ed r79f8e88  
    44import java.util.List;
    55import java.util.Map;
     6import java.util.concurrent.BlockingQueue;
    67
    78import net.i2p.router.Router;
    89import net.i2p.router.RouterContext;
     10import net.i2p.router.util.CoDelBlockingQueue;
    911import net.i2p.data.DataHelper;
    1012import net.i2p.util.I2PThread;
     
    2729    private final Log _log;
    2830    private final UDPTransport _transport;
    29     private final UDPEndpoint _endpoint;
    3031    private final EstablishmentManager _establisher;
    3132    private final InboundMessageFragments _inbound;
     
    3536    private final Handler[] _handlers;
    3637    private final Map<RemoteHostId, Object> _failCache;
     38    private final BlockingQueue<UDPPacket> _inboundQueue;
    3739    private static final Object DUMMY = new Object();
    3840   
     41    private static final int TYPE_POISON = -99999;
     42    private static final int MIN_QUEUE_SIZE = 16;
     43    private static final int MAX_QUEUE_SIZE = 192;
    3944    private static final int MIN_NUM_HANDLERS = 1;  // unless < 32MB
    4045    private static final int MAX_NUM_HANDLERS = 1;
     
    4247    private static final long GRACE_PERIOD = Router.CLOCK_FUDGE_FACTOR + 30*1000;
    4348   
    44     PacketHandler(RouterContext ctx, UDPTransport transport, UDPEndpoint endpoint, EstablishmentManager establisher,
     49    PacketHandler(RouterContext ctx, UDPTransport transport, EstablishmentManager establisher,
    4550                  InboundMessageFragments inbound, PeerTestManager testManager, IntroductionManager introManager) {
    4651        _context = ctx;
    4752        _log = ctx.logManager().getLog(PacketHandler.class);
    4853        _transport = transport;
    49         _endpoint = endpoint;
    5054        _establisher = establisher;
    5155        _inbound = inbound;
     
    5761        if (maxMemory == Long.MAX_VALUE)
    5862            maxMemory = 96*1024*1024l;
     63        int qsize = (int) Math.max(MIN_QUEUE_SIZE, Math.min(MAX_QUEUE_SIZE, maxMemory / (2*1024*1024)));
     64        _inboundQueue = new CoDelBlockingQueue(ctx, "UDP-Receiver", qsize);
    5965        int num_handlers;
    6066        if (maxMemory < 32*1024*1024)
     
    108114    public synchronized void shutdown() {
    109115        _keepReading = false;
     116        stopQueue();
    110117    }
    111118
     
    120127    }
    121128
    122     /** @since 0.8.8 */
    123     int getHandlerCount() {
    124         return _handlers.length;
     129    /**
     130     * Blocking call to retrieve the next inbound packet, or null if we have
     131     * shut down.
     132     *
     133     * @since IPv6 moved from UDPReceiver
     134     */
     135    public void queueReceived(UDPPacket packet) throws InterruptedException {
     136        _inboundQueue.put(packet);
     137    }
     138
     139
     140    /**
     141     * Blocking for a while
     142     *
     143     * @since IPv6 moved from UDPReceiver
     144     */
     145    private void stopQueue() {
     146        _inboundQueue.clear();
     147        for (int i = 0; i < _handlers.length; i++) {
     148            UDPPacket poison = UDPPacket.acquire(_context, false);
     149            poison.setMessageType(TYPE_POISON);
     150            _inboundQueue.offer(poison);
     151        }
     152        for (int i = 1; i <= 5 && !_inboundQueue.isEmpty(); i++) {
     153            try {
     154                Thread.sleep(i * 50);
     155            } catch (InterruptedException ie) {}
     156        }
     157        _inboundQueue.clear();
     158    }
     159
     160    /**
     161     * Blocking call to retrieve the next inbound packet, or null if we have
     162     * shut down.
     163     *
     164     * @since IPv6 moved from UDPReceiver
     165     */
     166    public UDPPacket receiveNext() {
     167        UDPPacket rv = null;
     168        //int remaining = 0;
     169        while (_keepReading && rv == null) {
     170            try {
     171                rv = _inboundQueue.take();
     172            } catch (InterruptedException ie) {}
     173            if (rv != null && rv.getMessageType() == TYPE_POISON)
     174                return null;
     175        }
     176        //_context.statManager().addRateData("udp.receiveRemaining", remaining, 0);
     177        return rv;
    125178    }
    126179
     
    145198            while (_keepReading) {
    146199                _state = 2;
    147                 UDPPacket packet = _endpoint.receive();
     200                UDPPacket packet = receiveNext();
    148201                _state = 3;
    149202                if (packet == null) break; // keepReading is probably false, or bind failed...
  • router/java/src/net/i2p/router/transport/udp/PacketPusher.java

    rbddfe3ed r79f8e88  
    11package net.i2p.router.transport.udp;
     2
     3import java.util.List;
    24
    35import net.i2p.router.RouterContext;
     
    79/**
    810 * Blocking thread to grab new packets off the outbound fragment
    9  * pool and toss 'em onto the outbound packet queue
     11 * pool and toss 'em onto the outbound packet queues.
    1012 *
     13 * Here we select which UDPEndpoint/UDPSender to send it out.
    1114 */
    1215class PacketPusher implements Runnable {
     
    1417    private final Log _log;
    1518    private final OutboundMessageFragments _fragments;
    16     private final UDPSender _sender;
     19    private final List<UDPEndpoint> _endpoints;
    1720    private volatile boolean _alive;
    1821   
    19     public PacketPusher(RouterContext ctx, OutboundMessageFragments fragments, UDPSender sender) {
     22    public PacketPusher(RouterContext ctx, OutboundMessageFragments fragments, List<UDPEndpoint> endpoints) {
    2023        // _context = ctx;
    2124        _log = ctx.logManager().getLog(PacketPusher.class);
    2225        _fragments = fragments;
    23         _sender = sender;
     26        _endpoints = endpoints;
    2427    }
    2528   
     
    3942                    for (int i = 0; i < packets.length; i++) {
    4043                        if (packets[i] != null) // null for ACKed fragments
    41                             // BLOCKING if queue is full
    42                             _sender.add(packets[i]);
     44                            send(packets[i]);
    4345                    }
    4446                }
     
    4850        }
    4951    }
     52
     53    /**
     54     *  This sends it directly out, bypassing OutboundMessageFragments
     55     *  and the PacketPusher. The only queueing is for the bandwidth limiter.
     56     *  BLOCKING if OB queue is full.
     57     *
     58     *  @param packet non-null
     59     *  @since IPv6
     60     */
     61    public void send(UDPPacket packet) {
     62        boolean isIPv4 = packet.getPacket().getAddress().getAddress().length == 4;
     63        for (int j = 0; j < _endpoints.size(); j++) {
     64            // Find the best endpoint (socket) to send this out.
     65            // TODO if we have multiple IPv4, or multiple IPv6 endpoints,
     66            // we have to track which one we're using in the PeerState and
     67            // somehow set that in the UDPPacket so we're consistent
     68            UDPEndpoint ep;
     69            try {
     70                ep = _endpoints.get(j);
     71            } catch (IndexOutOfBoundsException ioobe) {
     72                // whups, list changed
     73                break;
     74            }
     75            if ((isIPv4 && ep.isIPv4()) ||
     76                ((!isIPv4) && ep.isIPv6())) {
     77                // BLOCKING if queue is full
     78                ep.getSender().add(packet);
     79                return;
     80            }
     81        }
     82        // not handled
     83        _log.error("No endpoint to send " + packet);
     84        packet.release();
     85    }
    5086}
  • router/java/src/net/i2p/router/transport/udp/PeerState.java

    rbddfe3ed r79f8e88  
    268268     */
    269269    public static final int MIN_MTU = 620;
     270
     271    /**
     272     * IPv6/UDP header is 48 bytes, so we want MTU % 16 == 0.
     273     */
     274    public static final int MIN_IPV6_MTU = 1280;
     275    public static final int MAX_IPV6_MTU = 1472;  // TODO 1488
    270276    private static final int DEFAULT_MTU = MIN_MTU;
    271277
     
    316322        _lastCongestionOccurred = -1;
    317323        _remotePort = remotePort;
    318         _mtu = DEFAULT_MTU;
    319         _mtuReceive = DEFAULT_MTU;
    320         _largeMTU = transport.getMTU();
     324        if (remoteIP.length == 4) {
     325            _mtu = DEFAULT_MTU;
     326            _mtuReceive = DEFAULT_MTU;
     327            _largeMTU = transport.getMTU(false);
     328        } else {
     329            _mtu = MIN_IPV6_MTU;
     330            _mtuReceive = MIN_IPV6_MTU;
     331            _largeMTU = transport.getMTU(true);
     332        }
    321333        //_mtuLastChecked = -1;
    322334        _lastACKSend = -1;
     
    687699    public int getConsecutiveSendRejections() { return _consecutiveRejections; }
    688700    public boolean isInbound() { return _isInbound; }
     701
     702    /** @since IPv6 */
     703    public boolean isIPv6() {
     704        return _remoteIP.length == 16;
     705    }
     706
    689707    public long getIntroducerTime() { return _lastIntroducerTime; }
    690708    public void setIntroducerTime() { _lastIntroducerTime = _context.clock().now(); }
     
    11461164                }
    11471165            } else if (!wantLarge && _mtu == _largeMTU) {
    1148                 _mtu = MIN_MTU;
     1166                _mtu = _remoteIP.length == 4 ? MIN_MTU : MIN_IPV6_MTU;
    11491167                _mtuDecreases++;
    11501168                _context.statManager().addRateData("udp.mtuDecrease", _mtuDecreases);
    11511169            }
    11521170        } else {
    1153             _mtu = DEFAULT_MTU;
     1171            _mtu = _remoteIP.length == 4 ? DEFAULT_MTU : MIN_IPV6_MTU;
    11541172        }
    11551173    }
     
    11591177     */
    11601178    public synchronized void setHisMTU(int mtu) {
    1161         if (mtu <= MIN_MTU || mtu >= _largeMTU)
     1179        if (mtu <= MIN_MTU || mtu >= _largeMTU ||
     1180            (_remoteIP.length == 16 && mtu <= MIN_IPV6_MTU))
    11621181            return;
    11631182        _largeMTU = mtu;
     
    12261245    private static final int OVERHEAD_SIZE = PacketBuilder.IP_HEADER_SIZE + PacketBuilder.UDP_HEADER_SIZE +
    12271246                                             UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
     1247    /** 80 */
     1248    private static final int IPV6_OVERHEAD_SIZE = PacketBuilder.IPV6_HEADER_SIZE + PacketBuilder.UDP_HEADER_SIZE +
     1249                                             UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE;
    12281250
    12291251    /**
     
    12321254    public void packetReceived(int size) {
    12331255        _packetsReceived++;
    1234         size += OVERHEAD_SIZE;
    1235         if (size <= MIN_MTU) {
     1256        int minMTU;
     1257        if (_remoteIP.length == 4) {
     1258            size += OVERHEAD_SIZE;
     1259            minMTU = MIN_MTU;
     1260        } else {
     1261            size += IPV6_OVERHEAD_SIZE;
     1262            minMTU = MIN_IPV6_MTU;
     1263        }
     1264        if (size <= minMTU) {
    12361265            _consecutiveSmall++;
    12371266            if (_consecutiveSmall >= MTU_RCV_DISPLAY_THRESHOLD)
    1238                 _mtuReceive = MIN_MTU;
     1267                _mtuReceive = minMTU;
    12391268        } else {
    12401269            _consecutiveSmall = 0;
     
    12901319        return Math.min(PacketBuilder.ABSOLUTE_MAX_ACKS * 4,
    12911320                _mtu
    1292                 - PacketBuilder.IP_HEADER_SIZE
     1321                - (_remoteIP.length == 4 ? PacketBuilder.IP_HEADER_SIZE : PacketBuilder.IPV6_HEADER_SIZE)
    12931322                - PacketBuilder.UDP_HEADER_SIZE
    12941323                - UDPPacket.IV_SIZE
     
    16311660    /**
    16321661     *  how much payload data can we shove in there?
    1633      *  @return MTU - 87, i.e. 533 or 1397
    1634      */
    1635     private static final int fragmentSize(int mtu) {
    1636         // 46 + 20 + 8 + 13 = 74 + 13 = 87
    1637         return mtu - (PacketBuilder.MIN_DATA_PACKET_OVERHEAD + MIN_ACK_SIZE);
     1662     *  @return MTU - 87, i.e. 533 or 1397 (IPv4), MTU - 107 (IPv6)
     1663     */
     1664    private int fragmentSize() {
     1665        // 46 + 20 + 8 + 13 = 74 + 13 = 87 (IPv4)
     1666        // 46 + 40 + 8 + 13 = 74 + 13 = 107 (IPv6)
     1667        return _mtu -
     1668               (_remoteIP.length == 4 ? PacketBuilder.MIN_DATA_PACKET_OVERHEAD : PacketBuilder.MIN_IPV6_DATA_PACKET_OVERHEAD) -
     1669               MIN_ACK_SIZE;
    16381670    }
    16391671   
     
    16481680        if (state.getNextSendTime() <= now) {
    16491681            if (!state.isFragmented()) {
    1650                 state.fragment(fragmentSize(_mtu));
     1682                state.fragment(fragmentSize());
    16511683                if (state.getMessage() != null)
    16521684                    state.getMessage().timestamp("fragment into " + state.getFragmentCount());
  • router/java/src/net/i2p/router/transport/udp/PeerTestManager.java

    rbddfe3ed r79f8e88  
    2424 *  Entry points are runTest() to start a new test as Alice,
    2525 *  and receiveTest() for all received test packets.
     26 *
     27 *  IPv6 info: All Alice-Bob and Alice-Charlie communication is via IPv4.
     28 *  The Bob-Charlie communication may be via IPv6, however Charlie must
     29 *  be IPv4-capable.
     30 *  The IP address (of Alice) in the message must be IPv4 if present,
     31 *  as we only support testing of IPv4.
     32 *  Testing of IPv6 could be added in the future.
    2633 *
    2734 *  From udp.html on the website:
     
    167174    /**
    168175     *  The next few methods are for when we are Alice
     176     *
     177     *  @param bobIP IPv4 only
    169178     */
    170179    public synchronized void runTest(InetAddress bobIP, int bobPort, SessionKey bobCipherKey, SessionKey bobMACKey) {
     
    174183            return;
    175184        }
    176         if (DataHelper.eq(bobIP.getAddress(), 0, _transport.getExternalIP(), 0, 2)) {
     185        if (_transport.isTooClose(bobIP.getAddress())) {
    177186            if (_log.shouldLog(Log.WARN))
    178187                _log.warn("Not running test with Bob too close to us " + bobIP);
     
    305314
    306315            int ipSize = testInfo.readIPSize();
    307             if (ipSize != 4 && ipSize != 16) {
     316            if (ipSize != 4) {
    308317                // There appears to be a bug where Bob is sending us a zero-length IP.
    309318                // We could proceed without setting the IP, but then when Charlie
     
    367376                    test.setAlicePortFromCharlie(testPort);
    368377                    byte ip[] = new byte[testInfo.readIPSize()];
     378                    if (ip.length != 4)
     379                        throw new UnknownHostException("not IPv4");
    369380                    testInfo.readIP(ip, 0);
    370381                    InetAddress addr = InetAddress.getByAddress(ip);
     
    486497        if (fromPort < 1024 || fromPort > 65535 ||
    487498            (!_transport.isValid(fromIP)) ||
    488             DataHelper.eq(fromIP, 0, _transport.getExternalIP(), 0, 2) ||
     499            _transport.isTooClose(fromIP) ||
    489500            _context.blocklist().isBlocklisted(fromIP)) {
    490501            // spoof check, and don't respond to privileged ports
     
    506517            (testIP != null &&
    507518                               ((!_transport.isValid(testIP)) ||
     519                                testIP.length != 4 ||
    508520                                _context.blocklist().isBlocklisted(testIP)))) {
    509521            // spoof check, and don't respond to privileged ports
     
    545557        PeerTestState state = _activeTests.get(lNonce);
    546558
    547         if (testIP != null && DataHelper.eq(testIP, 0, _transport.getExternalIP(), 0, 2)) {
     559        if (testIP != null && _transport.isTooClose(testIP)) {
    548560            // spoof check - have to do this after receiveTestReply(), since
    549561            // the field should be us there.
     
    642654        try {
    643655            testInfo.readIP(aliceIPData, 0);
     656            if (sz != 4)
     657                throw new UnknownHostException("not IPv4");
    644658            int alicePort = testInfo.readPort();
    645659            if (alicePort == 0)
     
    707721        RouterInfo charlieInfo = null;
    708722        if (state == null) { // pick a new charlie
    709             charlie = _transport.pickTestPeer(from);
     723            if (from.getIP().length != 4) {
     724                if (_log.shouldLog(Log.WARN))
     725                    _log.warn("PeerTest over IPv6 from Alice as Bob? " + from);
     726                return;
     727            }
     728            charlie = _transport.pickTestPeer(CHARLIE, from);
    710729        } else {
    711730            charlie = _transport.getPeerState(new RemoteHostId(state.getCharlieIP().getAddress(), state.getCharliePort()));
  • router/java/src/net/i2p/router/transport/udp/UDPAddress.java

    rbddfe3ed r79f8e88  
    33import java.net.InetAddress;
    44import java.net.UnknownHostException;
     5import java.util.Map;
    56
    67import net.i2p.data.Base64;
    78import net.i2p.data.RouterAddress;
    89import net.i2p.data.SessionKey;
     10import net.i2p.util.LHMCache;
    911
    1012/**
    1113 * basic helper to parse out peer info from a udp address
    12  * FIXME public for ConfigNetHelper
    1314 */
    14 public class UDPAddress {
     15class UDPAddress {
    1516    private final String _host;
    1617    private InetAddress _hostAddress;
     
    3839    public static final String PROP_INTRO_TAG_PREFIX = "itag";
    3940    static final int MAX_INTRODUCERS = 3;
     41    private static final String[] PROP_INTRO_HOST;
     42    private static final String[] PROP_INTRO_PORT;
     43    private static final String[] PROP_INTRO_IKEY;
     44    private static final String[] PROP_INTRO_TAG;
     45    static {
     46        // object churn
     47        PROP_INTRO_HOST = new String[MAX_INTRODUCERS];
     48        PROP_INTRO_PORT = new String[MAX_INTRODUCERS];
     49        PROP_INTRO_IKEY = new String[MAX_INTRODUCERS];
     50        PROP_INTRO_TAG = new String[MAX_INTRODUCERS];
     51        for (int i = 0; i < MAX_INTRODUCERS; i++) {
     52            PROP_INTRO_HOST[i] = PROP_INTRO_HOST_PREFIX + i;
     53            PROP_INTRO_PORT[i] = PROP_INTRO_PORT_PREFIX + i;
     54            PROP_INTRO_IKEY[i] = PROP_INTRO_KEY_PREFIX + i;
     55            PROP_INTRO_TAG[i] = PROP_INTRO_TAG_PREFIX + i;
     56        }
     57    }
    4058
    4159    public UDPAddress(RouterAddress addr) {
     
    5068        try {
    5169            String mtu = addr.getOption(PROP_MTU);
    52             if (mtu != null)
    53                 _mtu = MTU.rectify(Integer.parseInt(mtu));
     70            if (mtu != null) {
     71                boolean isIPv6 = _host != null && _host.contains(":");
     72                _mtu = MTU.rectify(isIPv6, Integer.parseInt(mtu));
     73            }
    5474        } catch (NumberFormatException nfe) {}
    5575        String key = addr.getOption(PROP_INTRO_KEY);
    56         if (key != null)
    57             _introKey = Base64.decode(key.trim());
     76        if (key != null) {
     77            byte[] ik = Base64.decode(key.trim());
     78            if (ik != null && ik.length == SessionKey.KEYSIZE_BYTES)
     79                _introKey = ik;
     80        }
    5881       
    59         for (int i = MAX_INTRODUCERS; i >= 0; i--) {
    60             String host = addr.getOption(PROP_INTRO_HOST_PREFIX + i);
     82        for (int i = MAX_INTRODUCERS - 1; i >= 0; i--) {
     83            String host = addr.getOption(PROP_INTRO_HOST[i]);
    6184            if (host == null) continue;
    62             String port = addr.getOption(PROP_INTRO_PORT_PREFIX + i);
     85            String port = addr.getOption(PROP_INTRO_PORT[i]);
    6386            if (port == null) continue;
    64             String k = addr.getOption(PROP_INTRO_KEY_PREFIX + i);
     87            String k = addr.getOption(PROP_INTRO_IKEY[i]);
    6588            if (k == null) continue;
    6689            byte ikey[] = Base64.decode(k);
    6790            if ( (ikey == null) || (ikey.length != SessionKey.KEYSIZE_BYTES) )
    6891                continue;
    69             String t = addr.getOption(PROP_INTRO_TAG_PREFIX + i);
     92            String t = addr.getOption(PROP_INTRO_TAG[i]);
    7093            if (t == null) continue;
    71             int p = -1;
     94            int p;
    7295            try {
    7396                p = Integer.parseInt(port);
    74                 if (p <= 0 || p > 65535) continue;
     97                if (p < UDPTransport.MIN_PEER_PORT || p > 65535) continue;
    7598            } catch (NumberFormatException nfe) {
    7699                continue;
    77100            }
    78             long tag = -1;
     101            long tag;
    79102            try {
    80103                tag = Long.parseLong(t);
     
    132155   
    133156    public String getHost() { return _host; }
     157
    134158    InetAddress getHostAddress() {
    135         if (_hostAddress == null) {
    136             try {
    137                 _hostAddress = InetAddress.getByName(_host);
    138             } catch (UnknownHostException uhe) {
    139                 _hostAddress = null;
    140             }
    141         }
     159        if (_hostAddress == null)
     160            _hostAddress = getByName(_host);
    142161        return _hostAddress;
    143162    }
     
    151170   
    152171    int getIntroducerCount() { return (_introAddresses == null ? 0 : _introAddresses.length); }
     172
    153173    InetAddress getIntroducerHost(int i) {
    154         if (_introAddresses[i] == null) {
    155             try {
    156                 _introAddresses[i] = InetAddress.getByName(_introHosts[i]);
    157             } catch (UnknownHostException uhe) {
    158                 _introAddresses[i] = null;
    159             }
    160         }
     174        if (_introAddresses[i] == null)
     175            _introAddresses[i] = getByName(_introHosts[i]);
    161176        return _introAddresses[i];
    162177    }
     178
    163179    int getIntroducerPort(int i) { return _introPorts[i]; }
     180
    164181    byte[] getIntroducerKey(int i) { return _introKeys[i]; }
     182
    165183    long getIntroducerTag(int i) { return _introTags[i]; }
    166184       
     
    193211        return rv.toString();
    194212    }
     213
     214    ////////////////
     215    // cache copied from Addresses.java but caching InetAddress instead of byte[]
     216
     217
     218    /**
     219     *  Textual IP to InetAddress, because InetAddress.getByName() is slow.
     220     *
     221     *  @since IPv6
     222     */
     223    private static final Map<String, InetAddress> _inetAddressCache;
     224
     225    static {
     226        long maxMemory = Runtime.getRuntime().maxMemory();
     227        if (maxMemory == Long.MAX_VALUE)
     228            maxMemory = 96*1024*1024l;
     229        long min = 128;
     230        long max = 2048;
     231        // 512 nominal for 128 MB
     232        int size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (256*1024))));
     233        _inetAddressCache = new LHMCache(size);
     234    }
     235
     236    /**
     237     *  Caching version of InetAddress.getByName(host), which is slow.
     238     *  Caches numeric host names only.
     239     *  Will resolve but not cache DNS host names.
     240     *
     241     *  Unlike InetAddress.getByName(), we do NOT allow numeric IPs
     242     *  of the form d.d.d, d.d, or d, as these are almost certainly mistakes.
     243     *
     244     *  @param host DNS or IPv4 or IPv6 host name; if null returns null
     245     *  @return InetAddress or null
     246     *  @since IPv6
     247     */
     248    private static InetAddress getByName(String host) {
     249        if (host == null)
     250            return null;
     251        InetAddress rv;
     252        synchronized (_inetAddressCache) {
     253            rv = _inetAddressCache.get(host);
     254        }
     255        if (rv == null) {
     256            try {
     257                boolean isIPv4 = host.replaceAll("[0-9\\.]", "").length() == 0;
     258                if (isIPv4 && host.replaceAll("[0-9]", "").length() != 3)
     259                    return null;
     260                rv = InetAddress.getByName(host);
     261                if (isIPv4 ||
     262                    host.replaceAll("[0-9a-fA-F:]", "").length() == 0) {
     263                    synchronized (_inetAddressCache) {
     264                        _inetAddressCache.put(host, rv);
     265                    }
     266                }
     267            } catch (UnknownHostException uhe) {}
     268        }
     269        return rv;
     270    }
     271
     272    /**
     273     *  @since IPv6
     274     */
     275    static void clearCache() {
     276        synchronized(_inetAddressCache) {
     277            _inetAddressCache.clear();
     278        }
     279    }
    195280}
  • router/java/src/net/i2p/router/transport/udp/UDPEndpoint.java

    rbddfe3ed r79f8e88  
    11package net.i2p.router.transport.udp;
    22
     3import java.io.IOException;
    34import java.net.DatagramSocket;
    45import java.net.InetAddress;
     6import java.net.Inet4Address;
     7import java.net.Inet6Address;
    58import java.net.SocketException;
     9import java.util.concurrent.atomic.AtomicInteger;
    610
    711import net.i2p.router.RouterContext;
     
    913
    1014/**
    11  * Coordinate the low level datagram socket, managing the UDPSender and
    12  * UDPReceiver
     15 * Coordinate the low-level datagram socket, creating and managing the UDPSender and
     16 * UDPReceiver.
    1317 */
    1418class UDPEndpoint {
     
    2125    private DatagramSocket _socket;
    2226    private final InetAddress _bindAddress;
    23    
    24     /**
     27    private final boolean _isIPv4, _isIPv6;
     28    private static final AtomicInteger _counter = new AtomicInteger();
     29   
     30    /**
     31     *  @param transport may be null for unit testing ONLY
    2532     *  @param listenPort -1 or the requested port, may not be honored
    2633     *  @param bindAddress null ok
     
    3239        _bindAddress = bindAddress;
    3340        _listenPort = listenPort;
     41        _isIPv4 = bindAddress == null || bindAddress instanceof Inet4Address;
     42        _isIPv6 = bindAddress == null || bindAddress instanceof Inet6Address;
    3443    }
    3544   
    3645    /** caller should call getListenPort() after this to get the actual bound port and determine success */
    37     public synchronized void startup() {
     46    public synchronized void startup() throws SocketException {
    3847        if (_log.shouldLog(Log.DEBUG))
    3948            _log.debug("Starting up the UDP endpoint");
     
    4251        if (_socket == null) {
    4352            _log.log(Log.CRIT, "UDP Unable to open a port");
    44             return;
    45         }
    46         _sender = new UDPSender(_context, _socket, "UDPSender");
    47         _receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver");
     53            throw new SocketException("SSU Unable to bind to a port on " + _bindAddress);
     54        }
     55        int count = _counter.incrementAndGet();
     56        _sender = new UDPSender(_context, _socket, "UDPSender " + count);
    4857        _sender.startup();
    49         _receiver.startup();
     58        if (_transport != null) {
     59            _receiver = new UDPReceiver(_context, _transport, _socket, "UDPReceiver " + count);
     60            _receiver.startup();
     61        }
    5062    }
    5163   
     
    104116                 // try random ports rather than just do new DatagramSocket()
    105117                 // so we stay out of the way of other I2P stuff
    106                  int minPort = _context.getProperty(PROP_MIN_PORT, MIN_RANDOM_PORT);
    107                  int maxPort = _context.getProperty(PROP_MAX_PORT, MAX_RANDOM_PORT);
    108                  port = minPort + _context.random().nextInt(maxPort - minPort);
     118                 port = selectRandomPort(_context);
    109119             }
    110120             try {
     
    132142    }
    133143
     144    /**
     145     *  Pick a random port between the configured boundaries
     146     *  @since IPv6
     147     */
     148    public static int selectRandomPort(RouterContext ctx) {
     149        int minPort = Math.min(65535, Math.max(1, ctx.getProperty(PROP_MIN_PORT, MIN_RANDOM_PORT)));
     150        int maxPort = Math.min(65535, Math.max(minPort, ctx.getProperty(PROP_MAX_PORT, MAX_RANDOM_PORT)));
     151        return minPort + ctx.random().nextInt(1 + maxPort - minPort);
     152    }
     153
     154
    134155    /** call after startup() to get actual port or -1 on startup failure */
    135156    public int getListenPort() { return _listenPort; }
     
    144165        _sender.add(packet);
    145166    }
    146    
     167     
    147168    /**
    148169     * Blocking call to receive the next inbound UDP packet from any peer.
    149      * @return null if we have shut down
     170     *
     171     * UNIT TESTING ONLY. Direct from the socket.
     172     * In normal operation, UDPReceiver thread injects to PacketHandler queue.
     173     *
     174     * @return null if we have shut down, or on failure
    150175     */
    151176    public UDPPacket receive() {
    152         if (_receiver == null)
     177        UDPPacket packet = UDPPacket.acquire(_context, true);
     178        try {
     179            _socket.receive(packet.getPacket());
     180            return packet;
     181        } catch (IOException ioe) {
     182            packet.release();
    153183            return null;
    154         return _receiver.receiveNext();
     184        }
    155185    }
    156186   
     
    163193            _sender.clear();
    164194    }
     195
     196    /**
     197     *  @return true for wildcard too
     198     *  @since IPv6
     199     */
     200    public boolean isIPv4() {
     201        return _isIPv4;
     202    }
     203
     204    /**
     205     *  @return true for wildcard too
     206     *  @since IPv6
     207     */
     208    public boolean isIPv6() {
     209        return _isIPv6;
     210    }
    165211}
  • router/java/src/net/i2p/router/transport/udp/UDPPacket.java

    rbddfe3ed r79f8e88  
    1111import net.i2p.data.SessionKey;
    1212import net.i2p.router.util.CDQEntry;
     13import net.i2p.util.Addresses;
    1314import net.i2p.util.Log;
    1415
     
    301302        buf.append(_packet.getLength());
    302303        buf.append(" byte pkt with ");
    303         buf.append(_packet.getAddress().getHostAddress()).append(":");
    304         buf.append(_packet.getPort());
     304        buf.append(Addresses.toString(_packet.getAddress().getAddress(), _packet.getPort()));
    305305        //buf.append(" id=").append(System.identityHashCode(this));
    306306        if (_messageType >= 0)
  • router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java

    rbddfe3ed r79f8e88  
    731731        }
    732732       
     733        /** @deprecated unused */
    733734        public int readAliceIPSize() {
    734735            int offset = readBodyOffset();
     
    738739            return (int)DataHelper.fromLong(_message, offset, 1);
    739740        }
     741        /** @deprecated unused */
    740742        public void readAliceIP(byte target[], int targetOffset) {
    741743            int offset = readBodyOffset();
     
    747749            System.arraycopy(_message, offset, target, targetOffset, sz);
    748750        }
     751        /** @deprecated unused */
    749752        public int readAlicePort() {
    750753            int offset = readBodyOffset();
  • router/java/src/net/i2p/router/transport/udp/UDPReceiver.java

    rbddfe3ed r79f8e88  
    44import java.net.DatagramSocket;
    55import java.util.Arrays;
    6 import java.util.concurrent.BlockingQueue;
    76
    87import net.i2p.router.RouterContext;
    98import net.i2p.router.transport.FIFOBandwidthLimiter;
    10 import net.i2p.router.util.CoDelBlockingQueue;
    119import net.i2p.util.I2PThread;
    1210import net.i2p.util.Log;
     
    2119 * from the queue ASAP by a {@link PacketHandler}
    2220 *
     21 * There is a UDPReceiver for each UDPEndpoint.
     22 * It contains a thread but no queue. Received packets are queued
     23 * in the common PacketHandler queue.
    2324 */
    2425class UDPReceiver {
     
    2728    private final DatagramSocket _socket;
    2829    private String _name;
    29     private final BlockingQueue<UDPPacket> _inboundQueue;
    3030    private volatile boolean _keepRunning;
    3131    private final Runner _runner;
    3232    private final UDPTransport _transport;
    33     private static int __id;
    34     private final int _id;
     33    private final PacketHandler _handler;
    3534
    3635    private static final boolean _isAndroid = SystemVersion.isAndroid();
    37 
    38     private static final int TYPE_POISON = -99999;
    39     private static final int MIN_QUEUE_SIZE = 16;
    40     private static final int MAX_QUEUE_SIZE = 192;
    4136
    4237    public UDPReceiver(RouterContext ctx, UDPTransport transport, DatagramSocket socket, String name) {
    4338        _context = ctx;
    4439        _log = ctx.logManager().getLog(UDPReceiver.class);
    45         _id = ++__id;
    4640        _name = name;
    47         long maxMemory = Runtime.getRuntime().maxMemory();
    48         if (maxMemory == Long.MAX_VALUE)
    49             maxMemory = 96*1024*1024l;
    50         int qsize = (int) Math.max(MIN_QUEUE_SIZE, Math.min(MAX_QUEUE_SIZE, maxMemory / (2*1024*1024)));
    51         _inboundQueue = new CoDelBlockingQueue(ctx, "UDP-Receiver", qsize);
    5241        _socket = socket;
    5342        _transport = transport;
     43        _handler = transport.getPacketHandler();
     44        if (_handler == null)
     45            throw new IllegalStateException();
    5446        _runner = new Runner();
    5547        //_context.statManager().createRateStat("udp.receivePacketSize", "How large packets received are", "udp", UDPTransport.RATES);
     
    6355        //adjustDropProbability();
    6456        _keepRunning = true;
    65         I2PThread t = new I2PThread(_runner, _name + '.' + _id, true);
     57        I2PThread t = new I2PThread(_runner, _name, true);
    6658        t.start();
    6759    }
     
    6961    public synchronized void shutdown() {
    7062        _keepRunning = false;
    71         _inboundQueue.clear();
    72         for (int i = 0; i < _transport.getPacketHandlerCount(); i++) {
    73             UDPPacket poison = UDPPacket.acquire(_context, false);
    74             poison.setMessageType(TYPE_POISON);
    75             _inboundQueue.offer(poison);
    76         }
    77         for (int i = 1; i <= 5 && !_inboundQueue.isEmpty(); i++) {
    78             try {
    79                 Thread.sleep(i * 50);
    80             } catch (InterruptedException ie) {}
    81         }
    82         _inboundQueue.clear();
    8363    }
    8464   
     
    172152
    173153        // drop anything apparently from our IP (any port)
    174         if (Arrays.equals(from.getIP(), _transport.getExternalIP())) {
     154        if (Arrays.equals(from.getIP(), _transport.getExternalIP()) && !_transport.allowLocal()) {
    175155            if (_log.shouldLog(Log.WARN))
    176156                _log.warn("Dropping (spoofed?) packet from ourselves");
     
    195175****/
    196176                try {
    197                     _inboundQueue.put(packet);
     177                    _handler.queueReceived(packet);
    198178                } catch (InterruptedException ie) {
    199179                    packet.release();
     
    230210  ****/
    231211   
    232     /**
    233      * Blocking call to retrieve the next inbound packet, or null if we have
    234      * shut down.
    235      *
    236      */
    237     public UDPPacket receiveNext() {
    238         UDPPacket rv = null;
    239         //int remaining = 0;
    240         while (_keepRunning && rv == null) {
    241             try {
    242                 rv = _inboundQueue.take();
    243             } catch (InterruptedException ie) {}
    244             if (rv != null && rv.getMessageType() == TYPE_POISON)
    245                 return null;
    246         }
    247         //_context.statManager().addRateData("udp.receiveRemaining", remaining, 0);
    248         return rv;
    249     }
    250212   
    251213    private class Runner implements Runnable {
     
    289251                        throw new IOException("packet too large! truncated and dropped from: " + packet.getRemoteHost());
    290252                    }
    291                     if (size > 0) {
     253                    if (_context.commSystem().isDummy()) {
     254                        // testing
     255                        packet.release();
     256                    } else if (size > 0) {
    292257                        //FIFOBandwidthLimiter.Request req = _context.bandwidthLimiter().requestInbound(size, "UDP receiver");
    293258                        //_context.bandwidthLimiter().requestInbound(req, size, "UDP receiver");
  • router/java/src/net/i2p/router/transport/udp/UDPSender.java

    rbddfe3ed r79f8e88  
    1515 * Lowest level packet sender, pushes anything on its queue ASAP.
    1616 *
     17 * There is a UDPSender for each UDPEndpoint.
     18 * It contains a thread and a queue. Packet to be sent are queued
     19 * by the PacketPusher.
    1720 */
    1821class UDPSender {
     
    2427    private volatile boolean _keepRunning;
    2528    private final Runner _runner;
     29    private final boolean _dummy;
     30
    2631    private static final int TYPE_POISON = 99999;
    27    
     32
    2833    private static final int MIN_QUEUE_SIZE = 64;
    2934    private static final int MAX_QUEUE_SIZE = 384;
     
    3136    public UDPSender(RouterContext ctx, DatagramSocket socket, String name) {
    3237        _context = ctx;
     38        _dummy = false; // ctx.commSystem().isDummy();
    3339        _log = ctx.logManager().getLog(UDPSender.class);
    3440        long maxMemory = Runtime.getRuntime().maxMemory();
     
    177183            return;
    178184        }
     185        if (_dummy) {
     186  &nb