public abstract class AbstractSession extends SessionHelper
The AbstractSession handles all the basic SSH protocol such as key exchange, authentication, encoding and decoding.
Both server side and client side sessions should inherit from this abstract class. Some basic packet processing
methods are defined but the actual call to these methods should be done from the handleMessage(Buffer)
method, which is dependent on the state and side of this session.
Modifier and Type | Class and Description |
---|---|
private static class |
AbstractSession.KexStart |
protected static class |
AbstractSession.MessageCodingSettings
Message encoding or decoding settings as determined at the end of a key exchange.
|
AbstractCloseable.State
SessionHeartbeatController.HeartbeatType
AttributeRepository.AttributeKey<T>
Modifier and Type | Field and Description |
---|---|
protected ChannelListener |
channelListenerProxy |
protected java.util.Collection<ChannelListener> |
channelListeners
Channel events listener container
|
private byte[] |
clientKexData |
protected java.util.Map<KexProposalOption,java.lang.String> |
clientProposal |
protected java.lang.String |
clientVersion |
protected CurrentService |
currentService |
protected java.lang.Object |
decodeLock |
protected SessionWorkBuffer |
decoderBuffer |
protected int |
decoderLength |
protected int |
decoderState |
protected java.lang.Object |
encodeLock |
protected java.lang.Boolean |
firstKexPacketFollows |
private java.util.Map<Buffer,java.util.function.LongConsumer> |
globalSequenceNumbers |
protected int |
ignorePacketDataLength |
protected java.util.concurrent.atomic.AtomicLong |
ignorePacketsCount |
protected long |
ignorePacketsFrequency |
protected int |
ignorePacketsVariance |
protected java.util.concurrent.atomic.AtomicLong |
inBlocksCount |
protected java.util.concurrent.atomic.AtomicLong |
inBytesCount |
protected Cipher |
inCipher |
protected int |
inCipherSize |
protected Compression |
inCompression |
protected boolean |
initialKexDone |
protected Mac |
inMac |
protected byte[] |
inMacResult |
protected int |
inMacSize |
protected java.util.concurrent.atomic.AtomicLong |
inPacketsCount |
protected AbstractSession.MessageCodingSettings |
inSettings
Resulting message coding settings at the end of a key exchange for incoming messages.
|
protected KeyExchange |
kex |
protected java.util.concurrent.atomic.AtomicReference<DefaultKeyExchangeFuture> |
kexFutureHolder |
protected KeyExchangeMessageHandler |
kexHandler
The
KeyExchangeMessageHandler instance also serves as lock protecting kexState changes from DONE
to INIT or RUN, and from KEYS to DONE. |
protected DefaultKeyExchangeFuture |
kexInitializedFuture |
protected java.util.concurrent.atomic.AtomicReference<KexState> |
kexState
Holds the current key exchange state.
|
protected java.util.concurrent.atomic.AtomicReference<java.time.Instant> |
lastKeyTimeValue |
protected java.util.concurrent.atomic.AtomicLong |
maxRekeyBlocks |
protected long |
maxRekeyBytes |
protected java.time.Duration |
maxRekeyInterval |
protected long |
maxRekyPackets |
protected java.util.Map<KexProposalOption,java.lang.String> |
negotiationResult |
protected java.util.concurrent.atomic.AtomicLong |
outBlocksCount |
protected java.util.concurrent.atomic.AtomicLong |
outBytesCount |
protected Cipher |
outCipher |
protected int |
outCipherSize |
protected Compression |
outCompression |
protected Mac |
outMac |
protected int |
outMacSize |
protected java.util.concurrent.atomic.AtomicLong |
outPacketsCount |
protected AbstractSession.MessageCodingSettings |
outSettings
Resulting message coding settings at the end of a key exchange for outgoing messages.
|
private java.util.Deque<GlobalRequestFuture> |
pendingGlobalRequests
Used to wait for results of global requests sent with
want-reply = true . |
protected Random |
random
The pseudo random generator
|
protected java.lang.Object |
requestLock |
protected long |
seqi
Input packet sequence number.
|
protected long |
seqo
Output packet sequence number.
|
private byte[] |
serverKexData |
protected java.util.Map<KexProposalOption,java.lang.String> |
serverProposal |
protected java.lang.String |
serverVersion |
static java.lang.String |
SESSION
Name of the property where this session is stored in the attributes of the underlying MINA session.
|
protected byte[] |
sessionId |
protected SessionListener |
sessionListenerProxy |
protected java.util.Collection<SessionListener> |
sessionListeners
Session listeners container
|
protected PortForwardingEventListener |
tunnelListenerProxy |
protected java.util.Collection<PortForwardingEventListener> |
tunnelListeners
Port forwarding events listener container
|
protected SessionWorkBuffer |
uncompressBuffer |
protected java.util.Map<KexProposalOption,java.lang.String> |
unmodClientProposal |
protected java.util.Map<KexProposalOption,java.lang.String> |
unmodNegotiationResult |
protected java.util.Map<KexProposalOption,java.lang.String> |
unmodServerProposal |
authStart, idleStart, initialKexProposal
closeFuture, futureLock, state
log
DEFAULT_SSH_VERSION_PREFIX, FALLBACK_SSH_VERSION_PREFIX, MAX_VERSION_LINE_LENGTH
EMPTY
NONE
Modifier | Constructor and Description |
---|---|
protected |
AbstractSession(boolean serverSession,
FactoryManager factoryManager,
IoSession ioSession)
Create a new session.
|
Modifier and Type | Method and Description |
---|---|
void |
addChannelListener(ChannelListener listener)
Add a channel listener
|
void |
addPortForwardingEventListener(PortForwardingEventListener listener)
Add a port forwarding listener
|
void |
addSessionListener(SessionListener listener)
Add a session listener.
|
protected void |
aeadOutgoingBuffer(Buffer buf,
int offset,
int len) |
protected void |
appendOutgoingMac(Buffer buf,
int offset,
int len) |
static void |
attachSession(IoSession ioSession,
AbstractSession session)
Attach an SSH
AbstractSession to the I/O session |
static int |
calculatePadLength(int len,
int blockSize,
boolean etmMode) |
protected abstract void |
checkKeys()
Indicates the the key exchange is completed and the exchanged keys can now be verified - e.g., client can verify
the server's key
|
protected KeyExchangeFuture |
checkRekey()
Checks if a re-keying is required and if so initiates it
|
protected java.util.Map.Entry<java.lang.String,java.lang.String> |
comparePreferredKexProposalOption(KexProposalOption option)
Compares the specified
KexProposalOption option value for client vs. |
Buffer |
createBuffer(byte cmd,
int len)
Create a new buffer for the specified SSH packet and reserve the needed space (5 bytes) for the packet header.
|
protected void |
decode()
Decode the incoming buffer and handle packets as needed.
|
protected long |
determineRekeyBlockLimit(int inCipherBlockSize,
int outCipherBlockSize)
Compute the number of blocks after which we should re-key again.
|
protected void |
doHandleMessage(Buffer buffer) |
protected boolean |
doInvokeUnimplementedMessageHandler(int cmd,
Buffer buffer) |
protected void |
doKexNegotiation() |
protected IoWriteFuture |
doWritePacket(Buffer buffer) |
protected Buffer |
encode(Buffer buffer)
Encode a buffer into the SSH protocol.
|
protected void |
encryptOutgoingBuffer(Buffer buf,
int offset,
int len) |
ChannelListener |
getChannelListenerProxy() |
CipherInformation |
getCipherInformation(boolean incoming)
Retrieves current cipher information - Note: may change if key re-exchange executed
|
protected byte[] |
getClientKexData() |
java.util.Map<KexProposalOption,java.lang.String> |
getClientKexProposals() |
java.lang.String |
getClientVersion()
Retrieve the client version for this session.
|
CompressionInformation |
getCompressionInformation(boolean incoming)
Retrieves current compression information - Note: may change if key re-exchange executed
|
protected Closeable |
getInnerCloseable() |
KeyExchange |
getKex() |
java.util.Map<KexProposalOption,java.lang.String> |
getKexNegotiationResult() |
KexState |
getKexState() |
MacInformation |
getMacInformation(boolean incoming)
Retrieves current MAC information - Note: may change if key re-exchange executed
|
java.lang.String |
getNegotiatedKexParameter(KexProposalOption paramType)
Retrieve one of the negotiated values during the KEX stage
|
PortForwardingEventListener |
getPortForwardingEventListenerProxy() |
protected byte[] |
getServerKexData() |
java.util.Map<KexProposalOption,java.lang.String> |
getServerKexProposals() |
java.lang.String |
getServerVersion()
Retrieve the server version for this session.
|
<T extends Service> |
getService(java.lang.Class<T> clazz)
Get the service of the specified type.
|
protected java.util.List<Service> |
getServices() |
static AbstractSession |
getSession(IoSession ioSession)
Retrieve the SSH session from the I/O session.
|
static AbstractSession |
getSession(IoSession ioSession,
boolean allowNull)
Retrieve the session SSH from the I/O session.
|
byte[] |
getSessionId() |
SessionListener |
getSessionListenerProxy() |
protected boolean |
handleFirstKexPacketFollows(int cmd,
Buffer buffer,
boolean followFlag) |
protected void |
handleKexExtension(int cmd,
Buffer buffer) |
protected void |
handleKexInit(Buffer buffer) |
protected void |
handleKexMessage(int cmd,
Buffer buffer) |
protected void |
handleMessage(Buffer buffer)
Abstract method for processing incoming decoded packets.
|
protected void |
handleNewCompression(int cmd,
Buffer buffer) |
protected void |
handleNewKeys(int cmd,
Buffer buffer) |
protected void |
handleServiceAccept(Buffer buffer) |
protected void |
handleServiceAccept(java.lang.String serviceName,
Buffer buffer) |
protected void |
handleServiceRequest(Buffer buffer) |
protected boolean |
handleServiceRequest(java.lang.String serviceName,
Buffer buffer) |
protected CurrentService |
initializeCurrentService()
Creates a new
CurrentService instance managing this session's current SSH service. |
protected KeyExchangeMessageHandler |
initializeKeyExchangeMessageHandler()
Creates a new
KeyExchangeMessageHandler instance managing packet sending for this session. |
protected boolean |
isRekeyBlocksCountExceeded() |
protected boolean |
isRekeyDataSizeExceeded() |
protected boolean |
isRekeyPacketCountsExceeded() |
protected boolean |
isRekeyRequired() |
protected boolean |
isRekeyTimeIntervalExceeded() |
void |
messageReceived(Readable buffer)
Main input point for the MINA framework.
|
protected java.util.Map<KexProposalOption,java.lang.String> |
negotiate()
Compute the negotiated proposals by merging the client and server proposal.
|
protected IoWriteFuture |
notImplemented(int cmd,
Buffer buffer)
Send a
SSH_MSG_UNIMPLEMENTED packet. |
protected void |
preClose()
preClose is guaranteed to be called before doCloseGracefully or doCloseImmediately.
|
Buffer |
prepareBuffer(byte cmd,
Buffer buffer)
Prepare a new "clean" buffer while reserving the needed space (5 bytes) for the packet header.
|
protected void |
prepareNewKeys()
Prepares the new ciphers, macs and compression algorithms according to the negotiated server and client proposals
and stores them in
inSettings and outSettings . |
protected Buffer |
preProcessEncodeBuffer(int cmd,
Buffer buffer)
Invoked by the session before encoding the buffer in order to make sure that it is at least of size
SSH_PACKET_HEADER_LEN . |
protected abstract boolean |
readIdentification(Buffer buffer)
Read the other side identification.
|
protected byte[] |
receiveKexInit(Buffer buffer) |
protected byte[] |
receiveKexInit(Buffer buffer,
java.util.Map<KexProposalOption,java.lang.String> proposal)
Receive the remote key exchange init message.
|
protected abstract void |
receiveKexInit(java.util.Map<KexProposalOption,java.lang.String> proposal,
byte[] seed) |
KeyExchangeFuture |
reExchangeKeys()
Initiate a new key exchange.
|
protected void |
refreshConfiguration()
Refresh whatever internal configuration is not
final |
void |
removeChannelListener(ChannelListener listener)
Remove a channel listener
|
void |
removePortForwardingEventListener(PortForwardingEventListener listener)
Remove a port forwarding listener
|
void |
removeSessionListener(SessionListener listener)
Remove a session listener.
|
GlobalRequestFuture |
request(Buffer buffer,
java.lang.String request,
GlobalRequestFuture.ReplyHandler replyHandler)
Send a global request and handle the reply asynchronously.
|
Buffer |
request(java.lang.String request,
Buffer buffer,
long maxWaitMillis)
Send a global request and wait for the response, if the request is sent with
want-reply = true . |
protected void |
requestFailure(Buffer buffer)
Indicates the reception of a
SSH_MSG_REQUEST_FAILURE message |
protected KeyExchangeFuture |
requestNewKeysExchange()
Initiates a new keys exchange if one not already in progress
|
protected void |
requestSuccess(Buffer buffer)
Indicates the reception of a
SSH_MSG_REQUEST_SUCCESS message |
protected int |
resolveIgnoreBufferDataLength() |
protected Buffer |
resolveOutputPacket(Buffer buffer) |
protected java.lang.String |
resolveSessionKexProposal(java.lang.String hostKeyTypes) |
protected byte[] |
sendKexInit() |
protected byte[] |
sendKexInit(java.util.Map<KexProposalOption,java.lang.String> proposal)
Send the key exchange initialization packet.
|
protected IoWriteFuture |
sendNewKeys()
Send a message to put new keys into use.
|
protected void |
setClientKexData(byte[] data) |
protected void |
setInputEncoding()
Installs the current prepared
inSettings so that they are effective and will be applied to any future
incoming packet. |
protected abstract void |
setKexSeed(byte... seed) |
protected java.util.Map<KexProposalOption,java.lang.String> |
setNegotiationResult(java.util.Map<KexProposalOption,java.lang.String> guess) |
protected void |
setOutputEncoding()
Installs the current prepared
outSettings so that they are effective and will be applied to any future
outgoing packet. |
protected void |
setServerKexData(byte[] data) |
protected void |
validateIncomingMac(byte[] data,
int offset,
int len) |
protected void |
validateKexState(int cmd,
KexState expected) |
protected boolean |
validateServiceKexState(KexState state) |
protected <B extends Buffer> |
validateTargetBuffer(int cmd,
B buffer)
Makes sure that the buffer used for output is not
null or one of the session's internal ones used for
decoding and uncompressing |
private boolean |
wantReply(Buffer buffer) |
IoWriteFuture |
writePacket(Buffer buffer)
Encode and send the given buffer.
|
IoWriteFuture |
writePacket(Buffer buffer,
long timeout,
java.util.concurrent.TimeUnit unit)
Encode and send the given buffer with the specified timeout.
|
attributeKeys, calculateNextIgnorePacketCount, checkAuthenticationTimeout, checkForTimeouts, checkIdleTimeout, clearAttributes, computeAttributeIfAbsent, createProposal, disconnect, doInvokeDebugMessageHandler, doInvokeIgnoreMessageHandler, doReadIdentification, exceptionCaught, getAttribute, getAttributesCount, getAuthTimeout, getAuthTimeoutStart, getBoundLocalPortForwards, getBoundRemotePortForward, getChannelStreamWriterResolver, getConnectionService, getFactoryManager, getForwarder, getIdleTimeout, getIdleTimeoutStart, getIoSession, getKexProposal, getLocalForwardsBindings, getParentPropertyResolver, getProperties, getRemoteForwardsBindings, getReservedSessionMessagesHandler, getSessionDisconnectHandler, getStartedLocalPortForwards, getStartedRemotePortForwards, getTimeoutStatus, getUnknownChannelReferenceHandler, getUsername, handleDebug, handleDisconnect, handleDisconnect, handleIgnore, handleUnimplemented, invokeSessionSignaller, isAuthenticated, isLocalPortForwardingStartedForPort, isRemotePortForwardingStartedForPort, isServerSession, mergeProposals, removeAttribute, resetAuthTimeout, resetIdleTimeout, resizeKey, resolveAvailableSignaturesProposal, resolveAvailableSignaturesProposal, resolveChannelStreamWriterResolver, resolveIdentificationString, resolvePeerAddress, resolveReservedSessionMessagesHandler, resolveUnknownChannelReferenceHandler, sendDebugMessage, sendIdentification, sendIgnoreMessage, sendNotImplemented, setAttribute, setAuthenticated, setChannelStreamWriterResolver, setReservedSessionMessagesHandler, setSessionDisconnectHandler, setUnknownChannelReferenceHandler, setUsername, signalDisconnect, signalDisconnect, signalExceptionCaught, signalExceptionCaught, signalNegotiationEnd, signalNegotiationEnd, signalNegotiationOptionsCreated, signalNegotiationOptionsCreated, signalNegotiationStart, signalNegotiationStart, signalPeerIdentificationReceived, signalPeerIdentificationReceived, signalReadPeerIdentificationLine, signalReadPeerIdentificationLine, signalSendIdentification, signalSendIdentification, signalSessionClosed, signalSessionClosed, signalSessionCreated, signalSessionCreated, signalSessionEstablished, signalSessionEstablished, signalSessionEvent, signalSessionEvent, toString
getCipherFactories, getCompressionFactories, getDelegate, getKexExtensionHandler, getKeyExchangeFactories, getMacFactories, getSignatureFactories, resolveEffectiveFactories, resolveEffectiveProvider, setCipherFactories, setCompressionFactories, setKexExtensionHandler, setKeyExchangeFactories, setMacFactories, setSignatureFactories
doCloseGracefully, doCloseImmediately
addCloseFutureListener, builder, close, getFutureLock, isClosed, isClosing, removeCloseFutureListener
debug, debug, debug, debug, debug, error, error, error, error, error, getSimplifiedLogger, info, info, warn, warn, warn, warn, warn, warn, warn, warn
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
createBuffer, getLocalAddress, getRemoteAddress, request, request, resolveAttribute, resolveAttribute, startService, writePacket, writePacket
isDataIntegrityTransport, isSecureSessionTransport, isValidSessionPayloadSize, isValidVersionPrefix, validateSessionPayloadSize
disableSessionHeartbeat, getSessionHeartbeatInterval, getSessionHeartbeatType, setSessionHeartbeat, setSessionHeartbeat
getBoolean, getBooleanProperty, getCharset, getInteger, getIntProperty, getLong, getLongProperty, getObject, getString, getStringProperty, isEmpty, isEmpty
ofAttributesMap, ofKeyValuePair
addCloseFutureListener, close, close, close, getMaxCloseWaitTime, isClosed, isClosing, isOpen, removeCloseFutureListener
getCipherFactories, getCipherFactoriesNameList, getCipherFactoriesNames, getCompressionFactories, getCompressionFactoriesNameList, getCompressionFactoriesNames, getKeyExchangeFactories, getMacFactories, getMacFactoriesNameList, getMacFactoriesNames, setCipherFactories, setCipherFactoriesNameList, setCipherFactoriesNames, setCipherFactoriesNames, setCompressionFactories, setCompressionFactoriesNameList, setCompressionFactoriesNames, setCompressionFactoriesNames, setKeyExchangeFactories, setMacFactories, setMacFactoriesNameList, setMacFactoriesNames, setMacFactoriesNames
getSignatureFactories, resolveSignatureFactories, setSignatureFactories, setSignatureFactoriesNameList, setSignatureFactoriesNames, setSignatureFactoriesNames
getSignatureFactories, getSignatureFactoriesNameList, getSignatureFactoriesNames
getKexExtensionHandler, setKexExtensionHandler
resolveChannelStreamWriter
public static final java.lang.String SESSION
getSession(IoSession, boolean)
and attachSession(IoSession, AbstractSession)
.protected final Random random
protected final java.util.Collection<SessionListener> sessionListeners
protected final SessionListener sessionListenerProxy
protected final java.util.Collection<ChannelListener> channelListeners
protected final ChannelListener channelListenerProxy
protected final java.util.Collection<PortForwardingEventListener> tunnelListeners
protected final PortForwardingEventListener tunnelListenerProxy
protected byte[] sessionId
protected java.lang.String serverVersion
protected java.lang.String clientVersion
protected final java.util.Map<KexProposalOption,java.lang.String> serverProposal
protected final java.util.Map<KexProposalOption,java.lang.String> unmodServerProposal
protected final java.util.Map<KexProposalOption,java.lang.String> clientProposal
protected final java.util.Map<KexProposalOption,java.lang.String> unmodClientProposal
protected final java.util.Map<KexProposalOption,java.lang.String> negotiationResult
protected final java.util.Map<KexProposalOption,java.lang.String> unmodNegotiationResult
protected KeyExchange kex
protected java.lang.Boolean firstKexPacketFollows
protected boolean initialKexDone
protected final java.util.concurrent.atomic.AtomicReference<KexState> kexState
protected final java.util.concurrent.atomic.AtomicReference<DefaultKeyExchangeFuture> kexFutureHolder
protected DefaultKeyExchangeFuture kexInitializedFuture
protected Cipher outCipher
protected Cipher inCipher
protected int outCipherSize
protected int inCipherSize
protected Mac outMac
protected Mac inMac
protected int outMacSize
protected int inMacSize
protected byte[] inMacResult
protected Compression outCompression
protected Compression inCompression
protected long seqi
protected long seqo
protected SessionWorkBuffer uncompressBuffer
protected final SessionWorkBuffer decoderBuffer
protected int decoderState
protected int decoderLength
protected final java.lang.Object encodeLock
protected final java.lang.Object decodeLock
protected final java.lang.Object requestLock
protected final KeyExchangeMessageHandler kexHandler
KeyExchangeMessageHandler
instance also serves as lock protecting kexState
changes from DONE
to INIT or RUN, and from KEYS to DONE.protected final java.util.concurrent.atomic.AtomicLong inPacketsCount
protected final java.util.concurrent.atomic.AtomicLong outPacketsCount
protected final java.util.concurrent.atomic.AtomicLong inBytesCount
protected final java.util.concurrent.atomic.AtomicLong outBytesCount
protected final java.util.concurrent.atomic.AtomicLong inBlocksCount
protected final java.util.concurrent.atomic.AtomicLong outBlocksCount
protected final java.util.concurrent.atomic.AtomicReference<java.time.Instant> lastKeyTimeValue
protected long maxRekyPackets
protected long maxRekeyBytes
protected java.time.Duration maxRekeyInterval
protected AbstractSession.MessageCodingSettings inSettings
prepareNewKeys()
,
setInputEncoding()
protected AbstractSession.MessageCodingSettings outSettings
prepareNewKeys()
,
setOutputEncoding()
protected final CurrentService currentService
protected int ignorePacketDataLength
protected long ignorePacketsFrequency
protected int ignorePacketsVariance
protected final java.util.concurrent.atomic.AtomicLong maxRekeyBlocks
protected final java.util.concurrent.atomic.AtomicLong ignorePacketsCount
private final java.util.Deque<GlobalRequestFuture> pendingGlobalRequests
want-reply = true
. Note that per RFC 4254, global
requests may be sent at any time, but success/failure replies MUST come in the order the requests were sent. Some
implementations may also reply with SSH_MSG_UNIMPLEMENTED, on which RFC 4253 says they must be sent in the order
the message was received.
This implies that it is legal to send "nested" global requests: a client or server may send two (or more) global requests, and then receives two (or more) replies in the correct order: first reply for the first request sent; second reply for the second request sent.
We keep a FIFO list of pending global requests for which we expect a reply. We always add new global requests at the head. For success and failure replies, which don't identify the message sequence number of the global request, we apply the reply to the tail of the list. For unimplemented messages, we apply it to the request identified by the message sequence number, which normally also should be the tail.
When a reply is received, the corresponding global request is removed from the list.
Global requests sent with want-reply = false
are never added to this list; they are fire-and-forget.
According to the SSH RFCs, the peer MUST not reply on a message with want-reply = false
. If it does so
all the same, it is broken. We might then apply the result to the wrong pending global request if we have any.
#request(Buffer, String, org.apache.sshd.common.future.GlobalRequestFuture.ReplyHandler)}
,
#requestSuccess(Buffer)}
,
#requestFailure(Buffer)}
,
#doInvokeUnimplementedMessageHandler(int, Buffer)}
,
#preClose()}
private final java.util.Map<Buffer,java.util.function.LongConsumer> globalSequenceNumbers
private byte[] clientKexData
private byte[] serverKexData
protected AbstractSession(boolean serverSession, FactoryManager factoryManager, IoSession ioSession)
serverSession
- true
if this is a server session, false
if client onefactoryManager
- the factory managerioSession
- the underlying I/O sessionprotected KeyExchangeMessageHandler initializeKeyExchangeMessageHandler()
KeyExchangeMessageHandler
instance managing packet sending for this session.
This initialization method is invoked once from the AbstractSession
constructor. Do not rely on subclass
fields being initialized.
KeyExchangeMessageHandler
instance for the sessionprotected CurrentService initializeCurrentService()
CurrentService
instance managing this session's current SSH service.
This initialization method is invoked once from the AbstractSession
constructor. Do not rely on subclass
fields being initialized.
CurrentService
instance for the sessionpublic static int calculatePadLength(int len, int blockSize, boolean etmMode)
len
- The packet payload sizeblockSize
- The cipher block sizeetmMode
- Whether using "encrypt-then-MAC" modepublic java.lang.String getServerVersion()
SessionContext
null
/empty if versions not yet exchangedpublic java.util.Map<KexProposalOption,java.lang.String> getServerKexProposals()
SessionContext.getKexState()
public java.lang.String getClientVersion()
SessionContext
null
/empty if versions not yet exchangedpublic java.util.Map<KexProposalOption,java.lang.String> getClientKexProposals()
SessionContext.getKexState()
public KeyExchange getKex()
KeyExchange
in progress - null
if KEX not started or successfully completedpublic KexState getKexState()
public byte[] getSessionId()
null
if not yet establishedpublic java.util.Map<KexProposalOption,java.lang.String> getKexNegotiationResult()
public java.lang.String getNegotiatedKexParameter(KexProposalOption paramType)
SessionContext
paramType
- The request KexProposalOption
value - ignored if null
null
if invalid parameter or no negotiated value.SessionContext.getKexState()
public CipherInformation getCipherInformation(boolean incoming)
SessionContext
incoming
- If true
then the cipher for the incoming data, otherwise for the outgoing dataCipherInformation
- or null
if not negotiated yet.public CompressionInformation getCompressionInformation(boolean incoming)
SessionContext
incoming
- If true
then the compression for the incoming data, otherwise for the outgoing dataCompressionInformation
- or null
if not negotiated yet.public MacInformation getMacInformation(boolean incoming)
SessionContext
incoming
- If true
then the MAC for the incoming data, otherwise for the outgoing dataMacInformation
- or null
if not negotiated yet.public void messageReceived(Readable buffer) throws java.lang.Exception
Main input point for the MINA framework.
This method will be called each time new data is received on the socket and will append it to the input buffer
before calling the decode()
method.
buffer
- the new buffer receivedjava.lang.Exception
- if an error occurs while decoding or handling the dataprotected void refreshConfiguration()
final
protected void handleMessage(Buffer buffer) throws java.lang.Exception
buffer
- The Buffer
containing the packet - it may be re-used to generate the response once
request has been decodedjava.lang.Exception
- if an exception occurs while handling this packet.doHandleMessage(Buffer)
protected void doHandleMessage(Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected boolean handleFirstKexPacketFollows(int cmd, Buffer buffer, boolean followFlag)
protected java.util.Map.Entry<java.lang.String,java.lang.String> comparePreferredKexProposalOption(KexProposalOption option)
KexProposalOption
option value for client vs. serveroption
- The option to checknull
if option is equal, otherwise a key/value pair where key=client option value and
value=the server-side oneprotected IoWriteFuture sendNewKeys() throws java.lang.Exception
IoWriteFuture
that can be used to wait and check the result of sending the packetjava.lang.Exception
- if an error occurs sending the messageprotected void handleKexMessage(int cmd, Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected void handleKexExtension(int cmd, Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected void handleNewCompression(int cmd, Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected void handleServiceRequest(Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected boolean handleServiceRequest(java.lang.String serviceName, Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected boolean validateServiceKexState(KexState state)
protected void handleServiceAccept(Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected void handleServiceAccept(java.lang.String serviceName, Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected void handleKexInit(Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected void doKexNegotiation() throws java.lang.Exception
java.lang.Exception
protected void handleNewKeys(int cmd, Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected void validateKexState(int cmd, KexState expected)
protected Closeable getInnerCloseable()
getInnerCloseable
in class AbstractInnerCloseable
protected void preClose()
AbstractCloseable
preClose
in class AbstractCloseable
protected java.util.List<Service> getServices()
public <T extends Service> T getService(java.lang.Class<T> clazz)
Session
T
- The generic Service
typeclazz
- The service classprotected Buffer preProcessEncodeBuffer(int cmd, Buffer buffer) throws java.io.IOException
SessionHelper
SSH_PACKET_HEADER_LEN
. This is required in order to efficiently handle
the encoding. If necessary, it re-allocates a new buffer and returns it instead.preProcessEncodeBuffer
in class SessionHelper
cmd
- The command stored in the bufferbuffer
- The original Buffer
- assumed to be properly formatted and be of at least the
required minimum length.Buffer
. Note: users may use this method to totally alter the
contents of the buffer being sent but it is highly discouraged as it may have unexpected
results.java.io.IOException
- If failed to process the bufferpublic IoWriteFuture writePacket(Buffer buffer) throws java.io.IOException
Session
buffer
- the buffer to encode and sendIoWriteFuture
that can be used to check when the packet has actually been sentjava.io.IOException
- if an error occurred when encoding sending the packetpublic IoWriteFuture writePacket(Buffer buffer, long timeout, java.util.concurrent.TimeUnit unit) throws java.io.IOException
Session
IoWriteFuture
will be set with a
TimeoutException
exception to indicate a timeout.buffer
- the buffer to encode and spendtimeout
- the timeoutunit
- the time unit of the timeout parameterjava.io.IOException
- if an error occurred when encoding or sending the packetprotected Buffer resolveOutputPacket(Buffer buffer) throws java.io.IOException
java.io.IOException
protected IoWriteFuture doWritePacket(Buffer buffer) throws java.io.IOException
java.io.IOException
protected int resolveIgnoreBufferDataLength()
private boolean wantReply(Buffer buffer)
public Buffer request(java.lang.String request, Buffer buffer, long maxWaitMillis) throws java.io.IOException
Session
want-reply = true
.request
- the request name - used mainly for logging and debuggingbuffer
- the buffer containing the global requestmaxWaitMillis
- maximum time in milliseconds to wait for the request to finish - must be
positivenull
otherwise.java.io.IOException
- if an error occurred when encoding or sending the packetjava.net.SocketTimeoutException
- If no response received within specified timeoutpublic GlobalRequestFuture request(Buffer buffer, java.lang.String request, GlobalRequestFuture.ReplyHandler replyHandler) throws java.io.IOException
Session
want-reply = true
, pass the received
Buffer
to the given GlobalRequestFuture.ReplyHandler
, which may execute in a different thread.
null
when the request was sent, or with an exception if the
request could not be sent. The replyHandler
is invoked once the reply is received, with the SSH reply
code and the data received.Buffer
when the request was sent, or with an exception
if the request could not be sent. If a reply handler is given, it is invoked with that empty buffer. The handler
is not invoked if sending the request failed.buffer
- the Buffer
containing the global request, with the want-reply
flag set as
appropriaterequest
- the request namereplyHandler
- GlobalRequestFuture.ReplyHandler
for handling the reply; may be null
java.io.IOException
- if an error occurred while encoding or sending the packetprotected boolean doInvokeUnimplementedMessageHandler(int cmd, Buffer buffer) throws java.lang.Exception
doInvokeUnimplementedMessageHandler
in class SessionHelper
cmd
- The unimplemented commandbuffer
- The input Buffer
handleUnimplementedMessage
java.lang.Exception
- if failed to handle the messagepublic Buffer createBuffer(byte cmd, int len)
Session
cmd
- The SSH command to initialize the buffer withlen
- Estimated number of bytes the buffer will hold, 0 if unknown.Session.prepareBuffer(byte, Buffer)
public Buffer prepareBuffer(byte cmd, Buffer buffer)
Session
cmd
- The SSH command to initialize the buffer withbuffer
- The Buffer
instance to initializeprotected <B extends Buffer> B validateTargetBuffer(int cmd, B buffer)
null
or one of the session's internal ones used for
decoding and uncompressingB
- The Buffer
type being validatedcmd
- The most likely command this buffer refers to (not guaranteed to be correct)buffer
- The buffer to be examinedjava.lang.IllegalArgumentException
- if any of the conditions is violatedprotected Buffer encode(Buffer buffer) throws java.io.IOException
synchronized
block using encodeLock
.buffer
- the buffer to encodeSshConstants.SSH_PACKET_HEADER_LEN
, in which case a substitute buffer will be
created and used.java.io.IOException
- if an exception occurs during the encoding processprotected void aeadOutgoingBuffer(Buffer buf, int offset, int len) throws java.lang.Exception
java.lang.Exception
protected void appendOutgoingMac(Buffer buf, int offset, int len) throws java.lang.Exception
java.lang.Exception
protected void encryptOutgoingBuffer(Buffer buf, int offset, int len) throws java.lang.Exception
java.lang.Exception
protected void decode() throws java.lang.Exception
java.lang.Exception
- If failed to decodeprotected void validateIncomingMac(byte[] data, int offset, int len) throws java.lang.Exception
java.lang.Exception
protected abstract boolean readIdentification(Buffer buffer) throws java.lang.Exception
SessionHelper.doReadIdentification(Buffer, boolean)
and store the result in the needed property.buffer
- The Buffer
containing the remote identificationtrue
if the identification has been fully read or false
if more data
is neededjava.lang.Exception
- if an error occurs such as a bad protocol version or unsuccessful KEX was involvedprotected byte[] sendKexInit(java.util.Map<KexProposalOption,java.lang.String> proposal) throws java.lang.Exception
proposal
- our proposal for key exchange negotiationjava.lang.Exception
- if an error occurred sending the packetprotected byte[] receiveKexInit(Buffer buffer, java.util.Map<KexProposalOption,java.lang.String> proposal) throws java.lang.Exception
buffer
- the Buffer
containing the key exchange init packetproposal
- the remote proposal to filljava.lang.Exception
- If failed to handle the messageprotected void prepareNewKeys() throws java.lang.Exception
inSettings
and outSettings
. The new settings do not take effect yet; use
setInputEncoding()
or setOutputEncoding()
for that.java.lang.Exception
- if an error occursprotected void setOutputEncoding() throws java.lang.Exception
outSettings
so that they are effective and will be applied to any future
outgoing packet. Clears outSettings
.java.lang.Exception
- on errorsprotected void setInputEncoding() throws java.lang.Exception
inSettings
so that they are effective and will be applied to any future
incoming packet. Clears inSettings
.java.lang.Exception
- on errorsprotected long determineRekeyBlockLimit(int inCipherBlockSize, int outCipherBlockSize)
inCipherBlockSize
- block size of the input cipheroutCipherBlockSize
- block size of the output cipherprotected IoWriteFuture notImplemented(int cmd, Buffer buffer) throws java.lang.Exception
SSH_MSG_UNIMPLEMENTED
packet. This packet should contain the sequence id of the unsupported
packet: this number is assumed to be the last packet received.cmd
- The un-implemented command valuebuffer
- The Buffer
that contains the command. Note: the buffer's read position is just
beyond the command.IoWriteFuture
that can be used to wait for packet write completion - null
if
the registered ReservedSessionMessagesHandler
decided to handle the command internallyjava.lang.Exception
- if an error occurred while handling the packet.SessionHelper.sendNotImplemented(long)
protected java.util.Map<KexProposalOption,java.lang.String> negotiate() throws java.lang.Exception
negotiationResult
property.Map
java.lang.Exception
- If negotiation failedprotected java.util.Map<KexProposalOption,java.lang.String> setNegotiationResult(java.util.Map<KexProposalOption,java.lang.String> guess)
protected void requestSuccess(Buffer buffer) throws java.lang.Exception
SSH_MSG_REQUEST_SUCCESS
messagebuffer
- The Buffer
containing the message datajava.lang.Exception
- If failed to handle the messageprotected void requestFailure(Buffer buffer) throws java.lang.Exception
SSH_MSG_REQUEST_FAILURE
messagebuffer
- The Buffer
containing the message datajava.lang.Exception
- If failed to handle the messagepublic void addSessionListener(SessionListener listener)
SessionListenerManager
listener
- The SessionListener
to add - not null
public void removeSessionListener(SessionListener listener)
SessionListenerManager
listener
- The SessionListener
to removepublic SessionListener getSessionListenerProxy()
null
proxy SessionListener
that represents all the currently registered
listeners. Any method invocation on the proxy is replicated to the currently registered listenerspublic void addChannelListener(ChannelListener listener)
ChannelListenerManager
listener
- The ChannelListener
to add - not null
public void removeChannelListener(ChannelListener listener)
ChannelListenerManager
listener
- The ChannelListener
to removepublic ChannelListener getChannelListenerProxy()
null
proxy ChannelListener
that represents all the currently registered
listeners. Any method invocation on the proxy is replicated to the currently registered listenerspublic PortForwardingEventListener getPortForwardingEventListenerProxy()
public void addPortForwardingEventListener(PortForwardingEventListener listener)
PortForwardingEventListenerManager
listener
- The PortForwardingEventListener
to add - never null
public void removePortForwardingEventListener(PortForwardingEventListener listener)
PortForwardingEventListenerManager
listener
- The PortForwardingEventListener
to remove - ignored if null
public KeyExchangeFuture reExchangeKeys() throws java.io.IOException
Session
KeyExchangeFuture
for awaiting the completion of the exchangejava.io.IOException
- If failed to request keys re-negotiationprotected KeyExchangeFuture checkRekey() throws java.lang.Exception
KeyExchangeFuture
to wait for the initiated exchange or null
if no need to
re-key or an exchange is already in progressjava.lang.Exception
- If failed load/generate the keys or send the requestisRekeyRequired()
,
requestNewKeysExchange()
protected KeyExchangeFuture requestNewKeysExchange() throws java.lang.Exception
KeyExchangeFuture
to wait for the initiated exchange or null
if an exchange
is already in progressjava.lang.Exception
- If failed to load/generate the keys or send the requestprotected boolean isRekeyRequired()
protected boolean isRekeyTimeIntervalExceeded()
protected boolean isRekeyPacketCountsExceeded()
protected boolean isRekeyDataSizeExceeded()
protected boolean isRekeyBlocksCountExceeded()
protected java.lang.String resolveSessionKexProposal(java.lang.String hostKeyTypes) throws java.io.IOException
resolveSessionKexProposal
in class SessionHelper
java.io.IOException
protected byte[] sendKexInit() throws java.lang.Exception
java.lang.Exception
protected byte[] getClientKexData()
protected void setClientKexData(byte[] data)
protected byte[] getServerKexData()
protected void setServerKexData(byte[] data)
protected abstract void setKexSeed(byte... seed)
seed
- The result of the KEXINIT handshake - required for correct session key establishmentprotected abstract void checkKeys() throws java.io.IOException
java.io.IOException
- If validation failedprotected byte[] receiveKexInit(Buffer buffer) throws java.lang.Exception
java.lang.Exception
protected abstract void receiveKexInit(java.util.Map<KexProposalOption,java.lang.String> proposal, byte[] seed) throws java.io.IOException
java.io.IOException
public static AbstractSession getSession(IoSession ioSession) throws MissingAttachedSessionException
ioSession
- The IoSession
MissingAttachedSessionException
- if no attached SSH sessiongetSession(IoSession, boolean)
public static void attachSession(IoSession ioSession, AbstractSession session) throws MultipleAttachedSessionException
AbstractSession
to the I/O sessionioSession
- The IoSession
session
- The SSH session to attachMultipleAttachedSessionException
- If a previous session already attachedpublic static AbstractSession getSession(IoSession ioSession, boolean allowNull) throws MissingAttachedSessionException
false
, an exception will be thrown, otherwise a null
will be returned.ioSession
- The IoSession
allowNull
- If true
, a null
value may be returned if no session
is attachednull
MissingAttachedSessionException
- if no attached session and allowNull=false