SSU: Fix IPv6 addresses not being removed on some state transitions

Ensure IPv4/v6 peer tests are alternated
Reschedule peer test if result is UNKNOWN and a state transition is pending
Fix peer test last send time not being set in all cases
This commit is contained in:
zzz
2021-03-15 07:37:08 -04:00
parent 47283e6ef7
commit be863d643e
3 changed files with 29 additions and 14 deletions

View File

@ -8,7 +8,7 @@ import net.i2p.util.SimpleTimer2;
import static net.i2p.router.transport.TransportUtil.IPv6Config.*; import static net.i2p.router.transport.TransportUtil.IPv6Config.*;
import static net.i2p.router.transport.udp.PeerTestState.Role.*; import static net.i2p.router.transport.udp.PeerTestState.Role.*;
/** /**
* Initiate a test (we are Alice) * Initiate a test (we are Alice)
* *
@ -26,6 +26,7 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
private final AtomicLong _lastTestedV6 = new AtomicLong(); private final AtomicLong _lastTestedV6 = new AtomicLong();
private static final int NO_FORCE = 0, FORCE_IPV4 = 1, FORCE_IPV6 = 2; private static final int NO_FORCE = 0, FORCE_IPV4 = 1, FORCE_IPV6 = 2;
private int _forceRun; private int _forceRun;
private boolean _lastTestIPv6 = true;
private static final int TEST_FREQUENCY = 13*60*1000; private static final int TEST_FREQUENCY = 13*60*1000;
private static final int MIN_TEST_FREQUENCY = 45*1000; private static final int MIN_TEST_FREQUENCY = 45*1000;
@ -37,7 +38,7 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
_transport = udp; _transport = udp;
_testManager = ptmgr; _testManager = ptmgr;
} }
public synchronized void timeReached() { public synchronized void timeReached() {
if (shouldTest()) { if (shouldTest()) {
long now = _context.clock().now(); long now = _context.clock().now();
@ -45,14 +46,17 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
long sinceRunV6 = now - _lastTestedV6.get(); long sinceRunV6 = now - _lastTestedV6.get();
boolean configV4fw = _transport.isIPv4Firewalled(); boolean configV4fw = _transport.isIPv4Firewalled();
boolean configV6fw = _transport.isIPv6Firewalled(); boolean configV6fw = _transport.isIPv6Firewalled();
boolean preferV4 = _lastTestIPv6;
if (!configV4fw && _forceRun == FORCE_IPV4 && sinceRunV4 >= MIN_TEST_FREQUENCY) { if (!configV4fw && _forceRun == FORCE_IPV4 && sinceRunV4 >= MIN_TEST_FREQUENCY) {
locked_runTest(false); locked_runTest(false);
} else if (!configV6fw && _forceRun == FORCE_IPV6 && _transport.hasIPv6Address() && sinceRunV6 >= MIN_TEST_FREQUENCY) { } else if (!configV6fw && _forceRun == FORCE_IPV6 && _transport.hasIPv6Address() && sinceRunV6 >= MIN_TEST_FREQUENCY) {
locked_runTest(true); locked_runTest(true);
} else if (!configV4fw && sinceRunV4 >= TEST_FREQUENCY && _transport.getIPv6Config() != IPV6_ONLY) { } else if (preferV4 && !configV4fw && sinceRunV4 >= TEST_FREQUENCY && _transport.getIPv6Config() != IPV6_ONLY) {
locked_runTest(false); locked_runTest(false);
} else if (!configV6fw && _transport.hasIPv6Address() && sinceRunV6 >= TEST_FREQUENCY) { } else if (!configV6fw && _transport.hasIPv6Address() && sinceRunV6 >= TEST_FREQUENCY) {
locked_runTest(true); locked_runTest(true);
} else if (!preferV4 && !configV4fw && sinceRunV4 >= TEST_FREQUENCY && _transport.getIPv6Config() != IPV6_ONLY) {
locked_runTest(false);
} else { } else {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("PTE timeReached(), no test run, last v4 test: " + new java.util.Date(_lastTested.get()) + _log.info("PTE timeReached(), no test run, last v4 test: " + new java.util.Date(_lastTested.get()) +
@ -72,8 +76,9 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
schedule(delay); schedule(delay);
} }
} }
private void locked_runTest(boolean isIPv6) { private void locked_runTest(boolean isIPv6) {
_lastTestIPv6 = isIPv6;
PeerState bob = _transport.pickTestPeer(BOB, isIPv6, null); PeerState bob = _transport.pickTestPeer(BOB, isIPv6, null);
if (bob != null) { if (bob != null) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
@ -88,7 +93,7 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
// so we don't get stuck running the same test over and over // so we don't get stuck running the same test over and over
_forceRun = NO_FORCE; _forceRun = NO_FORCE;
} }
/** /**
* Run within the next 45 seconds at the latest * Run within the next 45 seconds at the latest
* @since 0.9.13 * @since 0.9.13
@ -96,7 +101,7 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
public synchronized void forceRunSoon(boolean isIPv6) { public synchronized void forceRunSoon(boolean isIPv6) {
forceRunSoon(isIPv6, MIN_TEST_FREQUENCY); forceRunSoon(isIPv6, MIN_TEST_FREQUENCY);
} }
/** /**
* Run within the specified time at the latest * Run within the specified time at the latest
* @since 0.9.39 * @since 0.9.39
@ -113,7 +118,7 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
_log.debug("reschedule for " + net.i2p.data.DataHelper.formatDuration(delay)); _log.debug("reschedule for " + net.i2p.data.DataHelper.formatDuration(delay));
reschedule(delay); reschedule(delay);
} }
/** /**
* *
* Run within the next 5 seconds at the latest * Run within the next 5 seconds at the latest
@ -122,7 +127,7 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
public synchronized void forceRunImmediately(boolean isIPv6) { public synchronized void forceRunImmediately(boolean isIPv6) {
forceRunSoon(isIPv6, 5*1000); forceRunSoon(isIPv6, 5*1000);
} }
public synchronized void setIsAlive(boolean isAlive) { public synchronized void setIsAlive(boolean isAlive) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("PTE.setIsAlive(), isAlive? " + isAlive, new Exception()); _log.debug("PTE.setIsAlive(), isAlive? " + isAlive, new Exception());
@ -151,7 +156,7 @@ class PeerTestEvent extends SimpleTimer2.TimedEvent {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("PTE.setLastTested() - v6? " + isIPv6, new Exception()); _log.debug("PTE.setLastTested() - v6? " + isIPv6, new Exception());
} }
private boolean shouldTest() { private boolean shouldTest() {
return ! (_context.router().isHidden() || return ! (_context.router().isHidden() ||
(_transport.isIPv4Firewalled() && _transport.isIPv6Firewalled())); (_transport.isIPv4Firewalled() && _transport.isIPv6Firewalled()));

View File

@ -195,7 +195,6 @@ class PeerTestManager {
test.setBobPort(bobPort); test.setBobPort(bobPort);
test.setBobCipherKey(bobCipherKey); test.setBobCipherKey(bobCipherKey);
test.setBobMACKey(bobMACKey); test.setBobMACKey(bobMACKey);
test.setLastSendTime(test.getBeginTime());
_currentTest = test; _currentTest = test;
_currentTestComplete = false; _currentTestComplete = false;
@ -268,6 +267,7 @@ class PeerTestManager {
if (!expired()) { if (!expired()) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending test to Bob: " + test); _log.debug("Sending test to Bob: " + test);
test.setLastSendTime(_context.clock().now());
_transport.send(_packetBuilder.buildPeerTestFromAlice(test.getBobIP(), test.getBobPort(), _transport.send(_packetBuilder.buildPeerTestFromAlice(test.getBobIP(), test.getBobPort(),
test.getBobCipherKey(), test.getBobMACKey(), //_bobIntroKey, test.getBobCipherKey(), test.getBobMACKey(), //_bobIntroKey,
test.getNonce(), _transport.getIntroKey())); test.getNonce(), _transport.getIntroKey()));
@ -282,6 +282,7 @@ class PeerTestManager {
if (!expired()) { if (!expired()) {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Sending test to Charlie: " + test); _log.debug("Sending test to Charlie: " + test);
test.setLastSendTime(_context.clock().now());
_transport.send(_packetBuilder.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(), _transport.send(_packetBuilder.buildPeerTestFromAlice(test.getCharlieIP(), test.getCharliePort(),
test.getCharlieIntroKey(), test.getCharlieIntroKey(),
test.getNonce(), _transport.getIntroKey())); test.getNonce(), _transport.getIntroKey()));
@ -688,7 +689,6 @@ class PeerTestManager {
state.setAliceIntroKey(aliceIntroKey); state.setAliceIntroKey(aliceIntroKey);
state.setBobIP(bobIP); state.setBobIP(bobIP);
state.setBobPort(from.getPort()); state.setBobPort(from.getPort());
state.setLastSendTime(now);
state.setReceiveBobTime(now); state.setReceiveBobTime(now);
PeerState bob = _transport.getPeerState(from); PeerState bob = _transport.getPeerState(from);
@ -716,6 +716,7 @@ class PeerTestManager {
_context.simpleTimer2().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME); _context.simpleTimer2().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME);
} }
state.setLastSendTime(now);
UDPPacket packet = _packetBuilder.buildPeerTestToBob(bobIP, from.getPort(), aliceIP, alicePort, UDPPacket packet = _packetBuilder.buildPeerTestToBob(bobIP, from.getPort(), aliceIP, alicePort,
aliceIntroKey, nonce, aliceIntroKey, nonce,
state.getBobCipherKey(), state.getBobMACKey()); state.getBobCipherKey(), state.getBobMACKey());
@ -810,7 +811,6 @@ class PeerTestManager {
state.setCharlieIP(charlie.getRemoteIPAddress()); state.setCharlieIP(charlie.getRemoteIPAddress());
state.setCharliePort(charlie.getRemotePort()); state.setCharliePort(charlie.getRemotePort());
state.setCharlieIntroKey(charlieIntroKey); state.setCharlieIntroKey(charlieIntroKey);
state.setLastSendTime(now);
state.setReceiveAliceTime(now); state.setReceiveAliceTime(now);
if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_BOB) { if (state.incrementPacketsRelayed() > MAX_RELAYED_PER_TEST_BOB) {
@ -824,6 +824,7 @@ class PeerTestManager {
_context.simpleTimer2().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME); _context.simpleTimer2().addEvent(new RemoveTest(nonce), MAX_CHARLIE_LIFETIME);
} }
state.setLastSendTime(now);
UDPPacket packet = _packetBuilder.buildPeerTestToCharlie(aliceIP, from.getPort(), aliceIntroKey, nonce, UDPPacket packet = _packetBuilder.buildPeerTestToCharlie(aliceIP, from.getPort(), aliceIntroKey, nonce,
charlie.getRemoteIPAddress(), charlie.getRemoteIPAddress(),
charlie.getRemotePort(), charlie.getRemotePort(),
@ -862,6 +863,7 @@ class PeerTestManager {
return; return;
} }
state.setReceiveCharlieTime(now); state.setReceiveCharlieTime(now);
state.setLastSendTime(now);
UDPPacket packet = _packetBuilder.buildPeerTestToAlice(state.getAliceIP(), state.getAlicePort(), UDPPacket packet = _packetBuilder.buildPeerTestToAlice(state.getAliceIP(), state.getAlicePort(),
state.getAliceIntroKey(), state.getCharlieIntroKey(), state.getAliceIntroKey(), state.getCharlieIntroKey(),
@ -894,6 +896,7 @@ class PeerTestManager {
return; return;
} }
state.setReceiveAliceTime(now); state.setReceiveAliceTime(now);
state.setLastSendTime(now);
try { try {
InetAddress aliceIP = InetAddress.getByAddress(from.getIP()); InetAddress aliceIP = InetAddress.getByAddress(from.getIP());

View File

@ -3353,9 +3353,9 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
// as rebuildExternalAddress() calls replaceAddress() which calls CSFI.notifyReplaceAddress() // as rebuildExternalAddress() calls replaceAddress() which calls CSFI.notifyReplaceAddress()
// which will start up NTCP inbound when we transition to OK. // which will start up NTCP inbound when we transition to OK.
if (isIPv6) { if (isIPv6) {
if (STATUS_IPV6_FW.contains(status)) { if (STATUS_IPV6_FW_2.contains(status)) {
removeExternalAddress(true, true); removeExternalAddress(true, true);
} else if (STATUS_IPV6_FW.contains(old) && } else if (STATUS_IPV6_FW_2.contains(old) &&
STATUS_IPV6_OK.contains(status) && STATUS_IPV6_OK.contains(status) &&
_lastOurIPv6 != null && _lastOurIPv6 != null &&
!explicitAddressSpecified()){ !explicitAddressSpecified()){
@ -3367,6 +3367,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
rebuildExternalAddress(); rebuildExternalAddress();
} }
} else { } else {
if (newStatus == Status.UNKNOWN && status != _reachabilityStatusPending) {
// still have something pending, try again
if (_log.shouldLog(Log.WARN))
_log.warn("Old status: " + status + " status pending confirmation: " + _reachabilityStatusPending +
" Caused by update: " + newStatus);
_testEvent.forceRunSoon(isIPv6);
}
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Status unchanged: " + _reachabilityStatus + _log.info("Status unchanged: " + _reachabilityStatus +
" after update: " + newStatus + " after update: " + newStatus +