SSU2: Add delayed lookup of RI for relay and peer test

Prefer SSU2 introducers for slots 1 and 2
log tweaks
This commit is contained in:
zzz
2022-06-19 12:04:10 -04:00
parent d69a65605d
commit 3c4956f0c3
2 changed files with 142 additions and 8 deletions

View File

@@ -27,6 +27,7 @@ import net.i2p.router.RouterContext;
import net.i2p.router.transport.TransportUtil;
import net.i2p.util.Addresses;
import net.i2p.util.Log;
import net.i2p.util.SimpleTimer2;
import net.i2p.util.VersionComparator;
/**
@@ -235,11 +236,18 @@ class IntroductionManager {
Introducer intro;
byte[] key = ua.getIntroducerKey(i);
if (key != null) {
// SSU 1
//// debug, replace SSU 1 with SSU 2 if available for slots 1-2
//// leave slot 0 for SSU 1
//// this will churn the SSU 1 introducers, oh well
if (preferV2 && i > 0)
continue;
intro = new Introducer(ua.getIntroducerHost(i).getAddress(),
ua.getIntroducerPort(i), key, tag, sexp);
if (_log.shouldInfo())
_log.info("Reusing introducer: " + ua.getIntroducerHost(i));
} else {
// SSU 2
intro = new Introducer(ua.getIntroducerHash(i), tag, sexp);
if (_log.shouldInfo())
_log.info("Reusing introducer: " + ua.getIntroducerHash(i));
@@ -879,6 +887,73 @@ class IntroductionManager {
* @since 0.9.55
*/
void receiveRelayIntro(PeerState2 bob, Hash alice, byte[] data) {
receiveRelayIntro(bob, alice, data, 0);
}
/**
* We are Charlie and we got this from Bob.
* Bob should have sent us the RI, but maybe it's in the block
* after this, or maybe it's in a different packet.
* Check for RI, if not found, return true to retry, unless retryCount is at the limit.
* Creates the timer if retryCount == 0.
*
* SSU 2 only.
*
* @return true if RI found, false to delay and retry.
* @since 0.9.55
*/
private boolean receiveRelayIntro(PeerState2 bob, Hash alice, byte[] data, int retryCount) {
RouterInfo aliceRI = null;
if (retryCount < 5 && !_context.banlist().isBanlisted(alice)) {
aliceRI = _context.netDb().lookupRouterInfoLocally(alice);
if (aliceRI == null) {
if (_log.shouldInfo())
_log.info("Delay after " + retryCount + " retries, no RI for " + alice.toBase64());
if (retryCount == 0)
new DelayIntro(bob, alice, data);
return false;
}
}
receiveRelayIntro(bob, alice, data, aliceRI);
return true;
}
/**
* Wait for RI.
* @since 0.9.55
*/
private class DelayIntro extends SimpleTimer2.TimedEvent {
private final PeerState2 bob;
private final Hash alice;
private final byte[] data;
private volatile int count;
private static final long DELAY = 50;
public DelayIntro(PeerState2 b, Hash a, byte[] d) {
super(_context.simpleTimer2());
bob = b;
alice = a;
data = d;
schedule(DELAY);
}
public void timeReached() {
boolean ok = receiveRelayIntro(bob, alice, data, ++count);
if (!ok)
reschedule(DELAY << count);
}
}
/**
* We are Charlie and we got this from Bob.
* Send a HolePunch to Alice, who will soon be sending us a SessionRequest.
* And send a RelayResponse to bob.
*
* SSU 2 only.
*
* @since 0.9.55
*/
private void receiveRelayIntro(PeerState2 bob, Hash alice, byte[] data, RouterInfo aliceRI) {
long nonce = DataHelper.fromLong(data, 0, 4);
long tag = DataHelper.fromLong(data, 4, 4);
long time = DataHelper.fromLong(data, 8, 4) * 1000;
@@ -912,7 +987,6 @@ class IntroductionManager {
return;
}
RouterInfo aliceRI = null;
SessionKey aliceIntroKey = null;
int rcode;
PeerState aps = _transport.getPeerState(alice);
@@ -927,8 +1001,7 @@ class IntroductionManager {
rcode = SSU2Util.RELAY_REJECT_CHARLIE_ADDRESS;
} else {
// bob should have sent it to us. Don't bother to lookup
// remotely if he didn't, or it was out-of-order or lost.
aliceRI = _context.netDb().lookupRouterInfoLocally(alice);
// remotely if he didn't, or it was lost.
if (aliceRI != null) {
// validate signed data
SigningPublicKey spk = aliceRI.getIdentity().getSigningPublicKey();
@@ -946,7 +1019,7 @@ class IntroductionManager {
}
} else {
if (_log.shouldWarn())
_log.warn("Alice RI not found " + alice);
_log.warn("Alice RI not found " + alice + " for relay intro from " + bob);
rcode = SSU2Util.RELAY_REJECT_CHARLIE_UNKNOWN_ALICE;
}
}
@@ -985,8 +1058,8 @@ class IntroductionManager {
return;
}
UDPPacket packet = _builder2.buildRelayResponse(data, bob);
if (_log.shouldDebug())
_log.debug("Send relay response " + rcode + " as charlie " + " nonce " + nonce + " to bob " + bob);
if (_log.shouldInfo())
_log.info("Send relay response " + rcode + " as charlie " + " nonce " + nonce + " to bob " + bob);
_transport.send(packet);
if (rcode == SSU2Util.RELAY_ACCEPT) {
// send hole punch with the same data we sent to Bob

View File

@@ -32,6 +32,7 @@ import net.i2p.util.Addresses;
import net.i2p.util.Log;
import net.i2p.util.HexDump;
import net.i2p.util.SimpleTimer;
import net.i2p.util.SimpleTimer2;
import net.i2p.util.VersionComparator;
/**
@@ -838,7 +839,67 @@ class PeerTestManager {
* @since 0.9.54
*/
public void receiveTest(RemoteHostId from, PeerState2 fromPeer, int msg, int status, Hash h, byte[] data) {
receiveTest(from, fromPeer, msg, status, h, data, null, 0);
if (status == 0 && (msg == 2 || msg == 4) && !_context.banlist().isBanlisted(h))
receiveTest(from, fromPeer, msg, h, data, 0);
else
receiveTest(from, fromPeer, msg, status, h, data, null, 0);
}
/**
* Status 0 only, Msg 2 and 4 only, SSU 2 only.
* Bob should have sent us the RI, but maybe it's in the block
* after this, or maybe it's in a different packet.
* Check for RI, if not found, return true to retry, unless retryCount is at the limit.
* Creates the timer if retryCount == 0.
*
* We are Alice for msg 4, Charlie for msg 2.
*
* @return true if RI found, false to delay and retry.
* @since 0.9.55
*/
private boolean receiveTest(RemoteHostId from, PeerState2 fromPeer, int msg, Hash h, byte[] data, int retryCount) {
if (retryCount < 5) {
RouterInfo ri = _context.netDb().lookupRouterInfoLocally(h);
if (ri == null) {
if (_log.shouldInfo())
_log.info("Delay after " + retryCount + " retries, no RI for " + h.toBase64());
if (retryCount == 0)
new DelayTest(from, fromPeer, msg, h, data);
return false;
}
}
receiveTest(from, fromPeer, msg, 0, h, data, null, 0);
return true;
}
/**
* Wait for RI.
* @since 0.9.55
*/
private class DelayTest extends SimpleTimer2.TimedEvent {
private final RemoteHostId from;
private final PeerState2 fromPeer;
private final int msg;
private final Hash hash;
private final byte[] data;
private volatile int count;
private static final long DELAY = 50;
public DelayTest(RemoteHostId f, PeerState2 fp, int m, Hash h, byte[] d) {
super(_context.simpleTimer2());
from = f;
fromPeer = fp;
msg = m;
hash = h;
data = d;
schedule(DELAY);
}
public void timeReached() {
boolean ok = receiveTest(from, fromPeer, msg, hash, data, ++count);
if (!ok)
reschedule(DELAY << count);
}
}
/**
@@ -1102,7 +1163,7 @@ class PeerTestManager {
}
} else {
if (_log.shouldWarn())
_log.warn("Alice RI not found " + h);
_log.warn("Alice RI not found " + h + " for peer test from " + fromPeer);
rcode = SSU2Util.TEST_REJECT_CHARLIE_UNKNOWN_ALICE;
}
}