Changeset 2c3311b


Ignore:
Timestamp:
Jun 25, 2016 9:25:12 PM (4 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
896af2c
Parents:
2506f6b
Message:

SSU: Add support for IPv6 SSU Peer Testing
(ticket #1752; proposal #126)
In PeerTestManager?, this is simply the removal of v6 restrictions,
and the tracking of whether we are testing v4 or v6.
In UDPTransport, track v4 and v6 peer tests separately.

Files:
5 edited

Legend:

Unmodified
Added
Removed
  • history.txt

    r2506f6b r2c3311b  
     12016-06-26 zzz
     2 * SSU peer testing: Add implementation (ticket #1752; proposal #126)
     3
    142016-06-22 zzz
    25 * SSU peer testing:
  • router/java/src/net/i2p/router/RouterVersion.java

    r2506f6b r2c3311b  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 2;
     21    public final static long BUILD = 3;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/transport/udp/PeerTestManager.java

    r2506f6b r2c3311b  
    22
    33import java.net.InetAddress;
     4import java.net.Inet6Address;
    45import java.net.UnknownHostException;
    56import java.util.Map;
     
    188189            return;
    189190        }
    190         PeerTestState test = new PeerTestState(ALICE,
     191        PeerTestState test = new PeerTestState(ALICE, bobIP instanceof Inet6Address,
    191192                                               _context.random().nextLong(MAX_NONCE),
    192193                                               _context.clock().now());
     
    316317
    317318            int ipSize = testInfo.readIPSize();
    318             if (ipSize != 4) {
     319            boolean expectV6 = test.isIPv6();
     320            if ((!expectV6 && ipSize != 4) ||
     321                (expectV6 && ipSize != 16)) {
    319322                // There appears to be a bug where Bob is sending us a zero-length IP.
    320323                // We could proceed without setting the IP, but then when Charlie
     
    365368                _currentTestComplete = true;
    366369                _context.statManager().addRateData("udp.statusKnownCharlie", 1);
    367                 honorStatus(Status.UNKNOWN);
     370                honorStatus(Status.UNKNOWN, test.isIPv6());
    368371                _currentTest = null;
    369372                return;
     
    378381                    test.setAlicePortFromCharlie(testPort);
    379382                    byte ip[] = new byte[testInfo.readIPSize()];
    380                     if (ip.length != 4)
    381                         throw new UnknownHostException("not IPv4");
     383                    int ipSize = ip.length;
     384                    boolean expectV6 = test.isIPv6();
     385                    if ((!expectV6 && ipSize != 4) ||
     386                        (expectV6 && ipSize != 16))
     387                        throw new UnknownHostException("bad sz - expect v6? " + expectV6 + " act sz: " + ipSize);
    382388                    testInfo.readIP(ip, 0);
    383389                    InetAddress addr = InetAddress.getByAddress(ip);
     
    443449        // }
    444450
     451        boolean isIPv6 = test.isIPv6();
    445452        Status status;
    446453        if (test.getAlicePortFromCharlie() > 0) {
     
    449456                 (test.getAliceIP() != null) && (test.getAliceIPFromCharlie() != null) &&
    450457                 (test.getAliceIP().equals(test.getAliceIPFromCharlie())) ) {
    451                 status = Status.IPV4_OK_IPV6_UNKNOWN;
     458                status = isIPv6 ? Status.IPV4_UNKNOWN_IPV6_OK : Status.IPV4_OK_IPV6_UNKNOWN;
    452459            } else {
    453                 status = Status.IPV4_SNAT_IPV6_UNKNOWN;
     460                // we don't have a SNAT state for IPv6
     461                status = isIPv6 ? Status.IPV4_UNKNOWN_IPV6_FIREWALLED : Status.IPV4_SNAT_IPV6_UNKNOWN;
    454462            }
    455463        } else if (test.getReceiveCharlieTime() > 0) {
     
    458466        } else if (test.getReceiveBobTime() > 0) {
    459467            // we received a message from bob but no messages from charlie
    460             status = Status.IPV4_FIREWALLED_IPV6_UNKNOWN;
     468            status = isIPv6 ? Status.IPV4_UNKNOWN_IPV6_FIREWALLED : Status.IPV4_FIREWALLED_IPV6_UNKNOWN;
    461469        } else {
    462470            // we never received anything from bob - he is either down,
     
    468476            _log.info("Test complete: " + test);
    469477       
    470         honorStatus(status);
     478        honorStatus(status, isIPv6);
    471479        if (forgetTest)
    472480            _currentTest = null;
     
    477485     * necessary).
    478486     *
    479      */
    480     private void honorStatus(Status status) {
     487     *  @param isIPv6 Is the change an IPv6 change?
     488     */
     489    private void honorStatus(Status status, boolean isIPv6) {
    481490        if (_log.shouldLog(Log.INFO))
    482             _log.info("Test results: status = " + status);
    483         _transport.setReachabilityStatus(status);
     491            _log.info("Test results (IPv6? " + isIPv6 + "): status = " + status);
     492        _transport.setReachabilityStatus(status, isIPv6);
    484493    }
    485494   
     
    519528            (testIP != null &&
    520529                               ((!_transport.isValid(testIP)) ||
    521                                 testIP.length != 4 ||
     530                                (testIP.length != 4 && testIP.length != 16) ||
    522531                                _context.blocklist().isBlocklisted(testIP)))) {
    523532            // spoof check, and don't respond to privileged ports
     
    646655    private void receiveFromBobAsCharlie(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo, long nonce, PeerTestState state) {
    647656        long now = _context.clock().now();
     657        int sz = testInfo.readIPSize();
    648658        boolean isNew = false;
    649659        if (state == null) {
    650660            isNew = true;
    651             state = new PeerTestState(CHARLIE, nonce, now);
     661            state = new PeerTestState(CHARLIE, sz == 16, nonce, now);
    652662        } else {
    653663            if (state.getReceiveBobTime() > now - (RESEND_TIMEOUT / 2)) {
     
    659669
    660670        // TODO should only do most of this if isNew
    661         int sz = testInfo.readIPSize();
    662671        byte aliceIPData[] = new byte[sz];
    663672        try {
    664673            testInfo.readIP(aliceIPData, 0);
    665             if (sz != 4)
    666                 throw new UnknownHostException("not IPv4");
     674            boolean expectV6 = state.isIPv6();
     675            if ((!expectV6 && sz != 4) ||
     676                (expectV6 && sz != 16))
     677                throw new UnknownHostException("bad sz - expect v6? " + expectV6 + " act sz: " + sz);
    667678            int alicePort = testInfo.readPort();
    668679            if (alicePort == 0)
     
    732743        PeerState charlie;
    733744        RouterInfo charlieInfo = null;
     745        int sz = from.getIP().length;
     746        boolean isIPv6 = sz == 16;
    734747        if (state == null) { // pick a new charlie
    735             if (from.getIP().length != 4) {
    736                 if (_log.shouldLog(Log.WARN))
    737                     _log.warn("PeerTest over IPv6 from Alice as Bob? " + from);
    738                 return;
    739             }
    740             charlie = _transport.pickTestPeer(CHARLIE, from);
     748            //if (from.getIP().length != 4) {
     749            //    if (_log.shouldLog(Log.WARN))
     750            //        _log.warn("PeerTest over IPv6 from Alice as Bob? " + from);
     751            //    return;
     752            //}
     753            charlie = _transport.pickTestPeer(CHARLIE, isIPv6, from);
    741754        } else {
    742755            charlie = _transport.getPeerState(new RemoteHostId(state.getCharlieIP().getAddress(), state.getCharliePort()));
    743756        }
    744         if (charlie != null)
    745             charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer());
    746        
    747         if ( (charlie == null) || (charlieInfo == null) ) {
    748             if (_log.shouldLog(Log.WARN))
    749                 _log.warn("Unable to pick a charlie");
     757        if (charlie == null) {
     758            if (_log.shouldLog(Log.WARN))
     759                _log.warn("Unable to pick a charlie (no peer), IPv6? " + isIPv6);
     760            return;
     761        }
     762        charlieInfo = _context.netDb().lookupRouterInfoLocally(charlie.getRemotePeer());
     763        if (charlieInfo == null) {
     764            if (_log.shouldLog(Log.WARN))
     765                _log.warn("Unable to pick a charlie (no RI), IPv6? " + isIPv6);
    750766            return;
    751767        }
     
    762778            if (raddr == null) {
    763779                if (_log.shouldLog(Log.WARN))
    764                     _log.warn("Unable to pick a charlie");
     780                    _log.warn("Unable to pick a charlie (no addr), IPv6? " + isIPv6);
    765781                return;
    766782            }
     
    769785            if (ikey == null) {
    770786                if (_log.shouldLog(Log.WARN))
    771                     _log.warn("Unable to pick a charlie");
     787                    _log.warn("Unable to pick a charlie (no ikey), IPv6? " + isIPv6);
    772788                return;
    773789            }
     
    781797            if (state == null) {
    782798                isNew = true;
    783                 state = new PeerTestState(BOB, nonce, now);
     799                state = new PeerTestState(BOB, isIPv6, nonce, now);
    784800            } else {
    785801                if (state.getReceiveAliceTime() > now - (RESEND_TIMEOUT / 2)) {
  • router/java/src/net/i2p/router/transport/udp/PeerTestState.java

    r2506f6b r2c3311b  
    1313    private final long _testNonce;
    1414    private final Role _ourRole;
     15    private final boolean _isIPv6;
    1516    private InetAddress _aliceIP;
    1617    private int _alicePort;
     
    3435    public enum Role {ALICE, BOB, CHARLIE};
    3536   
    36     public PeerTestState(Role role, long nonce, long now) {
     37    public PeerTestState(Role role, boolean isIPv6, long nonce, long now) {
    3738        _ourRole = role;
     39        _isIPv6 = isIPv6;
    3840        _testNonce = nonce;
    3941        _beginTime = now;
     
    4446    /** Are we Alice, bob, or Charlie. */
    4547    public Role getOurRole() { return _ourRole; }
     48
     49    /**
     50     * Is this an IPv6 test?
     51     * @since 0.9.27
     52     */
     53    public boolean isIPv6() { return _isIPv6; }
    4654
    4755    /**
  • router/java/src/net/i2p/router/transport/udp/UDPTransport.java

    r2506f6b r2c3311b  
    9696     *  TODO periodically update via CSFI.NetMonitor?
    9797     */
    98     private boolean _haveIPv6Address;
     98    private volatile boolean _haveIPv6Address;
    9999    private long _lastInboundIPv6;
    100100   
     
    219219     */
    220220    private static final String MIN_SIGTYPE_VERSION = "0.9.17";
     221
     222    /**
     223     *  IPv6 Peer Testing supported
     224     */
     225///////////////////////////////////// Testing only, set to 0.9.27 before release ////////////////////////////////////////
     226    private static final String MIN_V6_PEER_TEST_VERSION = "0.9.26";
    221227
    222228
     
    536542                    // a v6 address after it's removed.
    537543                    _lastInboundIPv6 = _context.clock().now();
    538                     setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK);
     544                    if (!isIPv6Firewalled())
     545                        setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true);
    539546                } else {
    540547                    if (!isIPv4Firewalled())
     
    547554                if (ia.getAddress().length == 16) {
    548555                    _lastInboundIPv6 = _context.clock().now();
    549                     setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK);
     556                    if (!isIPv6Firewalled())
     557                        setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true);
    550558                } else {
    551559                    if (!isIPv4Firewalled())
     
    764772    void inboundConnectionReceived(boolean isIPv6) {
    765773        if (isIPv6) {
    766             // FIXME we need to check and time out after an hour of no inbound ipv6,
    767             // change to firewalled maybe? but we don't have any test to restore
    768             // a v6 address after it's removed.
    769774            _lastInboundIPv6 = _context.clock().now();
    770             if (_currentOurV6Address != null)
    771                 setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK);
     775            // former workaround for lack of IPv6 peer testing
     776            //if (_currentOurV6Address != null)
     777            //    setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true);
    772778        } else {
    773779            // Introduced connections are still inbound, this is not evidence
     
    846852                // TODO should we set both to unknown and wait for an inbound v6 conn,
    847853                // since there's no v6 testing?
    848                 setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK);
     854                if (!isIPv6Firewalled())
     855                    setReachabilityStatus(Status.IPV4_UNKNOWN_IPV6_OK, true);
    849856            }
    850857        }
     
    10081015
    10091016        if (fireTest) {
     1017            // always false, commented out above
    10101018            _context.statManager().addRateData("udp.addressTestInsteadOfUpdate", 1);
    1011             _testEvent.forceRunImmediately();
     1019            _testEvent.forceRunImmediately(isIPv6);
    10121020        } else if (updated) {
    10131021            _context.statManager().addRateData("udp.addressUpdated", 1);
     
    10621070            // deadlock thru here ticket #1699
    10631071            _context.router().rebuildRouterInfo();
    1064             _testEvent.forceRunImmediately();
     1072            _testEvent.forceRunImmediately(isIPv6);
    10651073        }
    10661074        return updated;
     
    13301338                status != Status.DISCONNECTED &&
    13311339                _reachabilityStatusUnchanged < 7) {
    1332                 _testEvent.forceRunSoon();
     1340                // IPv4 only for now
     1341                _testEvent.forceRunSoon(false);
    13331342            }
    13341343        }
     
    30773086    }
    30783087   
    3079     void setReachabilityStatus(Status status) {
     3088    /**
     3089     *  IPv4 only
     3090     */
     3091    private void setReachabilityStatus(Status status) {
     3092        setReachabilityStatus(status, false);
     3093    }
     3094   
     3095    /**
     3096     *  @since 0.9.27
     3097     *  @param isIPv6 Is the change an IPv6 change?
     3098     */
     3099    void setReachabilityStatus(Status status, boolean isIPv6) {
    30803100        synchronized (_rebuildLock) {
    3081             locked_setReachabilityStatus(status);
    3082         }
    3083     }
    3084 
    3085     private void locked_setReachabilityStatus(Status newStatus) {
     3101            locked_setReachabilityStatus(status, isIPv6);
     3102        }
     3103    }
     3104
     3105    /**
     3106     *  @param isIPv6 Is the change an IPv6 change?
     3107     */
     3108    private void locked_setReachabilityStatus(Status newStatus, boolean isIPv6) {
    30863109        Status old = _reachabilityStatus;
    30873110        // merge new status into old
    30883111        Status status = Status.merge(old, newStatus);
    3089         _testEvent.setLastTested();
     3112        _testEvent.setLastTested(isIPv6);
    30903113        // now modify if we are IPv6 only
    30913114        TransportUtil.IPv6Config config = getIPv6Config();
     
    31003123        if (status != Status.UNKNOWN) {
    31013124            // now modify if we have no IPv6 address
    3102             if (_currentOurV6Address == null) {
     3125            if (_currentOurV6Address == null && !_haveIPv6Address) {
    31033126                if (status == Status.IPV4_OK_IPV6_UNKNOWN)
    31043127                    status = Status.OK;
     
    31763199     *  Pick a Bob (if we are Alice) or a Charlie (if we are Bob).
    31773200     *
    3178      *  For Bob (as called from PeerTestEvent below), returns an established IPv4 peer.
     3201     *  For Bob (as called from PeerTestEvent below), returns an established IPv4/v6 peer.
    31793202     *  While the protocol allows Alice to select an unestablished Bob, we don't support that.
    31803203     *
     
    31833206     *
    31843207     *  Any returned peer must advertise an IPv4 address to prove it is IPv4-capable.
    3185      *
    3186      *  @param peerRole BOB or CHARLIE only
     3208     *  Ditto for v6.
     3209     *
     3210     *  @param peerRole The role of the peer we are looking for, BOB or CHARLIE only (NOT our role)
     3211     *  @param isIPv6 true to get a v6-capable peer back
    31873212     *  @param dontInclude may be null
    31883213     *  @return IPv4 peer or null
    31893214     */
    3190     PeerState pickTestPeer(PeerTestState.Role peerRole, RemoteHostId dontInclude) {
     3215    PeerState pickTestPeer(PeerTestState.Role peerRole, boolean isIPv6, RemoteHostId dontInclude) {
    31913216        if (peerRole == ALICE)
    31923217            throw new IllegalArgumentException();
     
    31963221            if ( (dontInclude != null) && (dontInclude.equals(peer.getRemoteHostId())) )
    31973222                continue;
    3198             // enforce IPv4 connection if we are ALICE looking for a BOB
     3223            // enforce IPv4/v6 connection if we are ALICE looking for a BOB
    31993224            byte[] ip = peer.getRemoteIP();
    3200             if (peerRole == BOB && ip.length != 4)
     3225            if (peerRole == BOB) {
     3226                if ((!isIPv6 && ip.length != 4) ||
     3227                    (isIPv6 && ip.length != 16))
    32013228                continue;
    3202             // enforce IPv4 advertised for all
     3229            }
     3230            // enforce IPv4/v6 advertised for all
    32033231            RouterInfo peerInfo = _context.netDb().lookupRouterInfoLocally(peer.getRemotePeer());
    32043232            if (peerInfo == null)
    32053233                continue;
     3234            if (isIPv6) {
     3235                String v = peerInfo.getVersion();
     3236                if (VersionComparator.comp(v, MIN_SIGTYPE_VERSION) < 0)
     3237                    continue;
     3238            }
    32063239            ip = null;
    32073240            List<RouterAddress> addrs = getTargetAddresses(peerInfo);
    32083241            for (RouterAddress addr : addrs) {
    32093242                ip = addr.getIP();
    3210                 if (ip != null && ip.length == 4)
     3243                if (ip != null) {
     3244                    if ((!isIPv6 && ip.length != 4) ||
     3245                        (isIPv6 && ip.length != 16))
    32113246                    break;
     3247                }
    32123248            }
    32133249            if (ip == null)
     
    32223258    private boolean shouldTest() {
    32233259        return ! (_context.router().isHidden() ||
    3224                   isIPv4Firewalled());
     3260                  (isIPv4Firewalled() && isIPv6Firewalled()));
    32253261        //String val = _context.getProperty(PROP_SHOULD_TEST);
    32263262        //return ( (val != null) && ("true".equals(val)) );
     
    32343270        /** when did we last test our reachability */
    32353271        private final AtomicLong _lastTested = new AtomicLong();
    3236         private boolean _forceRun;
     3272        private final AtomicLong _lastTestedV6 = new AtomicLong();
     3273        private static final int NO_FORCE = 0, FORCE_IPV4 = 1, FORCE_IPV6 = 2;
     3274        private int _forceRun;
    32373275
    32383276        PeerTestEvent() {
     
    32413279       
    32423280        public synchronized void timeReached() {
     3281            // just for IPv6 for now
    32433282            if (shouldTest()) {
    3244                 long sinceRun = _context.clock().now() - _lastTested.get();
    3245                 if ( (_forceRun && sinceRun >= MIN_TEST_FREQUENCY) || (sinceRun >= TEST_FREQUENCY) ) {
    3246                     locked_runTest();
     3283                long now = _context.clock().now();
     3284                long sinceRunV4 = now - _lastTested.get();
     3285                long sinceRunV6 = now - _lastTestedV6.get();
     3286                if (_forceRun == FORCE_IPV4 && sinceRunV4 >= MIN_TEST_FREQUENCY) {
     3287                    locked_runTest(false);
     3288                } else if (_haveIPv6Address &&_forceRun == FORCE_IPV6 && sinceRunV6 >= MIN_TEST_FREQUENCY) {
     3289                    locked_runTest(true);
     3290                } else if (sinceRunV4 >= TEST_FREQUENCY) {
     3291                    locked_runTest(false);
     3292                } else if (_haveIPv6Address && sinceRunV6 >= TEST_FREQUENCY) {
     3293                    locked_runTest(true);
     3294                } else {
     3295                    if (_log.shouldLog(Log.INFO))
     3296                        _log.info("PTE timeReached(), no test run, last v4 test: " + new java.util.Date(_lastTested.get()) +
     3297                                  " last v6 test: " + new java.util.Date(_lastTestedV6.get()));
    32473298                }
    32483299            }
    32493300            if (_alive) {
    32503301                long delay = (TEST_FREQUENCY / 2) + _context.random().nextInt(TEST_FREQUENCY);
     3302                // if we have 2 addresses, give IPv6 a chance also
     3303                if (_haveIPv6Address)
     3304                    delay /= 2;
    32513305                schedule(delay);
    32523306            }
    32533307        }
    32543308       
    3255         private void locked_runTest() {
    3256             PeerState bob = pickTestPeer(BOB, null);
     3309        private void locked_runTest(boolean isIPv6) {
     3310            PeerState bob = pickTestPeer(BOB, isIPv6, null);
    32573311            if (bob != null) {
    32583312                if (_log.shouldLog(Log.INFO))
    32593313                    _log.info("Running periodic test with bob = " + bob);
    32603314                _testManager.runTest(bob.getRemoteIPAddress(), bob.getRemotePort(), bob.getCurrentCipherKey(), bob.getCurrentMACKey());
    3261                 setLastTested();
     3315                setLastTested(isIPv6);
    32623316            } else {
    32633317                if (_log.shouldLog(Log.WARN))
    3264                     _log.warn("Unable to run a periodic test, as there are no peers with the capacity required");
    3265             }
    3266             _forceRun = false;
     3318                    _log.warn("Unable to run peer test, no peers available - v6? " + isIPv6);
     3319            }
     3320            _forceRun = NO_FORCE;
    32673321        }
    32683322       
     
    32713325         *  @since 0.9.13
    32723326         */
    3273         public synchronized void forceRunSoon() {
    3274             if (isIPv4Firewalled())
     3327        public synchronized void forceRunSoon(boolean isIPv6) {
     3328            if (!isIPv6 && isIPv4Firewalled())
    32753329                return;
    3276             _forceRun = true;
     3330            if (isIPv6 && isIPv6Firewalled())
     3331                return;
     3332            _forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4;
    32773333            reschedule(MIN_TEST_FREQUENCY);
    32783334        }
     
    32833339         *  @since 0.9.13
    32843340         */
    3285         public synchronized void forceRunImmediately() {
    3286             if (isIPv4Firewalled())
     3341        public synchronized void forceRunImmediately(boolean isIPv6) {
     3342            if (!isIPv6 && isIPv4Firewalled())
    32873343                return;
    3288             _lastTested.set(0);
    3289             _forceRun = true;
     3344            if (isIPv6 && isIPv6Firewalled())
     3345                return;
     3346            if (isIPv6)
     3347                _lastTestedV6.set(0);
     3348            else
     3349                _lastTested.set(0);
     3350            _forceRun = isIPv6 ? FORCE_IPV6 : FORCE_IPV4;
    32903351            reschedule(5*1000);
    32913352        }
     
    33053366         *  @since 0.9.13
    33063367         */
    3307         public void setLastTested() {
     3368        public void setLastTested(boolean isIPv6) {
    33083369            // do not synchronize - deadlock with PeerTestManager
    3309             _lastTested.set(_context.clock().now());
     3370            long now = _context.clock().now();
     3371            if (isIPv6)
     3372                _lastTestedV6.set(now);
     3373            else
     3374                _lastTested.set(now);
     3375            if (_log.shouldLog(Log.DEBUG))
     3376                _log.debug("PTE.setLastTested() - v6? " + isIPv6, new Exception());
    33103377        }
    33113378       
Note: See TracChangeset for help on using the changeset viewer.