forked from I2P_Developers/i2p.i2p
SSU2: Add state lookup by conn ID
As fallback for failed lookup by RemoteHostId. This will eventually be the primary lookup after most traffic is SSU2. For now, only used to receive traffic from a peer that changed IP/port. SSU 1/2 send destroy when replacing old session with new. Prep for full SSU2 connection migration.
This commit is contained in:
@@ -272,7 +272,7 @@ class PacketHandler {
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("Packet received IS for an existing peer");
|
||||
if (state.getVersion() == 2)
|
||||
receiveSSU2Packet(packet, (PeerState2) state);
|
||||
((PeerState2) state).receivePacket(rem, packet);
|
||||
else
|
||||
receivePacket(reader, packet, state);
|
||||
}
|
||||
@@ -771,23 +771,6 @@ class PacketHandler {
|
||||
|
||||
//// Begin SSU2 Handling ////
|
||||
|
||||
/**
|
||||
* Hand off to the state for processing.
|
||||
* Packet is decrypted in-place, no fallback
|
||||
* processing is possible.
|
||||
*
|
||||
* Min packet data size: 40
|
||||
*
|
||||
* @param packet any in-session message
|
||||
* @param state must be version 2, non-null
|
||||
* @since 0.9.54
|
||||
*/
|
||||
private void receiveSSU2Packet(UDPPacket packet, PeerState2 state) {
|
||||
// header and body decryption is done by PeerState2
|
||||
// This bypasses InboundMessageStates completely.
|
||||
// All handling of fragments and acks is done in PeerState2.
|
||||
state.receivePacket(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the header and hand off to the state for processing.
|
||||
@@ -831,6 +814,20 @@ class PacketHandler {
|
||||
// in group 4 receive packet
|
||||
//if (_log.shouldDebug())
|
||||
// _log.debug("Does not decrypt as Session Request, Token Request, or Peer Test: " + header);
|
||||
if (header != null) {
|
||||
// conn ID decryption is the same for short and long header, with k1
|
||||
// presumably a data packet, either ip/port changed, or a race during establishment?
|
||||
// lookup peer state by conn ID, pass over for decryption with the proper k2
|
||||
long id = header.getDestConnID();
|
||||
PeerState2 ps2 = _transport.getPeerState(id);
|
||||
if (ps2 != null) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Migrated " + packet.getPacket().getLength() + " byte packet from " + from +
|
||||
" for " + ps2);
|
||||
ps2.receivePacket(from, packet);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
type = header.getType();
|
||||
@@ -925,7 +922,7 @@ class PacketHandler {
|
||||
_establisher.receiveHolePunch(from, packet);
|
||||
} else {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Got unknown message " + header + " on " + state);
|
||||
_log.warn("Got unknown SSU2 message " + header + " from " + from);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@@ -310,6 +310,23 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
|
||||
* @param packet fully encrypted, header and body decryption will be done here
|
||||
*/
|
||||
void receivePacket(UDPPacket packet) {
|
||||
receivePacket(packet.getRemoteHost(), packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* From different than expected source IP/port
|
||||
*
|
||||
* @param from source address
|
||||
* @param packet fully encrypted, header and body decryption will be done here
|
||||
* @since 0.9.56
|
||||
*/
|
||||
void receivePacket(RemoteHostId from, UDPPacket packet) {
|
||||
if (!from.equals(_remoteHostId)) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Got packet from " + from + " expected " + _remoteHostId + " on " + this);
|
||||
// Connection Migration TODO
|
||||
}
|
||||
|
||||
DatagramPacket dpacket = packet.getPacket();
|
||||
byte[] data = dpacket.getData();
|
||||
int off = dpacket.getOffset();
|
||||
@@ -332,6 +349,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
|
||||
// attempting to decrypt with our intro key.
|
||||
// resend session confirmed in response
|
||||
checkRetransmitSessionConfirmed(_context.clock().now(), true);
|
||||
// alternatively, the session closed and we didn't get the termination,
|
||||
// and this is a new inbound session request? TODO
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@@ -172,6 +172,7 @@ final class SSU2Util {
|
||||
public static final int REASON_LIMITS = 19;
|
||||
public static final int REASON_VERSION = 20;
|
||||
public static final int REASON_NETID = 21;
|
||||
public static final int REASON_REPLACED = 22;
|
||||
|
||||
private SSU2Util() {}
|
||||
|
||||
|
@@ -75,6 +75,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
private final Map<Hash, PeerState> _peersByIdent;
|
||||
/** RemoteHostId to PeerState */
|
||||
private final Map<RemoteHostId, PeerState> _peersByRemoteHost;
|
||||
private final Map<Long, PeerState2> _peersByConnID;
|
||||
private PacketHandler _handler;
|
||||
private EstablishmentManager _establisher;
|
||||
private final MessageQueue _outboundMessages;
|
||||
@@ -336,6 +337,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_log = ctx.logManager().getLog(UDPTransport.class);
|
||||
_peersByIdent = new ConcurrentHashMap<Hash, PeerState>(128);
|
||||
_peersByRemoteHost = new ConcurrentHashMap<RemoteHostId, PeerState>(128);
|
||||
_peersByConnID = (xdh != null) ? new ConcurrentHashMap<Long, PeerState2>(32) : null;
|
||||
_dropList = new ConcurrentHashSet<RemoteHostId>(2);
|
||||
_endpoints = new CopyOnWriteArrayList<UDPEndpoint>();
|
||||
|
||||
@@ -852,6 +854,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_testEvent.setIsAlive(false);
|
||||
_peersByRemoteHost.clear();
|
||||
_peersByIdent.clear();
|
||||
if (_peersByConnID != null)
|
||||
_peersByConnID.clear();
|
||||
_dropList.clear();
|
||||
_introManager.reset();
|
||||
UDPPacket.clearCache();
|
||||
@@ -1630,15 +1634,23 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* get the state for the peer with the given ident, or null
|
||||
* if no state exists
|
||||
*/
|
||||
PeerState getPeerState(Hash remotePeer) {
|
||||
PeerState getPeerState(Hash remotePeer) {
|
||||
return _peersByIdent.get(remotePeer);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the state by SSU2 connection ID
|
||||
* @since 0.9.56
|
||||
*/
|
||||
PeerState2 getPeerState(long rcvConnID) {
|
||||
return _peersByConnID.get(Long.valueOf(rcvConnID));
|
||||
}
|
||||
|
||||
/**
|
||||
* For /peers UI only. Not a public API, not for external use.
|
||||
*
|
||||
@@ -1769,9 +1781,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
oldEstablishedOn = oldPeer.getKeyEstablishedTime();
|
||||
}
|
||||
}
|
||||
|
||||
if (peer.getVersion() == 2) {
|
||||
PeerState2 state2 = (PeerState2) peer;
|
||||
_peersByConnID.put(Long.valueOf(state2.getRcvConnID()), state2);
|
||||
}
|
||||
|
||||
RemoteHostId remoteId = peer.getRemoteHostId();
|
||||
if (oldPeer != null) {
|
||||
sendDestroy(oldPeer, SSU2Util.REASON_REPLACED);
|
||||
oldPeer.dropOutbound();
|
||||
_introManager.remove(oldPeer);
|
||||
RemoteHostId oldID = oldPeer.getRemoteHostId();
|
||||
@@ -1786,6 +1804,10 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_introManager.remove(oldPeer2);
|
||||
}
|
||||
}
|
||||
if (oldPeer != peer && oldPeer.getVersion() == 2) {
|
||||
PeerState2 state2 = (PeerState2) oldPeer;
|
||||
_peersByConnID.remove(Long.valueOf(state2.getRcvConnID()));
|
||||
}
|
||||
}
|
||||
|
||||
// Should always be direct... except maybe for hidden mode?
|
||||
@@ -1802,6 +1824,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
// transfer over the old state/inbound message fragments/etc
|
||||
peer.loadFrom(oldPeer2);
|
||||
oldEstablishedOn = oldPeer2.getKeyEstablishedTime();
|
||||
sendDestroy(oldPeer2, SSU2Util.REASON_REPLACED);
|
||||
oldPeer2.dropOutbound();
|
||||
_introManager.remove(oldPeer2);
|
||||
}
|
||||
@@ -1984,6 +2007,11 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
|
||||
_context.statManager().addRateData("udp.droppedPeer", now - peer.getLastReceiveTime(), now - peer.getKeyEstablishedTime());
|
||||
altByIdent = _peersByIdent.remove(peer.getRemotePeer());
|
||||
}
|
||||
|
||||
if (peer.getVersion() == 2) {
|
||||
PeerState2 state2 = (PeerState2) peer;
|
||||
_peersByConnID.remove(Long.valueOf(state2.getRcvConnID()));
|
||||
}
|
||||
|
||||
RemoteHostId remoteId = peer.getRemoteHostId();
|
||||
PeerState altByHost = _peersByRemoteHost.remove(remoteId);
|
||||
|
Reference in New Issue
Block a user