forked from I2P_Developers/i2p.i2p
SSU2: Refactor tokens
Store OB tokens by IP/port Centralize token generation and expiration in Establishment Manager Add methods to flush OB tokens on IP/port change Log tweaks Javadoc fix
This commit is contained in:
@@ -51,7 +51,7 @@ class EstablishmentManager {
|
||||
// SSU 2
|
||||
private final PacketBuilder2 _builder2;
|
||||
private final boolean _enableSSU2;
|
||||
private final Map<Hash, Token> _outboundTokens;
|
||||
private final Map<RemoteHostId, Token> _outboundTokens;
|
||||
private final Map<RemoteHostId, Token> _inboundTokens;
|
||||
|
||||
/** map of RemoteHostId to InboundEstablishState */
|
||||
@@ -168,7 +168,7 @@ class EstablishmentManager {
|
||||
_outboundByHash = new ConcurrentHashMap<Hash, OutboundEstablishState>();
|
||||
if (_enableSSU2) {
|
||||
_inboundTokens = new LHMCache<RemoteHostId, Token>(MAX_TOKENS);
|
||||
_outboundTokens = new LHMCache<Hash, Token>(MAX_TOKENS);
|
||||
_outboundTokens = new LHMCache<RemoteHostId, Token>(MAX_TOKENS);
|
||||
} else {
|
||||
_inboundTokens = null;
|
||||
_outboundTokens = null;
|
||||
@@ -1800,7 +1800,7 @@ class EstablishmentManager {
|
||||
* @param token nonzero
|
||||
* @since 0.9.54
|
||||
*/
|
||||
public void addOutboundToken(Hash peer, long token, long expires) {
|
||||
public void addOutboundToken(RemoteHostId peer, long token, long expires) {
|
||||
if (expires < _context.clock().now())
|
||||
return;
|
||||
Token tok = new Token(token, expires);
|
||||
@@ -1815,7 +1815,7 @@ class EstablishmentManager {
|
||||
* @return 0 if none available
|
||||
* @since 0.9.54
|
||||
*/
|
||||
public long getOutboundToken(Hash peer) {
|
||||
public long getOutboundToken(RemoteHostId peer) {
|
||||
Token tok;
|
||||
synchronized(_outboundTokens) {
|
||||
tok = _outboundTokens.remove(peer);
|
||||
@@ -1828,17 +1828,54 @@ class EstablishmentManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember a token that can be used later for the peer to connect to us
|
||||
* Remove our outbound tokens for this length
|
||||
*
|
||||
* @param token nonzero
|
||||
* @since 0.9.54
|
||||
*/
|
||||
public void addInboundToken(RemoteHostId peer, long token) {
|
||||
public void ipChanged(boolean isIPv6) {
|
||||
if (!_enableSSU2)
|
||||
return;
|
||||
int len = isIPv6 ? 16 : 4;
|
||||
// expire while we're at it
|
||||
long now = _context.clock().now();
|
||||
synchronized(_outboundTokens) {
|
||||
for (Iterator<Map.Entry<RemoteHostId, Token>> iter = _outboundTokens.entrySet().iterator(); iter.hasNext(); ) {
|
||||
Map.Entry<RemoteHostId, Token> e = iter.next();
|
||||
if (e.getKey().getIP().length == len || e.getValue().expires < now)
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all outbound tokens
|
||||
*
|
||||
* @since 0.9.54
|
||||
*/
|
||||
public void portChanged() {
|
||||
if (!_enableSSU2)
|
||||
return;
|
||||
synchronized(_outboundTokens) {
|
||||
_outboundTokens.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a token that can be used later for the peer to connect to us
|
||||
*
|
||||
* @since 0.9.54
|
||||
*/
|
||||
public Token getInboundToken(RemoteHostId peer) {
|
||||
long token;
|
||||
do {
|
||||
token = _context.random().nextLong();
|
||||
} while (token == 0);
|
||||
long expires = _context.clock().now() + IB_TOKEN_EXPIRATION;
|
||||
Token tok = new Token(token, expires);
|
||||
synchronized(_inboundTokens) {
|
||||
_inboundTokens.put(peer, tok);
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1862,7 +1899,7 @@ class EstablishmentManager {
|
||||
return tok.expires >= _context.clock().now();
|
||||
}
|
||||
|
||||
private static class Token {
|
||||
public static class Token {
|
||||
public final long token, expires;
|
||||
public Token(long tok, long exp) {
|
||||
token = tok; expires = exp;
|
||||
|
||||
@@ -370,7 +370,7 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
|
||||
public void gotToken(long token, long expires) {
|
||||
if (_receivedConfirmedIdentity == null)
|
||||
throw new IllegalStateException("RI must be first");
|
||||
_transport.getEstablisher().addOutboundToken(_receivedConfirmedIdentity.calculateHash(), token, expires);
|
||||
_transport.getEstablisher().addOutboundToken(_remoteHostId, token, expires);
|
||||
}
|
||||
|
||||
public void gotI2NP(I2NPMessage msg) {
|
||||
@@ -429,14 +429,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
|
||||
public long getSendConnID() { return _sendConnID; }
|
||||
public long getRcvConnID() { return _rcvConnID; }
|
||||
public long getToken() { return _token; }
|
||||
public long getNextToken() {
|
||||
// generate on the fly, this will only be called once
|
||||
long token;
|
||||
do {
|
||||
token = _context.random().nextLong();
|
||||
} while (token == 0);
|
||||
_transport.getEstablisher().addInboundToken(_remoteHostId, token);
|
||||
return token;
|
||||
public EstablishmentManager.Token getNextToken() {
|
||||
return _transport.getEstablisher().getInboundToken(_remoteHostId);
|
||||
}
|
||||
public HandshakeState getHandshakeState() { return _handshakeState; }
|
||||
public byte[] getSendHeaderEncryptKey1() { return _sendHeaderEncryptKey1; }
|
||||
@@ -720,6 +714,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
buf.append("IES2 ");
|
||||
buf.append(Addresses.toString(_aliceIP, _alicePort));
|
||||
buf.append(" Rcv ID: ").append(_rcvConnID);
|
||||
buf.append(" Send ID: ").append(_sendConnID);
|
||||
buf.append(" RelayTag: ").append(_sentRelayTag);
|
||||
buf.append(' ').append(_currentState);
|
||||
return buf.toString();
|
||||
|
||||
@@ -127,7 +127,7 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
|
||||
} while (_sendConnID == rcid);
|
||||
_rcvConnID = rcid;
|
||||
|
||||
_token = _transport.getEstablisher().getOutboundToken(_remotePeer.calculateHash());
|
||||
_token = _transport.getEstablisher().getOutboundToken(_remoteHostId);
|
||||
_routerAddress = ra;
|
||||
if (_token != 0)
|
||||
createNewState(ra);
|
||||
@@ -247,7 +247,7 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
|
||||
}
|
||||
|
||||
public void gotToken(long token, long expires) {
|
||||
_transport.getEstablisher().addOutboundToken(_remotePeer.calculateHash(), token, expires);
|
||||
_transport.getEstablisher().addOutboundToken(_remoteHostId, token, expires);
|
||||
}
|
||||
|
||||
public void gotI2NP(I2NPMessage msg) {
|
||||
@@ -299,14 +299,8 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
|
||||
public long getSendConnID() { return _sendConnID; }
|
||||
public long getRcvConnID() { return _rcvConnID; }
|
||||
public long getToken() { return _token; }
|
||||
public long getNextToken() {
|
||||
// generate on the fly, this will only be called once
|
||||
long token;
|
||||
do {
|
||||
token = _context.random().nextLong();
|
||||
} while (token == 0);
|
||||
_transport.getEstablisher().addInboundToken(_remoteHostId, token);
|
||||
return token;
|
||||
public EstablishmentManager.Token getNextToken() {
|
||||
return _transport.getEstablisher().getInboundToken(_remoteHostId);
|
||||
}
|
||||
public HandshakeState getHandshakeState() { return _handshakeState; }
|
||||
public byte[] getSendHeaderEncryptKey1() { return _sendHeaderEncryptKey1; }
|
||||
@@ -567,6 +561,9 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OES2 " + _remoteHostId + ' ' + _currentState;
|
||||
return "OES2 " + _remoteHostId +
|
||||
" Rcv ID: " + _rcvConnID +
|
||||
" Send ID: " + _sendConnID +
|
||||
' ' + _currentState;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,9 +73,6 @@ class PacketBuilder2 {
|
||||
/** 80 */
|
||||
public static final int MIN_IPV6_DATA_PACKET_OVERHEAD = IPV6_HEADER_SIZE + UDP_HEADER_SIZE + DATA_HEADER_SIZE + MAC_LEN;
|
||||
|
||||
/// FIXME
|
||||
private static final int MAX_IDENTITY_FRAGMENT_SIZE = 1280 - (MIN_DATA_PACKET_OVERHEAD + KEY_LEN + MAC_LEN);
|
||||
|
||||
private static final int ABSOLUTE_MAX_ACK_RANGES = 512;
|
||||
|
||||
/* Higher than all other OutNetMessage priorities, but still droppable,
|
||||
@@ -788,7 +785,8 @@ class PacketBuilder2 {
|
||||
* @param packet containing only 32 byte header
|
||||
*/
|
||||
private void encryptSessionCreated(UDPPacket packet, HandshakeState state,
|
||||
byte[] hdrKey1, byte[] hdrKey2, long relayTag, long token, byte[] ip, int port) {
|
||||
byte[] hdrKey1, byte[] hdrKey2, long relayTag,
|
||||
EstablishmentManager.Token token, byte[] ip, int port) {
|
||||
DatagramPacket pkt = packet.getPacket();
|
||||
byte data[] = pkt.getData();
|
||||
int off = pkt.getOffset();
|
||||
@@ -805,8 +803,8 @@ class PacketBuilder2 {
|
||||
len += block.getTotalLength();
|
||||
blocks.add(block);
|
||||
}
|
||||
if (token > 0) {
|
||||
block = new SSU2Payload.NewTokenBlock(token, _context.clock().now() + EstablishmentManager.IB_TOKEN_EXPIRATION);
|
||||
if (token != null) {
|
||||
block = new SSU2Payload.NewTokenBlock(token.token, token.expires);
|
||||
len += block.getTotalLength();
|
||||
blocks.add(block);
|
||||
}
|
||||
@@ -938,7 +936,7 @@ class PacketBuilder2 {
|
||||
*/
|
||||
private void encryptSessionConfirmed(UDPPacket packet, HandshakeState state, int mtu,
|
||||
boolean isIPv6, byte[] hdrKey1, byte[] hdrKey2,
|
||||
SSU2Payload.RIBlock riblock, long token) {
|
||||
SSU2Payload.RIBlock riblock, EstablishmentManager.Token token) {
|
||||
DatagramPacket pkt = packet.getPacket();
|
||||
byte data[] = pkt.getData();
|
||||
int off = pkt.getOffset();
|
||||
@@ -949,8 +947,8 @@ class PacketBuilder2 {
|
||||
int len = riblock.getTotalLength();
|
||||
blocks.add(riblock);
|
||||
// only if room
|
||||
if (token > 0 && mtu - (SHORT_HEADER_SIZE + KEY_LEN + MAC_LEN + len + MAC_LEN) >= 15) {
|
||||
Block block = new SSU2Payload.NewTokenBlock(token, _context.clock().now() + EstablishmentManager.IB_TOKEN_EXPIRATION);
|
||||
if (token != null && mtu - (SHORT_HEADER_SIZE + KEY_LEN + MAC_LEN + len + MAC_LEN) >= 15) {
|
||||
Block block = new SSU2Payload.NewTokenBlock(token.token, token.expires);
|
||||
len += block.getTotalLength();
|
||||
blocks.add(block);
|
||||
}
|
||||
|
||||
@@ -289,8 +289,8 @@ class PacketHandler {
|
||||
if (state.getNextMACKey() != null)
|
||||
isValid = validate(packet, state.getNextMACKey());
|
||||
if (!isValid) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Failed validation with existing con, trying as new con: " + packet);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Failed validation with existing con, trying as new con: " + packet);
|
||||
|
||||
isValid = validate(packet, _transport.getIntroKey());
|
||||
if (isValid) {
|
||||
@@ -472,8 +472,8 @@ class PacketHandler {
|
||||
if (state.getMACKey() != null) {
|
||||
isValid = validate(packet, state.getMACKey());
|
||||
if (isValid) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Valid introduction packet received for inbound con: " + packet);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Valid introduction packet received for inbound con: " + packet);
|
||||
|
||||
packet.decrypt(state.getCipherKey());
|
||||
handlePacket(reader, packet, null, null, null, AuthType.SESSION);
|
||||
@@ -513,8 +513,8 @@ class PacketHandler {
|
||||
isValid = validate(packet, state.getMACKey());
|
||||
if (isValid) {
|
||||
// this should be the Session Confirmed packet
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Valid introduction packet received for outbound established con: " + packet);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Valid introduction packet received for outbound established con: " + packet);
|
||||
packet.decrypt(state.getCipherKey());
|
||||
handlePacket(reader, packet, null, state, null, AuthType.SESSION);
|
||||
return;
|
||||
@@ -524,8 +524,8 @@ class PacketHandler {
|
||||
// keys not yet exchanged, lets try it with the peer's intro key
|
||||
isValid = validate(packet, state.getIntroKey());
|
||||
if (isValid) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Valid packet received for " + state + " with Bob's intro key: " + packet);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Valid packet received for " + state + " with Bob's intro key: " + packet);
|
||||
packet.decrypt(state.getIntroKey());
|
||||
// the only packet we should be getting with Bob's intro key is Session Created
|
||||
handlePacket(reader, packet, null, state, null, AuthType.BOBINTRO);
|
||||
@@ -721,8 +721,8 @@ class PacketHandler {
|
||||
_log.warn("Dropping type " + type + " auth " + auth + ": " + packet);
|
||||
break;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Received relay request packet: " + reader + " from " + from);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Received relay request packet: " + reader + " from " + from);
|
||||
_introManager.receiveRelayRequest(from, reader);
|
||||
break;
|
||||
case UDPPacket.PAYLOAD_TYPE_RELAY_INTRO:
|
||||
@@ -731,8 +731,8 @@ class PacketHandler {
|
||||
_log.warn("Dropping type " + type + " auth " + auth + ": " + packet);
|
||||
break;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Received relay intro packet: " + reader + " from " + from);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Received relay intro packet: " + reader + " from " + from);
|
||||
_introManager.receiveRelayIntro(from, reader);
|
||||
break;
|
||||
case UDPPacket.PAYLOAD_TYPE_RELAY_RESPONSE:
|
||||
@@ -741,8 +741,8 @@ class PacketHandler {
|
||||
_log.warn("Dropping type " + type + " auth " + auth + ": " + packet);
|
||||
break;
|
||||
}
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Received relay response packet: " + reader + " from " + from);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Received relay response packet: " + reader + " from " + from);
|
||||
_establisher.receiveRelayResponse(from, reader);
|
||||
break;
|
||||
case UDPPacket.PAYLOAD_TYPE_SESSION_DESTROY:
|
||||
|
||||
@@ -427,7 +427,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
|
||||
}
|
||||
|
||||
public void gotToken(long token, long expires) {
|
||||
_transport.getEstablisher().addOutboundToken(_remotePeer, token, expires);
|
||||
_transport.getEstablisher().addOutboundToken(_remoteHostId, token, expires);
|
||||
}
|
||||
|
||||
public void gotI2NP(I2NPMessage msg) {
|
||||
|
||||
@@ -184,7 +184,7 @@ class PeerTestManager {
|
||||
/**
|
||||
* The next few methods are for when we are Alice
|
||||
*
|
||||
* @param bobIP IPv4 only
|
||||
* @param bob IPv4 only
|
||||
*/
|
||||
public synchronized void runTest(PeerState bob) {
|
||||
if (_currentTest != null) {
|
||||
|
||||
Reference in New Issue
Block a user