Nested Class Summary
Modifier and TypeClassDescriptionprivate classDriving thread, processing up to one step for an inbound peer and up to one step for an outbound peer.private static classProcess SSU2 hole punch payload.private classFor inbound tokens only, to record eviction time in a stat, for use in setting expiration times.static classToken used for SSU2 session establishment and validation.private static classSoonest expiration first.Field Summary
Modifier and TypeFieldDescriptionprivate intEstablishment attempts currently in flight.private final ObjectLock for the establishment activity count.private booleanFalse once the manager has shut down.private final BanLoggerRecords why routers were banned.private final PacketBuilder2Builder for SSU2 packets.private final RouterContextThe router context.private static final AtomicLongCorrupt confirm logs suppressed since the last one.private static intDefault concurrent establishments for a high profile.private static intDefault concurrent establishments for a low profile.private final Map<RemoteHostId, Long> Temporary inbound bans after previous IB failure, to prevent excessive DH.private static final AtomicLongGiveup logs suppressed since the last one.private final ConcurrentHashMap<RemoteHostId, InboundEstablishState> Map of RemoteHostId to InboundEstablishState.private RateStatCached "udp.inboundTokenLifetime" RateStat handle.private final Map<RemoteHostId, EstablishmentManager.Token> Tokens issued to hosts that contacted us.private static final AtomicLongWhen a corrupt confirm was last logged.private static final AtomicLongWhen the inbound giveup was last logged.private final ConcurrentHashMap<Long, OutboundEstablishState> Map of nonce (Long) to OutboundEstablishState.private final LogLogger for SSU connection establishment.private final intThe network id we communicate on.private final ConcurrentHashMap<RemoteHostId, OutboundEstablishState> Map of claimed IP/port to OutboundEstablishState.private final ConcurrentHashMap<Hash, OutboundEstablishState> Map of router hash to OutboundEstablishState.private final ConcurrentHashMap<RemoteHostId, OutboundEstablishState> Map of RemoteHostId to OutboundEstablishState.private final Map<RemoteHostId, EstablishmentManager.Token> Tokens we hold for hosts we contact.private final ConcurrentHashMap<RemoteHostId, LinkedBlockingQueue<OutNetMessage>> Map of RemoteHostId to a bounded, thread-safe queue of OutNetMessage instances for peers whose outbound establishment is pending due to concurrency limits.private final ObjectCounter<RemoteHostId> Counts termination messages per host.private final UDPTransportThe SSU transport we serve.private static intTuned max concurrent establish, -1 = use config.private static final longBan duration for a peer that supplied an invalid or spoofed SSU address, an unusable MTU, or a bad introduction key.(package private) static final longMinimum gap between "Corrupt SessionConfirmed" reports.(package private) static final AtomicLongFor the DSM and or netdb store.private final intMax outbound in progress - max inbound is half of this.private static final longHow long an inbound establishment failure bans a peer.private static final longInbound retry-sent limit: how long we wait to get a session request back after a retry, before giving up (5x the retransmit delay).static final longHow long an inbound token stays valid, in milliseconds.(package private) static final longMinimum gap between inbound establishment give-up reports.(package private) static final AtomicLongKill any inbound that takes more than this.private static final longLargest possible handshake nonce value.(package private) static final AtomicLongKill any outbound that takes more than this.private static intMax pending outbound connections (waiting because we are at MAX_CONCURRENT_ESTABLISH).private static final intMax queued msgs per peer while peer connection is queued.private static final longMaximum clock skew accepted in a handshake.static final longThe relay tag is a 4-byte field in the protocol.private static final intMax immediate terminations to send to a peer every FAILSAFE_INTERVAL.private static final intMost tokens issued to one host.private static final intFewest tokens issued to one host.static final longMax wait before receiving a response to a single message during outbound establishment.private static final longExtra establishment budget granted to an outbound attempt once a resend has been scheduled and still failed.private static final StringConfig key for the concurrent establishment limit.(package private) static final longCompletion time above which a handshake counts as slow.private static final StringFile holding the SSU2 tokens across restarts.Constructor Summary
ConstructorsConstructorDescriptionEstablishmentManager(RouterContext ctx, UDPTransport transport) Creates the establishment manager.Method Summary
Modifier and TypeMethodDescriptionvoidaddOutboundToken(RemoteHostId peer, long token, long expires) Remember a token that can be used later to connect to the peer.private voidbanAndFail(OutNetMessage msg, Hash toHash, String failReason, String banReason, String noHashWarn, String ipAddress, int port, String truncHash, long banDuration, long now, boolean isBanned) Mark the peer unreachable and fail the message.private voidbanAndFailState(OutboundEstablishState state, String reason, long banDuration) Ban the peer and fail the outbound establish state for bad introduction data.(package private) static booleanCan the given introducer have signed the relay response? A peer that was never contacted, terminated the session, or explicitly rejected the hole punch cannot be the signer.(package private) static StringThe reason a SessionConfirmed was rejected, for the log line.private OutboundEstablishStatecreateOutboundState(OutNetMessage msg, RemoteHostId to, RemoteHostId maybeTo, RouterIdentity toIdentity, boolean isIndirect, UDPAddress addr, RouterAddress ra, Hash toHash, String truncHash, String ipAddress, int maybePort, long now, boolean isBanned) Create a new outbound establish state for the peer, after verifying that its introducers, MTU, and introduction key are usable.voidestablish(OutNetMessage msg) Send the message to its specified recipient by establishing a connection with them and sending it off.private voidestablish(OutNetMessage msg, boolean queueIfMaxExceeded) Establishes a connection to send the message, or queues it if the limit is exceeded.private OutboundEstablishStatefindHolePunchState(RemoteHostId id, long nonce) Find the outbound establish state this HolePunch belongs to.(package private) static longHow many corrupt-SessionConfirmed events were rate-limited away.static intThe default high max concurrent establish.static intThe default low max concurrent establish.(package private) static longThe extended budget an inbound attempt gets once it has sent a retry.(package private) static longInbound give-up events rate-limited away since the last report.(package private) InboundEstablishStategetInboundState(RemoteHostId from) Grab the active establishing state.getInboundToken(RemoteHostId peer) Token that can be used later for the peer to connect to us.getInboundToken(RemoteHostId peer, long expiration) Token that can be used later for the peer to connect to us.private intHow many concurrent outbound sessions to deal with.static intThe max concurrent establish in effect, tuned value if set else config.(package private) static longThe inbound establishment base deadline, as the Tuner has it set.private intHow many concurrent inbound sessions to deal with.static intThe current max queued outbound connections.A database store message with our router info.(package private) OutboundEstablishStategetOutboundState(RemoteHostId from) Grab the active establishing state.longgetOutboundToken(RemoteHostId peer) Token to connect to the peer.private voidOk, fully received, add it to the established cons and queue up a netDb store to them.private PeerStateOk, fully received, add it to the established cons and send any queued messages.private longDrive through the inbound establishment states, adjusting one of them as necessary.private longDrive through the outbound establishment states, adjusting one of them as necessary.private voidSend RelayRequests to multiple introducers.(package private) static booleanhasInboundEstablishExpired(long lifetime, boolean isRetrySent, long maxEstablishTime, long retrySentMaxTime) Has the inbound establish state lived long enough to be expired, either past the overall establish cap or, when we are waiting for a session request after sending a retry, past the retry-sent limit?(package private) static booleanhasObMessageTimedOut(long lastSentTime, long timeoutMs, long now) Has the outbound state gone unanswered for at least the message timeout? A zero/unknown send time never counts as timed out.(package private) static booleanhasOutboundEstablishExpired(long lifetime, boolean hasRetried, long maxEstablishTime, long retryExtraMs) Whether an outbound establishment attempt has run out of time.(package private) static booleanDoes the exception carry a message worth showing to the user? Legacy code stores the string "null" in the message.(package private) static booleanhasValidV2Introducer(UDPAddress addr, long now) Does the SSU2 address advertise at least one usable v2 introducer, meaning a hash that hasn't expired (expiration 0 means never expires)? Used bycreateOutboundState(OutNetMessage, RemoteHostId, RemoteHostId, RouterIdentity, boolean, UDPAddress, RouterAddress, Hash, String, String, int, long, boolean)before building a state for an indirect peer, since without any current introducer the establishment can never succeed.(package private) static longinboundEstablishBudget(boolean isRetrySent, long maxEstablishTime, long retrySentMaxTime) The deadline an inbound attempt was actually given.private RateStatResolves the "udp.inboundTokenLifetime" RateStat, caching the handle.voidipChanged(boolean isIPv6) Remove our tokens for this length.(package private) static booleanisBadRelayDataAddress(boolean validPort, boolean validIP, boolean tooClose, boolean sameAsIntroducer, boolean blocklisted) Is the claimed relay address unacceptable, meaning Charlie asked us to connect somewhere invalid, too close, on our own network, or a blocklisted address? Finding the introducer's own IP in the claim is also rejection-worthy (a relay must not send us back to itself).(package private) static booleanisBanlisted(Banlist banlist, Hash h) Is the router with the given hash banlisted under any active ban? Null-safe.(package private) static booleanisBlocklisted(Blocklist blocklist, byte[] ip) Is the given IP address in the router's blocklist? Null-safe.(package private) static booleanisBobRelayReject(int code) Is this a rejection from the introducer (Bob) rather than from Charlie or a success? SSU2 relay response codes 1-63 reject at the introducer layer.booleanisConnecting(Hash dest) Check if an outbound SSU handshake is in progress for the given peer.booleanisInboundTokenValid(RemoteHostId peer, long token) Is the token from this peer valid?(package private) static booleanisInvalidPeerIP(boolean isValid, boolean equalsExternalIP, boolean allowLocal) Is the claimed IP address unusable, either because it isn't a routable public address or because it is ours without local connections allowed? The caller supplies the per-transport validity and "equals external IP" booleans so this stays a pure decision.(package private) static booleanisMtuTooSmall(int mtu, int ourMTU) Is either our MTU or the peer's advertised MTU below the minimum usable for SSU2? MTUs of 0 are treated as unknown and pass, matching the original inline check.private booleanIs the peer on the blocklist or banlist?private booleanIs the peer on the blocklist or banlist?private booleanisPeerBanned(RemoteHostId hostId) Is the peer on the blocklist or banlist?private booleanisPeerBanned(RemoteHostId hostId, String context) Is the peer on the blocklist or banlist?(package private) static booleanisSendDue(long nextSendTime, long now) Is the state due to send now (its next send time has arrived)?(package private) static booleanIs the outbound establish state in a terminal state that should be dropped and processed (completed or failed) rather than retried? Guards the scan loop inhandleOutbound().(package private) static booleanisUnspecifiedNetwork(int id) Is the peer's network ID unset (i.e.(package private) static booleanisUsableUDPAddress(byte[] ip, int port) Is a raw IP/port pair usable to try a direct connection to an introducer? Identity withisUsableUDPAddress(InetAddress, int)except operating on the already-extracted address bytes.(package private) static booleanisUsableUDPAddress(InetAddress remAddr, int port) Is the claimed address usable for a direct connection? A null address or a port outside 1-65535 is useless to us.(package private) booleanisValid(byte[] ip, int port) Are IP and port valid? This is only for checking the relay response.private booleanisValidHolePunchResponse(EstablishmentManager.HPCallback cb, long rcvConnID, long now, RemoteHostId id) Validate the decrypted HolePunch payload: response code, clock skew, the nonce echoing the receiving connection ID, the response time, and the version.(package private) static booleanisWrongNetwork(int id, int ourNetworkId) Is the peer's network ID one we will not establish to? The router communicates only with peers in its own network.private voidNot threaded, because we're holding the token cache locks anyway.private intMove pending outbound messages from_queuedOutboundinto active outbound establishment states.private OutboundEstablishStatelookupOutboundState(RemoteHostId to, Hash toHash) Look up an existing outbound establish state for the peer, first by address, then by hash (for indirect connections).(package private) static booleanneedsIndirect(boolean hasIntroducers, boolean noDirectAddress) Should this establish use the peer's introducers rather than the claimed address? True when the peer offers introducers or when no usable direct address was found.(package private) static OutboundEstablishState2.IntroStatenextIntroStateforLocalLookup(OutboundEstablishState2.IntroState istate, boolean riFound) Advance an introducer's state based on a local RouterInfo lookup.(package private) static OutboundEstablishState2.IntroStatenextIntroStateforPeerCheck(OutboundEstablishState2.IntroState istate, boolean peerPresent, boolean peerSupported) Advance an introducer's state based on whether we already hold a live PeerState for it.private voidRecords that an establishment attempt happened.static StringparseReason(int reasonCode) The reason string for an SSU termination code.voidRemove all tokens.private voidprocessExpired(InboundEstablishState inboundState) Caller should probably synch on inboundState.private voidprocessExpired(OutboundEstablishState outboundState) Caller should probably synch on outboundState.(package private) static booleanqueueAtCapacity(int queueCount, int maxPerPeer) Has this peer's deferred queue hit its per-peer cap?private voidqueueToInboundState(InboundEstablishState inState, OutNetMessage msg) Queue the message on an inbound establish state that's already in progress, or send/fail it immediately if the state is already complete or failed.(package private) PeerStateA data packet arrived on an outbound connection being established, which means its complete (yay!).(package private) voidreceiveHolePunch(RemoteHostId id, UDPPacket packet) Called from PacketHandler.(package private) voidreceiveRelayResponse(PeerState2 bob, long nonce, int code, byte[] data) We are Alice, we sent a RelayRequest to Bob and got a RelayResponse back.(package private) voidreceiveRetry(OutboundEstablishState2 state, UDPPacket packet) Got a Retry (in response to our outbound SessionRequest or TokenRequest)(package private) voidreceiveSessionConfirmed(InboundEstablishState2 state, UDPPacket packet) Got a SessionConfirmed, should only happen as part of an inbound establishment.(package private) voidreceiveSessionCreated(OutboundEstablishState2 state, UDPPacket packet) Got a SessionCreated (in response to our outbound SessionRequest)(package private) voidGot a SessionDestroy - maybe during an inbound establish?(package private) voidreceiveSessionDestroy(RemoteHostId from, OutboundEstablishState state) Got a SessionDestroy during outbound establish(package private) voidreceiveSessionDestroy(RemoteHostId from, PeerState state) Got a SessionDestroy on an established conn(package private) voidreceiveSessionOrTokenRequest(RemoteHostId from, InboundEstablishState2 state, UDPPacket packet) Got a SessionRequest OR a TokenRequest (initiates an inbound establishment)(package private) static OutboundEstablishState2.IntroStaterelayResponseIntroState(int code) The intro state to record for a relay response, by response code: 0 means Charlie accepted, codes 1-63 mean Bob (the introducer) rejected, and codes 64+ mean Charlie rejected.private voidWrite unused intro tokens to disk.private voidSSU 2.private voidsendCreated(InboundEstablishState state) This handles both initial send and retransmission of Session Created, and, for SSU2, send of Retry.private voidsendInboundComplete(PeerState peer) Send our info immediately, bundled with the ACK of packet 0.private booleansendRelayRequest(long tag, PeerState2 bob, OutboundEstablishState charlie) We are Alice, send a RelayRequest to Bob.private voidThis handles both initial send and retransmission of SessionRequest, and, for SSU2, initial send and retransmission of Token Request.private voidsendTerminationPacket(RemoteHostId to, UDPPacket fromPacket, int terminationCode) Send a Retry packet with a termination code, for a rejection of a session/token request.static voidsetDefaultHighMaxConcurrentEstablish(int val) The default high max concurrent establish, bounded 64-8192.static voidsetDefaultLowMaxConcurrentEstablish(int val) The default low max concurrent establish, bounded 32-4096.static voidsetMaxConcurrentEstablish(int val) Set the max concurrent establish (called by Tuner).static voidsetMaxQueuedOutbound(int max) The max queued outbound connections (called by Tuner).booleanShould we allow another inbound establishment?(package private) static booleanshouldFailObState(boolean expired, long lastSentTime, long timeoutMs, long now) Should the outbound establish state be processed as expired, either because its lifetime is over or because it has been unanswered for the message timeout?(package private) static booleanshouldLogCorruptConfirm(long now) Whether to emit a corrupt-SessionConfirmed report now, counting any skipped.(package private) static booleanshouldLogInboundGiveup(long now) Whether to emit an inbound give-up report now, counting any skipped.(package private) static booleanshouldQueueOutbound(boolean queueIfMaxExceeded, int activeCount, int maxConcurrent) Should the message be put on the deferred queue instead of starting a new outbound state? Only when queueing is requested and the active outbound establish count is at or above the configured cap.(package private) static booleanshouldRejectQueue(boolean peerAlreadyQueued, int queuedOutboundSize, int maxQueued) Should the queued message be rejected outright rather than queued? True when the global deferred queue is at capacity and this peer does not already have a queue we could append to.(package private) static booleanDetermines whether the given Throwable (or any of its causes) contains a message that should be suppressed from logging.voidshutdown()Shut down the establishment manager.voidstartup()Start the establishment manager.private voidupdateHolePunchState(OutboundEstablishState state, OutboundEstablishState2 state2, byte[] data, int port, long now, long token) Update the state with the validated Charlie address, and swap the RemoteHostId the state is indexed under if this was a HolePunch before the RelayResponse.private intvalidateHolePunchAddress(OutboundEstablishState state, RemoteHostId id, byte[] data) Validate the IP and port Charlie claims in the signed data.private byte[]verifyIntroducerSignature(OutboundEstablishState state, OutboundEstablishState2 state2, EstablishmentManager.HPCallback cb) Validate the introducer signature on the HolePunch, by trying each introducer in a state that may have signed it.
Field Details
_context
The router context._log
Logger for SSU connection establishment._transport
The SSU transport we serve._networkID
private final int _networkIDThe network id we communicate on._banLogger
Records why routers were banned._builder2
Builder for SSU2 packets._outboundTokens
Tokens we hold for hosts we contact._inboundTokens
Tokens issued to hosts that contacted us._terminationCounter
Counts termination messages per host._inboundTokenLifetimeStat
Cached "udp.inboundTokenLifetime" RateStat handle. Registered in the constructor and never replaced, so it is resolved once rather than on everygetInboundToken(RemoteHostId)call: that path is reachable from an unauthenticated inbound Token Request, so the stat lookup (a name-based map get followed by a synchronized read of the Rate) was attacker triggerable. Resolved lazily because a test may construct this manager before the stat exists._inboundStates
Map of RemoteHostId to InboundEstablishState._outboundStates
Map of RemoteHostId to OutboundEstablishState. The key could be either an IP/Port (for direct) or a Hash (for indirect, before the RelayResponse is received). Once the RelayResponse is received we change the key._queuedOutbound
Map of RemoteHostId to a bounded, thread-safe queue of OutNetMessage instances for peers whose outbound establishment is pending due to concurrency limits. Each queue is capped atMAX_QUEUED_PER_PEERmessages. Thread-safe: no external synchronization required._liveIntroductions
Map of nonce (Long) to OutboundEstablishState. Only for indirect, before we receive the RelayResponse. This is so we can lookup state for the RelayResponse. After we receive the relay response, _outboundStates is keyed by actual IP._outboundByClaimedAddress
Map of claimed IP/port to OutboundEstablishState. Only for indirect, before we receive the RelayResponse. This is so we can lookup a pending introduction by IP even before we know the "real" IP, so we can match an inbound packet. After we receive the relay response, _outboundStates is keyed by actual IP._outboundByHash
Map of router hash to OutboundEstablishState. Only for indirect, after we receive the RelayResponse. This is so we can lookup a pending connection by Hash even after we've got the IP/port, so we can match a subsequent outbound packet. Before we receive the relay response, _outboundStates is keyed by hash._inboundBans
Temporary inbound bans after previous IB failure, to prevent excessive DH. SSU 2. Value is expiration time._alive
private volatile boolean _aliveFalse once the manager has shut down._activityLock
Lock for the establishment activity count._activity
private int _activityEstablishment attempts currently in flight.DEFAULT_MAX_CONCURRENT_ESTABLISH
private final int DEFAULT_MAX_CONCURRENT_ESTABLISHMax outbound in progress - max inbound is half of this._defaultLowMaxConcurrentEstablish
private static volatile int _defaultLowMaxConcurrentEstablishDefault concurrent establishments for a low profile._defaultHighMaxConcurrentEstablish
private static volatile int _defaultHighMaxConcurrentEstablishDefault concurrent establishments for a high profile.PROP_MAX_CONCURRENT_ESTABLISH
Config key for the concurrent establishment limit.- See Also:
_tunedMaxConcurrentEstablish
private static volatile int _tunedMaxConcurrentEstablishTuned max concurrent establish, -1 = use config. Set by Tuner.MAX_QUEUED_OUTBOUND
private static volatile int MAX_QUEUED_OUTBOUNDMax pending outbound connections (waiting because we are at MAX_CONCURRENT_ESTABLISH).MAX_QUEUED_PER_PEER
private static final int MAX_QUEUED_PER_PEERMax queued msgs per peer while peer connection is queued.- See Also:
BAN_DURATION_INVALID_ADDRESS_MS
private static final long BAN_DURATION_INVALID_ADDRESS_MSBan duration for a peer that supplied an invalid or spoofed SSU address, an unusable MTU, or a bad introduction key.- See Also:
MAX_NONCE
private static final long MAX_NONCELargest possible handshake nonce value.- See Also:
MAX_OB_ESTABLISH_TIME
Kill any outbound that takes more than this. Two round trips (Req-Created-Confirmed-Data) for direct; 3 1/2 round trips (RReq-RResp+Intro-HolePunch-Req-Created-Confirmed-Data) for indirect. Tuned to ~3-5x average establish time. The Tuner further adjusts this at runtime.MAX_IB_ESTABLISH_TIME
Kill any inbound that takes more than this. One round trip (Created-Confirmed), possibly two for SSU2 with retry. Tuned to ~3-5x average establish time; the Tuner further adjusts this at runtime.IB_RETRY_SENT_MAX_TIME
private static final long IB_RETRY_SENT_MAX_TIMEInbound retry-sent limit: how long we wait to get a session request back after a retry, before giving up (5x the retransmit delay).OB_RETRY_EXTRA_MS
private static final long OB_RETRY_EXTRA_MSExtra establishment budget granted to an outbound attempt once a resend has been scheduled and still failed.Additive rather than an absolute like the inbound
IB_RETRY_SENT_MAX_TIME. The inbound figure is 5x its retransmit delay, but the outbound delay is 300ms against the inbound 1000ms, so 5x would be 1500ms - already below the base deadline and therefore incapable of ever binding. An additive extension expresses the same intent at either delay: give a peer that missed our first messages more room, without extending the attempts that never got a reply to begin with.- See Also:
CORRUPT_CONFIRM_LOG_INTERVAL_MS
static final long CORRUPT_CONFIRM_LOG_INTERVAL_MSMinimum gap between "Corrupt SessionConfirmed" reports.This one warning was 9.2% of an entire log - roughly 180 lines a minute - and it carries no reason, so the volume bought no information. Two causes are folded into this one catch: a peer that legitimately failed the handshake and then sent SessionConfirmed anyway, which throws IllegalStateException on an already-FAILED state and is ordinary race behaviour; and a genuine key or payload rejection. They need opposite responses, so the reason is now reported and repeats are counted.
- See Also:
INBOUND_GIVEUP_LOG_INTERVAL_MS
static final long INBOUND_GIVEUP_LOG_INTERVAL_MSMinimum gap between inbound establishment give-up reports. @since 0.9.71+.- See Also:
_lastInboundGiveupLog
When the inbound giveup was last logged._inboundGiveupSuppressed
Giveup logs suppressed since the last one._lastCorruptConfirmLog
When a corrupt confirm was last logged._corruptConfirmSuppressed
Corrupt confirm logs suppressed since the last one.SLOW_ESTABLISH_MS
static final long SLOW_ESTABLISH_MSCompletion time above which a handshake counts as slow.The recorded
udp.*EstablishTimestats only expose a mean, and the mean is useless for sizing the deadline: measured live, successful outbound handshakes average 196ms, so 4x the mean targets 784ms - below the 2250 that abandoned 117 handshakes a minute. Latency here is heavily right-skewed, and the abandonments came from the tail, not the body. This threshold marks the tail so a tuner has something to read. It sits a quarter of the validated floor, so a healthy link records none.- See Also:
OB_MESSAGE_TIMEOUT
public static final long OB_MESSAGE_TIMEOUTMax wait before receiving a response to a single message during outbound establishment.- See Also:
DATA_MESSAGE_TIMEOUT
For the DSM and or netdb store.IB_BAN_TIME
private static final long IB_BAN_TIMEHow long an inbound establishment failure bans a peer.- See Also:
MIN_TOKENS
private static final int MIN_TOKENSFewest tokens issued to one host.MAX_TOKENS
private static final int MAX_TOKENSMost tokens issued to one host.IB_TOKEN_EXPIRATION
public static final long IB_TOKEN_EXPIRATIONHow long an inbound token stays valid, in milliseconds.- See Also:
MAX_SKEW
private static final long MAX_SKEWMaximum clock skew accepted in a handshake.- See Also:
TOKEN_FILE
File holding the SSU2 tokens across restarts.- See Also:
MAX_TERMINATIONS
private static final int MAX_TERMINATIONSMax immediate terminations to send to a peer every FAILSAFE_INTERVAL.- See Also:
MAX_TAG_VALUE
public static final long MAX_TAG_VALUEThe relay tag is a 4-byte field in the protocol.- See Also:
Constructor Details
EstablishmentManager
Creates the establishment manager.- Parameters:
ctx- the router contexttransport- the transport we establish sessions for
Method Details
getDefaultLowMaxConcurrentEstablish
public static int getDefaultLowMaxConcurrentEstablish()The default low max concurrent establish.- Returns:
- the default cap on concurrent outbound sessions before scaling
setDefaultLowMaxConcurrentEstablish
public static void setDefaultLowMaxConcurrentEstablish(int val) The default low max concurrent establish, bounded 32-4096.- Parameters:
val- the desired max concurrent outbound sessions, clamped to 32-4096
getDefaultHighMaxConcurrentEstablish
public static int getDefaultHighMaxConcurrentEstablish()The default high max concurrent establish.- Returns:
- the default ceiling on concurrent outbound sessions
setDefaultHighMaxConcurrentEstablish
public static void setDefaultHighMaxConcurrentEstablish(int val) The default high max concurrent establish, bounded 64-8192.- Parameters:
val- the desired max concurrent outbound sessions, clamped to 64-8192
setMaxConcurrentEstablish
public static void setMaxConcurrentEstablish(int val) Set the max concurrent establish (called by Tuner).- Parameters:
val- the max concurrent outbound sessions
getMaxConcurrentEstablishTuned
The max concurrent establish in effect, tuned value if set else config.- Parameters:
ctx- the router context- Returns:
- the max concurrent outbound sessions
getMaxQueuedOutbound
public static int getMaxQueuedOutbound()The current max queued outbound connections.- Returns:
- the limit currently in effect
setMaxQueuedOutbound
public static void setMaxQueuedOutbound(int max) The max queued outbound connections (called by Tuner).- Parameters:
max- the maximum number of queued connections
getMaxIbEstablishTime
static long getMaxIbEstablishTime()The inbound establishment base deadline, as the Tuner has it set.Exposed so the inbound state machine can schedule its next send from the same budget the expiry check uses. When those two were derived independently they drifted, and a state could become due for a retransmission while still short of its deadline - which the establisher then spun through, retransmitting and logging at WARN on every pass.
- Returns:
- the base deadline in milliseconds
getIbRetrySentMaxTime
static long getIbRetrySentMaxTime()The extended budget an inbound attempt gets once it has sent a retry.- Returns:
- the retry budget in milliseconds
inboundEstablishBudget
static long inboundEstablishBudget(boolean isRetrySent, long maxEstablishTime, long retrySentMaxTime) The deadline an inbound attempt was actually given.This was written as a disjunction -
lifetime > base || (retried && lifetime >= retryBudget)- which never extended anything. The first clause expires the attempt at the base on its own, so the second could only matter when the retry budget was the smaller of the two, and then it made a retried attempt die sooner. Observed live: with a 4000ms base and a 3750ms retry budget, a retried attempt died at 3751ms.The predicate now asks this method for the deadline, so the two cannot disagree and the retry budget means what
IB_RETRY_SENT_MAX_TIMEexists for: five retransmit delays of extra patience for an attempt that has already tried again.- Parameters:
isRetrySent- true if the attempt had already sent a retrymaxEstablishTime- the base deadlineretrySentMaxTime- the extended budget available after a retry- Returns:
- the effective deadline in milliseconds
shouldLogInboundGiveup
static boolean shouldLogInboundGiveup(long now) Whether to emit an inbound give-up report now, counting any skipped.- Parameters:
now- current time in milliseconds- Returns:
- true if the caller should log; false if the event was only counted
getInboundGiveupSuppressed
static long getInboundGiveupSuppressed()Inbound give-up events rate-limited away since the last report.- Returns:
- the number of suppressed give-up events
shouldLogCorruptConfirm
static boolean shouldLogCorruptConfirm(long now) Whether to emit a corrupt-SessionConfirmed report now, counting any skipped.- Parameters:
now- current wall clock- Returns:
- true if this caller should log; false if the event was only counted
getCorruptConfirmSuppressed
static long getCorruptConfirmSuppressed()How many corrupt-SessionConfirmed events were rate-limited away.- Returns:
- suppressed event count since the last emitted report
corruptConfirmReason
The reason a SessionConfirmed was rejected, for the log line. The RuntimeException and GeneralSecurityException wrappers just re-throw the real handshake failure, so report the root cause.- Parameters:
e- the exception thrown out of the handshake- Returns:
- a short, single-line description including the exception type
startup
public void startup()Start the establishment manager.shutdown
public void shutdown()Shut down the establishment manager.getInboundState
Grab the active establishing state.- Parameters:
from- the peer's IP and port, keying the inbound state map- Returns:
- null if none
getOutboundState
Grab the active establishing state.- Parameters:
from- the peer's IP and port, tried against the claimed and hash-keyed maps- Returns:
- null if none
getMaxConcurrentEstablish
private int getMaxConcurrentEstablish()How many concurrent outbound sessions to deal with.- Returns:
- the max concurrent establish
isBanlisted
Is the router with the given hash banlisted under any active ban? Null-safe. Shared by the establish, receiveSessionOrTokenRequest, and handleInbound confirmed-complete paths. Any active ban - temporary, hostile, or permanent - blocks inbound SSU2 connections: a banlisted peer is one the local router does not talk to at all (inbound or outbound) until the ban expires.Banlist.isBanlisted(Hash)returns true for every non-expired entry, so it covers all tiers.- Parameters:
banlist- the router's banlisth- the peer hash, may be null- Returns:
- true if the peer has an active ban of any tier
isBlocklisted
Is the given IP address in the router's blocklist? Null-safe. Shared by the session/establish and hole-punch paths.- Parameters:
blocklist- the router's blocklistip- the IP address, may be null- Returns:
- true if the IP is blocklisted
hasUsefulMessage
Does the exception carry a message worth showing to the user? Legacy code stores the string "null" in the message.- Parameters:
t- may be null- Returns:
- true if a useful message is present
canBeSigner
Can the given introducer have signed the relay response? A peer that was never contacted, terminated the session, or explicitly rejected the hole punch cannot be the signer.- Parameters:
istate- the intro state- Returns:
- true if the introducer may be the signer
isWrongNetwork
static boolean isWrongNetwork(int id, int ourNetworkId) Is the peer's network ID one we will not establish to? The router communicates only with peers in its own network.- Parameters:
id- the peer's network IDourNetworkId- this router's network ID- Returns:
- true if the network IDs differ
isUnspecifiedNetwork
static boolean isUnspecifiedNetwork(int id) Is the peer's network ID unset (i.e. the legacy -1)? Used to pick the ban reason and duration whenisWrongNetwork(int, int)rejects the peer: unset networks get a shorter temporary ban, while a present-but-different network ID is banned indefinitely.- Parameters:
id- the peer's network ID- Returns:
- true if the ID is the "no network specified" sentinel
isUsableUDPAddress
Is the claimed address usable for a direct connection? A null address or a port outside 1-65535 is useless to us.- Parameters:
remAddr- the claimed host address, may be nullport- the claimed port- Returns:
- true if the address can be used directly
isInvalidPeerIP
static boolean isInvalidPeerIP(boolean isValid, boolean equalsExternalIP, boolean allowLocal) Is the claimed IP address unusable, either because it isn't a routable public address or because it is ours without local connections allowed? The caller supplies the per-transport validity and "equals external IP" booleans so this stays a pure decision.- Parameters:
isValid- the transport's verdict on the addressequalsExternalIP- true if the address equals the router's external IPallowLocal- true if local connections are permitted- Returns:
- true if the address must be rejected
needsIndirect
static boolean needsIndirect(boolean hasIntroducers, boolean noDirectAddress) Should this establish use the peer's introducers rather than the claimed address? True when the peer offers introducers or when no usable direct address was found.- Parameters:
hasIntroducers- true if the address advertises introducersnoDirectAddress- true if no claimed address was usable- Returns:
- true to establish indirectly
shouldQueueOutbound
static boolean shouldQueueOutbound(boolean queueIfMaxExceeded, int activeCount, int maxConcurrent) Should the message be put on the deferred queue instead of starting a new outbound state? Only when queueing is requested and the active outbound establish count is at or above the configured cap.- Parameters:
queueIfMaxExceeded- true normally, false when called from locked_admitactiveCount- the current number of outbound establish statesmaxConcurrent- the configured cap- Returns:
- true to queue the message
shouldRejectQueue
static boolean shouldRejectQueue(boolean peerAlreadyQueued, int queuedOutboundSize, int maxQueued) Should the queued message be rejected outright rather than queued? True when the global deferred queue is at capacity and this peer does not already have a queue we could append to.- Parameters:
peerAlreadyQueued- true if this peer already has a deferred queuequeuedOutboundSize- the global deferred queue countmaxQueued- the global queue cap- Returns:
- true to reject the message
queueAtCapacity
static boolean queueAtCapacity(int queueCount, int maxPerPeer) Has this peer's deferred queue hit its per-peer cap?- Parameters:
queueCount- the number of messages now queued for the peermaxPerPeer- the per-peer queue cap- Returns:
- true if the queue is at capacity
nextIntroStateforPeerCheck
static OutboundEstablishState2.IntroState nextIntroStateforPeerCheck(OutboundEstablishState2.IntroState istate, boolean peerPresent, boolean peerSupported) Advance an introducer's state based on whether we already hold a live PeerState for it. Handles the connected-peer walk inhandlePendingIntro(OutboundEstablishState): an INIT/CONNECTING intro that resolves to a live peer becomes CONNECTED when the peer speaks a supported version, otherwise REJECTED (cross-version relaying is not implemented yet), and a CONNECTED intro whose peer has gone away becomes DISCONNECTED.- Parameters:
istate- the current intro statepeerPresent- true if a live PeerState was foundpeerSupported- true if the peer advertises a supported SSU2 version- Returns:
- the advanced intro state (unchanged for states not handled here)
nextIntroStateforLocalLookup
static OutboundEstablishState2.IntroState nextIntroStateforLocalLookup(OutboundEstablishState2.IntroState istate, boolean riFound) Advance an introducer's state based on a local RouterInfo lookup. Only intros we are allowed to connect to (INIT, LOOKUP_SENT, HAS_RI) are advanced, and only to HAS_RI when a local RouterInfo is known; every other state is returned unchanged.- Parameters:
istate- the current intro stateriFound- true if a RouterInfo was found locally- Returns:
- the advanced intro state (unchanged unless a local RI is found)
isUsableUDPAddress
static boolean isUsableUDPAddress(byte[] ip, int port) Is a raw IP/port pair usable to try a direct connection to an introducer? Identity withisUsableUDPAddress(InetAddress, int)except operating on the already-extracted address bytes.- Parameters:
ip- the address bytes, may be nullport- the claimed UDP port, valid 1-65535- Returns:
- true if the address can be used
isTerminalOutboundState
Is the outbound establish state in a terminal state that should be dropped and processed (completed or failed) rather than retried? Guards the scan loop inhandleOutbound().- Parameters:
state- the outbound state- Returns:
- true for CONFIRMED_COMPLETELY or VALIDATION_FAILED
hasObMessageTimedOut
static boolean hasObMessageTimedOut(long lastSentTime, long timeoutMs, long now) Has the outbound state gone unanswered for at least the message timeout? A zero/unknown send time never counts as timed out. Shared by the REQUEST_SENT / CONFIRMED_PARTIALLY / PENDING_INTRO dispatch arms inhandleOutbound().- Parameters:
lastSentTime- the time we last sent, 0 if nevertimeoutMs- the per-message timeoutnow- current time in milliseconds- Returns:
- true if a message was sent and has been unanswered too long
shouldFailObState
static boolean shouldFailObState(boolean expired, long lastSentTime, long timeoutMs, long now) Should the outbound establish state be processed as expired, either because its lifetime is over or because it has been unanswered for the message timeout?- Parameters:
expired- true if the state's lifetime is exhaustedlastSentTime- the time we last sent, 0 if nevertimeoutMs- the per-message timeoutnow- current time in milliseconds- Returns:
- true to process the state as expired
isSendDue
static boolean isSendDue(long nextSendTime, long now) Is the state due to send now (its next send time has arrived)?- Parameters:
nextSendTime- the scheduled send timenow- current time in milliseconds- Returns:
- true if the send is due
hasOutboundEstablishExpired
static boolean hasOutboundEstablishExpired(long lifetime, boolean hasRetried, long maxEstablishTime, long retryExtraMs) Whether an outbound establishment attempt has run out of time.Mirrors
hasInboundEstablishExpired(long, boolean, long, long)for the outbound direction, which until now had no equivalent: the outbound deadline was a flatlifetime >= MAX_OB_ESTABLISH_TIMEwith no retry grace, while the inbound side got up toIB_RETRY_SENT_MAX_TIMEonce a retry was sent. That made the direction which retransmits three times faster (300ms against 1000ms) the one held to the shorter patience, and it is the direction the SSU2 token exchange - one round trip more than SSU1 - runs through.- Parameters:
lifetime- how long the attempt has been alive, in millisecondshasRetried- true if a resend has already been scheduledmaxEstablishTime- the base deadline, normallyMAX_OB_ESTABLISH_TIMEretryExtraMs- additional budget granted once a resend has failed- Returns:
- true if the attempt should be abandoned
hasInboundEstablishExpired
static boolean hasInboundEstablishExpired(long lifetime, boolean isRetrySent, long maxEstablishTime, long retrySentMaxTime) Has the inbound establish state lived long enough to be expired, either past the overall establish cap or, when we are waiting for a session request after sending a retry, past the retry-sent limit?- Parameters:
lifetime- how long the state has existed, in millisecondsisRetrySent- true if the state is waiting in IB_STATE_RETRY_SENTmaxEstablishTime- the overall inbound establish capretrySentMaxTime- the extra cap applied only to retry-sent states- Returns:
- true if the inbound state should be expired
isBobRelayReject
static boolean isBobRelayReject(int code) Is this a rejection from the introducer (Bob) rather than from Charlie or a success? SSU2 relay response codes 1-63 reject at the introducer layer. 0 is success and >= 64 reject at the destination (Charlie). Both the live-introduction map handling and the signer selection inreceiveRelayResponse(PeerState2, long, int, byte[])branch on this.- Parameters:
code- the relay response code- Returns:
- true if the introducer rejected the request
relayResponseIntroState
The intro state to record for a relay response, by response code: 0 means Charlie accepted, codes 1-63 mean Bob (the introducer) rejected, and codes 64+ mean Charlie rejected.- Parameters:
code- the relay response code- Returns:
- the matching intro state; State selection must mirror
isBobRelayReject(int)
isBadRelayDataAddress
static boolean isBadRelayDataAddress(boolean validPort, boolean validIP, boolean tooClose, boolean sameAsIntroducer, boolean blocklisted) Is the claimed relay address unacceptable, meaning Charlie asked us to connect somewhere invalid, too close, on our own network, or a blocklisted address? Finding the introducer's own IP in the claim is also rejection-worthy (a relay must not send us back to itself).- Parameters:
validPort- whether the port is in rangevalidIP- whether the transport accepts the addresstooClose- whether the address is too close to ourssameAsIntroducer- whether the address is Bob's own IPblocklisted- whether the address is in the blocklist- Returns:
- true if any check fails
hasValidV2Introducer
Does the SSU2 address advertise at least one usable v2 introducer, meaning a hash that hasn't expired (expiration 0 means never expires)? Used bycreateOutboundState(OutNetMessage, RemoteHostId, RemoteHostId, RouterIdentity, boolean, UDPAddress, RouterAddress, Hash, String, String, int, long, boolean)before building a state for an indirect peer, since without any current introducer the establishment can never succeed.- Parameters:
addr- the peer's addressnow- the current time- Returns:
- true if any introducer hash is present and unexpired
isMtuTooSmall
static boolean isMtuTooSmall(int mtu, int ourMTU) Is either our MTU or the peer's advertised MTU below the minimum usable for SSU2? MTUs of 0 are treated as unknown and pass, matching the original inline check.- Parameters:
mtu- the peer's advertised MTUourMTU- our MTU for the same address family- Returns:
- true if either is positive and below
PeerState2.MIN_MTU
establish
Send the message to its specified recipient by establishing a connection with them and sending it off. This call does not block, and on failure, the message is failed.Note - if we go back to multiple PacketHandler threads, this may need more locking.
- Parameters:
msg- the outbound message to send, queued if we are at the concurrency limit
establish
Establishes a connection to send the message, or queues it if the limit is exceeded.- Parameters:
msg- the outbound message to send, queued if we are at the concurrency limitqueueIfMaxExceeded- true normally, false if called from locked_admit so we don't loop
queueToInboundState
Queue the message on an inbound establish state that's already in progress, or send/fail it immediately if the state is already complete or failed.- Parameters:
inState- non-nullmsg- the outbound message to queue on the state, or send or fail right away if the state is already finished
lookupOutboundState
Look up an existing outbound establish state for the peer, first by address, then by hash (for indirect connections).- Parameters:
to- the claimed address or hash key the state is filed undertoHash- the peer's router hash, the fallback key tried when the address key misses- Returns:
- the state, or null if none
createOutboundState
private OutboundEstablishState createOutboundState(OutNetMessage msg, RemoteHostId to, RemoteHostId maybeTo, RouterIdentity toIdentity, boolean isIndirect, UDPAddress addr, RouterAddress ra, Hash toHash, String truncHash, String ipAddress, int maybePort, long now, boolean isBanned) Create a new outbound establish state for the peer, after verifying that its introducers, MTU, and introduction key are usable. On failure, marks the peer unreachable and fails the message, banning the peer if it isn't already banned.- Parameters:
msg- the outbound message to fail if the peer turns out to be unusableto- the key in _outboundStates: the claimed address (direct) or the hash (indirect)maybeTo- the claimed address, or null if indirecttoIdentity- the peer's router identity, stored in the new stateisIndirect- true to reach the peer through an introducer, so a valid v2 introducer is requiredaddr- the peer's parsed SSU address options, source of the MTU and the introducer listra- the peer's router address entry, source of the SSU version, transport style and introduction key optiontoHash- the peer's router hash, used for bans and unreachable markingtruncHash- the first 6 base64 chars of toHash, for logging onlyipAddress- the claimed IP as text, empty when there is no claimed addressmaybePort- the claimed port, 0 when there is no claimed addressnow- the current time in ms, used for the introducer validity checkisBanned- true if the peer is already banlisted, so no new ban is added- Returns:
- the new state, or null if the message was failed
banAndFail
private void banAndFail(OutNetMessage msg, Hash toHash, String failReason, String banReason, String noHashWarn, String ipAddress, int port, String truncHash, long banDuration, long now, boolean isBanned) Mark the peer unreachable and fail the message. If the peer is known (has a hash) and not already banned, ban it for the given duration and log a warning; otherwise warn that the claimed address is bad.- Parameters:
msg- the outbound message to failtoHash- the peer's router hash, or null when the peer cannot be named, in which case no ban is recordedfailReason- reason given to the failed messagebanReason- reason used for the ban and the ban lognoHashWarn- warning text used when the peer has no hashipAddress- the claimed IP, may be empty for indirect peersport- the claimed porttruncHash- the first 6 base64 chars of toHash, for the warning logbanDuration- ban duration in ms, e.g.BAN_DURATION_INVALID_ADDRESS_MSnow- the current time in ms, the base for the ban's expiryisBanned- true if the peer is already banlisted, so no new ban is added
getMaxInboundEstablishers
private int getMaxInboundEstablishers()How many concurrent inbound sessions to deal with.- Returns:
- the max inbound establishers
shouldAllowInboundEstablishment
public boolean shouldAllowInboundEstablishment()Should we allow another inbound establishment?- Returns:
- whether allow inbound establishment
receiveSessionOrTokenRequest
void receiveSessionOrTokenRequest(RemoteHostId from, InboundEstablishState2 state, UDPPacket packet) Got a SessionRequest OR a TokenRequest (initiates an inbound establishment)SSU 2 only.
- Parameters:
from- the sender's IP and port, not yet a trusted peer identitystate- as looked up inPacketHandler, but null unless retransmitted or retry sentpacket- header decrypted only
sendTerminationPacket
Send a Retry packet with a termination code, for a rejection of a session/token request. No InboundEstablishState2 required.SSU 2 only. The inbound packet was superficially validated for type, netID, and version, so we have basic probing resistance. The Retry packet encryption is low-cost, chacha only.
Rate limited to MAX_TERMINATIONS per peer every FAILSAFE_INTERVAL.
- Parameters:
to- the peer's address to reject, ignored if null or banlistedfromPacket- header already decrypted, must be session or token requestterminationCode- SSU2 reason code placed in the Retry packet
receiveSessionConfirmed
Got a SessionConfirmed, should only happen as part of an inbound establishment.SSU 2 only.
- Parameters:
state- non-nullpacket- header decrypted only
receiveSessionCreated
Got a SessionCreated (in response to our outbound SessionRequest)SSU 2 only.
- Parameters:
state- non-nullpacket- header decrypted only
receiveRetry
Got a Retry (in response to our outbound SessionRequest or TokenRequest)SSU 2 only.
- Parameters:
state- the outbound attempt that our Retry went to, null if we sent nonepacket- header decrypted only, the Retry itself is parsed by the state
receiveSessionDestroy
Got a SessionDestroy on an established connSSU 2.
- Parameters:
from- the sender, logged only - the authenticated state decides what to dropstate- the established session to tear down
receiveSessionDestroy
Got a SessionDestroy during outbound establishSSU 2.
- Parameters:
from- the sender, which keys the outbound state to abandonstate- the outbound attempt being torn down
receiveSessionDestroy
Got a SessionDestroy - maybe during an inbound establish?A SessionDestroy received before a session exists is only informational: there is no state to drop, and a peer that never completed an establishment has nothing to tear down. The inbound establish is abandoned by its own IES2 timeout rather than by this packet, which is why there is no inbound-state lookup here.
As this packet was essentially unauthenticated (i.e. intro key, not session key) we just log it as it could be spoofed.
SSU 2.
- Parameters:
from- the unauthenticated sender, logged only as it may be spoofed
isPeerBanned
Is the peer on the blocklist or banlist?- Parameters:
hostId- the peer's address and hash to test- Returns:
- true if the peer's IP is blocklisted or its hash is banlisted
isPeerBanned
Is the peer on the blocklist or banlist?- Parameters:
hostId- the peer's address and hash to testcontext- what to call the peer in the log line naming the match- Returns:
- true if the peer's IP is blocklisted or its hash is banlisted
isPeerBanned
Is the peer on the blocklist or banlist?- Parameters:
state- the inbound attempt whose peer to test- Returns:
- true if the peer's IP is blocklisted or its hash is banlisted
isPeerBanned
Is the peer on the blocklist or banlist?- Parameters:
state- the outbound attempt whose peer to test- Returns:
- true if the peer's IP is blocklisted or its hash is banlisted
receiveData
A data packet arrived on an outbound connection being established, which means its complete (yay!). This is a blocking call, more than I'd like...- Parameters:
state- the outbound attempt that completed, removed from the pending maps- Returns:
- the new PeerState
locked_admitQueued
private int locked_admitQueued()Move pending outbound messages from_queuedOutboundinto active outbound establishment states. This processes one peer at a time until concurrency limits are reached.- Returns:
- number of peers admitted from the queue
notifyActivity
private void notifyActivity()Records that an establishment attempt happened.handleCompletelyEstablished
Ok, fully received, add it to the established cons and queue up a netDb store to them.- Parameters:
state- the inbound attempt that just completed, an SSU2 state, ignored if it is already marked complete
sendInboundComplete
Send our info immediately, bundled with the ACK of packet 0.The two messages share a packet, so this stays separate from sendAck0() rather than being folded into it: sendAck0() may run before the PeerState exists, and only this path needs the peer's RouterInfo.
- Parameters:
peer- the newly established peer to send our RouterInfo to
handleCompletelyEstablished
Ok, fully received, add it to the established cons and send any queued messages.- Parameters:
state- the outbound attempt that just completed, an SSU2 state- Returns:
- the new PeerState, or null if the state has no remote identity
getOurInfo
A database store message with our router info.- Returns:
- non-null
sendCreated
This handles both initial send and retransmission of Session Created, and, for SSU2, send of Retry. Retry is never retransmitted except in response to a retransmitted Token Request.This may be called more than once.
Caller must synch on state.
- Parameters:
state- the inbound attempt to answer, an SSU2 state whose current inbound state selects which packet is sent
sendRequest
This handles both initial send and retransmission of SessionRequest, and, for SSU2, initial send and retransmission of Token Request.This may be called more than once.
Caller must synch on state.
- Parameters:
state- the outbound attempt to drive, an SSU2 state whose current outbound state selects whether a Token Request or a Session Request is sent
handlePendingIntro
Send RelayRequests to multiple introducers. This may be called multiple times, it sets the nonce the first time only Caller should probably synch on state.SSU 2.
- Parameters:
state- the outbound state to walk through the introducers of; must be anOutboundEstablishState2with at least one valid v2 introducer
sendRelayRequest
We are Alice, send a RelayRequest to Bob.SSU 2 only.
- Parameters:
tag- the per-tunnel introducer tag taken from Charlie's address entry, echoed in the signed request databob- the already-connected introducer's session to askcharlie- must be SSU2- Returns:
- true if the RelayRequest was queued; false if we have no address to send from or the payload could not be signed or written
receiveRelayResponse
We are Alice, we sent a RelayRequest to Bob and got a RelayResponse back. Time and version already checked by caller.SSU 2 only.
- Parameters:
bob- the introducer's established session, we are answering its relaynonce- matches the live introduction we sent, keys the pending outbound statecode- 0 if Charlie accepted, 1-63 if the introducer rejected, 64+ if Charlie rejecteddata- including nonce, including token if code == 0
receiveHolePunch
Called from PacketHandler. Accelerate response to RelayResponse if we haven't sent it yet.SSU 2 only.
- Parameters:
id- non-nullpacket- header already decrypted
isValidHolePunchResponse
private boolean isValidHolePunchResponse(EstablishmentManager.HPCallback cb, long rcvConnID, long now, RemoteHostId id) Validate the decrypted HolePunch payload: response code, clock skew, the nonce echoing the receiving connection ID, the response time, and the version.- Parameters:
cb- payload callback resultsrcvConnID- connection ID this packet was sent tonow- the packet receipt time in millisecondsid- theRemoteHostIdof the sending peer- Returns:
- true if all checks pass
findHolePunchState
Find the outbound establish state this HolePunch belongs to.- Parameters:
id- theRemoteHostIdof the sending peernonce- the nonce from the validated response- Returns:
- the state, or null if unknown
verifyIntroducerSignature
private byte[] verifyIntroducerSignature(OutboundEstablishState state, OutboundEstablishState2 state2, EstablishmentManager.HPCallback cb) Validate the introducer signature on the HolePunch, by trying each introducer in a state that may have signed it.- Parameters:
state- outbound establish statestate2- SSU2-specific state, for intro bookkeepingcb- payload callback results- Returns:
- the signed portion of the response data (everything but the trailing token), or null if Charlie's RouterInfo is unknown or no introducer signature validated
banAndFailState
Ban the peer and fail the outbound establish state for bad introduction data.- Parameters:
state- the outbound establish statereason- the human-readable cause recorded in the banlist and the ban logbanDuration- ban duration in ms
validateHolePunchAddress
Validate the IP and port Charlie claims in the signed data. A port mismatch is tolerated (use the source port, Charlie may be behind a symmetric NAT); an invalid source port is not.- Parameters:
state- the outbound establish stateid- the actual sender of the HolePunchdata- the signed portion of the response- Returns:
- the validated port (possibly the sender's source port), or -1 if the data is invalid
updateHolePunchState
private void updateHolePunchState(OutboundEstablishState state, OutboundEstablishState2 state2, byte[] data, int port, long now, long token) Update the state with the validated Charlie address, and swap the RemoteHostId the state is indexed under if this was a HolePunch before the RelayResponse.- Parameters:
state- the outbound establish statestate2- SSU2-specific statedata- the signed portion of the responseport- the validated portnow- the packet receipt time in millisecondstoken- the token from the end of the full response
isValid
boolean isValid(byte[] ip, int port) Are IP and port valid? This is only for checking the relay response. Allow IPv6 as of 0.9.50. Refuse anybody in the same /16.- Parameters:
ip- the address from the relay response, IPv4 or IPv6, may be nullport- the claimed port, must be a valid 1-65535- Returns:
- true if the address is routable, blocklist-free and not in our own /16
sendConfirmation
SSU 2. For SSU 2, it contains a full router info, so it may be fragmented.Caller must synch on state.
- Parameters:
state- the outbound attempt to confirm, an SSU2 state, failed if its SessionCreated does not validate
handleInbound
private long handleInbound()Drive through the inbound establishment states, adjusting one of them as necessary. Called from Establisher thread only.- Returns:
- next requested time or Long.MAX_VALUE
handleOutbound
private long handleOutbound()Drive through the outbound establishment states, adjusting one of them as necessary. Called from Establisher thread only.- Returns:
- next requested time or Long.MAX_VALUE
processExpired
Caller should probably synch on outboundState.- Parameters:
outboundState- the outbound attempt that timed out; dropped from the pending maps, and its queued messages failed unless the session is already confirmed
processExpired
Caller should probably synch on inboundState.- Parameters:
inboundState- the inbound attempt that timed out; its address is added to the inbound ban map and its queued messages are failed
addOutboundToken
Remember a token that can be used later to connect to the peer.- Parameters:
peer- the peer's address and port, which keys the stored tokentoken- nonzero token value to storeexpires- absolute expiry as milliseconds since the epoch
getOutboundToken
Token to connect to the peer.- Parameters:
peer- the peer's address and port, consuming any stored token- Returns:
- 0 if none available
isConnecting
Check if an outbound SSU handshake is in progress for the given peer.- Parameters:
dest- the remote RouterIdentity hash, as stored in the outbound-by-hash map- Returns:
- true if we are currently trying to establish an outbound connection
ipChanged
public void ipChanged(boolean isIPv6) Remove our tokens for this length.- Parameters:
isIPv6- true if the new address is 16 bytes, false if 4
portChanged
public void portChanged()Remove all tokens.inboundTokenLifetimeStat
Resolves the "udp.inboundTokenLifetime" RateStat, caching the handle.The stat is created in this class's constructor and never replaced, so after the first successful lookup this is a single volatile read. A stat that is not registered yet is not cached, so a later call retries.
- Returns:
- the cached stat, or null if it is not registered yet
getInboundToken
Token that can be used later for the peer to connect to us.- Parameters:
peer- the peer's address and port, at most one live token per peer- Returns:
- the inbound token
getInboundToken
Token that can be used later for the peer to connect to us.- Parameters:
peer- the peer's address and port, at most one live token per peerexpiration- time from now, will be reduced if necessary based on cache eviction time.- Returns:
- non-null
isInboundTokenValid
Is the token from this peer valid?- Parameters:
peer- the peer's address and port, keying the stored tokentoken- the offered value, a match consumes the stored token; 0 always fails- Returns:
- true if it matched and has not expired
loadTokens
private void loadTokens()Not threaded, because we're holding the token cache locks anyway.Format:
4 ourIPv4addr ourIPv4port 6 ourIPv6addr ourIPv6port I addr port token exp O addr port token exp
saveTokens
private void saveTokens()Write unused intro tokens to disk.shouldSuppressException
Determines whether the given Throwable (or any of its causes) contains a message that should be suppressed from logging.- Parameters:
t- the Throwable to check- Returns:
- true if the exception should be suppressed, false otherwise
parseReason
The reason string for an SSU termination code.- Parameters:
reasonCode- the 1-byte termination code, one of the SSU2Util.REASON_ constants- Returns:
- the reason text, or "Unknown error" for an unrecognized code