diff --git a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java index 1013de01b15bd487fab55e169c85efad0fb4c94a..e3d8147044065ef5992560409c7f546f9b0852f1 100644 --- a/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java +++ b/router/java/src/net/i2p/router/transport/udp/IntroductionManager.java @@ -18,6 +18,7 @@ import net.i2p.data.Hash; import net.i2p.data.SessionKey; import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; +import net.i2p.data.i2np.DatabaseStoreMessage; import net.i2p.data.router.RouterAddress; import net.i2p.data.router.RouterInfo; import net.i2p.router.RouterContext; @@ -106,6 +107,7 @@ class IntroductionManager { private static final int MAX_PUNCHES = 20; private static final long INTRODUCER_EXPIRATION = 80*60*1000L; private static final String MIN_IPV6_INTRODUCER_VERSION = "0.9.50"; + private static final long MAX_SKEW = 2*60*1000; public IntroductionManager(RouterContext ctx, UDPTransport transport) { _context = ctx; @@ -667,6 +669,79 @@ class IntroductionManager { * @since 0.9.55 */ void receiveRelayRequest(PeerState2 alice, byte[] data) { + long tag = DataHelper.fromLong(data, 4, 4); + long time = DataHelper.fromLong(data, 8, 4) * 1000; + long now = _context.clock().now(); + long skew = time - now; + if (skew > MAX_SKEW || skew < 0 - MAX_SKEW) { + if (_log.shouldWarn()) + _log.warn("Too skewed for relay req from " + alice); + return; + } + int ver = data[12] & 0xff; + if (ver != 2) { + if (_log.shouldWarn()) + _log.warn("Bad relay req version " + ver + " from " + alice); + return; + } + PeerState charlie = _outbound.get(Long.valueOf(tag)); + RouterInfo aliceRI = null; + int rcode; + if (charlie == null) { + if (_log.shouldWarn()) + _log.warn("Relay tag not found " + tag + " from " + alice); + rcode = SSU2Util.RELAY_REJECT_BOB_NO_TAG; + } else if (charlie.getVersion() != 2) { + return; + } else { + aliceRI = _context.netDb().lookupRouterInfoLocally(alice.getRemotePeer()); + if (aliceRI != null) { + // validate signed data + SigningPublicKey spk = aliceRI.getIdentity().getSigningPublicKey(); + if (SSU2Util.validateSig(_context, SSU2Util.RELAY_REQUEST_PROLOGUE, + _context.routerHash(), charlie.getRemotePeer(), data, spk)) { + rcode = SSU2Util.RELAY_ACCEPT; + } else { + if (_log.shouldWarn()) + _log.warn("Signature failed relay intro\n" + aliceRI); + rcode = SSU2Util.RELAY_REJECT_BOB_SIGFAIL; + } + } else { + if (_log.shouldWarn()) + _log.warn("Alice RI not found " + alice); + rcode = SSU2Util.RELAY_REJECT_BOB_UNKNOWN_ALICE; + } + } + UDPPacket packet; + if (rcode == SSU2Util.RELAY_ACCEPT) { + // Send Alice RI and forward data in a Relay Intro to Charlie + if (_log.shouldDebug()) + _log.debug("Send alice RI and relay intro to " + charlie); + DatabaseStoreMessage dbsm = new DatabaseStoreMessage(_context); + dbsm.setEntry(aliceRI); + dbsm.setMessageExpiration(now + 10*1000); + _transport.send(dbsm, charlie); + packet = _builder2.buildRelayIntro(data, (PeerState2) charlie); + } else { + // send rejection to Alice + SigningPrivateKey spk = _context.keyManager().getSigningPrivateKey(); + long nonce = DataHelper.fromLong(data, 0, 4); + int iplen = data[13] & 0xff; + int testPort = (int) DataHelper.fromLong(data, 14, 2); + byte[] testIP = new byte[iplen - 2]; + System.arraycopy(data, 16, testIP, 0, iplen - 2); + data = SSU2Util.createRelayResponseData(_context, _context.routerHash(), rcode, + nonce, testIP, testPort, spk); + if (data == null) { + if (_log.shouldWarn()) + _log.warn("sig fail"); + return; + } + if (_log.shouldDebug()) + _log.debug("Send relay response rejection " + rcode + " to " + alice); + packet = _builder2.buildRelayResponse(data, alice); + } + _transport.send(packet); } /** @@ -682,6 +757,13 @@ class IntroductionManager { long nonce = DataHelper.fromLong(data, 0, 4); long tag = DataHelper.fromLong(data, 4, 4); long time = DataHelper.fromLong(data, 8, 4) * 1000; + long now = _context.clock().now(); + long skew = time - now; + if (skew > MAX_SKEW || skew < 0 - MAX_SKEW) { + if (_log.shouldWarn()) + _log.warn("Too skewed for relay intro from " + bob); + return; + } int ver = data[12] & 0xff; if (ver != 2) { if (_log.shouldWarn()) diff --git a/router/java/src/net/i2p/router/transport/udp/SSU2Util.java b/router/java/src/net/i2p/router/transport/udp/SSU2Util.java index 15a6be50d7642d1ae9e5de9609e42ae7e1738652..4f4878d55f3e3be080e70999931b7b7a6513bcf1 100644 --- a/router/java/src/net/i2p/router/transport/udp/SSU2Util.java +++ b/router/java/src/net/i2p/router/transport/udp/SSU2Util.java @@ -139,6 +139,7 @@ final class SSU2Util { public static final int RELAY_REJECT_BOB_LIMIT = 3; public static final int RELAY_REJECT_BOB_SIGFAIL = 4; public static final int RELAY_REJECT_BOB_NO_TAG = 5; + public static final int RELAY_REJECT_BOB_UNKNOWN_ALICE = 6; public static final int RELAY_REJECT_CHARLIE_UNSPEC = 64; public static final int RELAY_REJECT_CHARLIE_ADDRESS = 65; public static final int RELAY_REJECT_CHARLIE_LIMIT = 66;