diff options
| -rw-r--r-- | oxish-proto/src/lib.rs | 33 | ||||
| -rw-r--r-- | oxish/src/session/mod.rs | 15 |
2 files changed, 47 insertions, 1 deletions
diff --git a/oxish-proto/src/lib.rs b/oxish-proto/src/lib.rs index a67228c..be7b0ea 100644 --- a/oxish-proto/src/lib.rs +++ b/oxish-proto/src/lib.rs @@ -492,6 +492,39 @@ impl Encode for Ignore<'_> { } } +/// The `SSH_MSG_GLOBAL_REQUEST` message +/// +/// Requests that apply to the connection as a whole rather than to a single channel, such as +/// the client's `[email protected]` liveness probe. +/// +/// See <https://www.rfc-editor.org/rfc/rfc4254#section-4>. +#[derive(Debug)] +pub struct GlobalRequest<'a> { + /// The name of the request + pub name: &'a [u8], + /// Whether the sender wants a `SSH_MSG_REQUEST_SUCCESS` or `SSH_MSG_REQUEST_FAILURE` reply + pub want_reply: bool, +} + +impl<'a> TryFrom<IncomingPacket<'a>> for GlobalRequest<'a> { + type Error = ProtoError; + + fn try_from(packet: IncomingPacket<'a>) -> Result<Self, Self::Error> { + if packet.message_type != MessageType::GlobalRequest { + return Err(ProtoError::InvalidPacket("expected global request packet")); + } + + let Decoded { value: name, next } = <&[u8]>::decode(packet.payload)?; + // Request-specific data follows `want_reply`, but we don't act on any request, so + // parsing the boolean is enough to know whether the sender expects a reply. + let Decoded { + value: want_reply, .. + } = bool::decode(next)?; + + Ok(Self { name, want_reply }) + } +} + impl<'a> Decode<'a> for &'a [u8] { fn decode(bytes: &'a [u8]) -> Result<Decoded<'a, Self>, ProtoError> { let len = u32::decode(bytes)?; diff --git a/oxish/src/session/mod.rs b/oxish/src/session/mod.rs index 1fdd95c..b61bdeb 100644 --- a/oxish/src/session/mod.rs +++ b/oxish/src/session/mod.rs @@ -10,7 +10,8 @@ use std::{ }; use proto::{ - Decoded, Disconnect, Encoder, MessageType, Pretty, ReadState, SessionHostKey, WriteState, + Decoded, Disconnect, Encoder, GlobalRequest, MessageType, Pretty, ReadState, SessionHostKey, + WriteState, channels::{ChannelRequest, ChannelRequestType}, crypto::CryptoProvider, key_exchange::Rekey, @@ -214,6 +215,18 @@ impl<T: AsyncRead + AsyncWrite + Unpin> Session<T> { self.post_quantum_kx = post_quantum_kx; continue; } + MessageType::GlobalRequest => { + let request = GlobalRequest::try_from(packet)?; + debug!(name = %String::from_utf8_lossy(request.name), "refusing unsupported global request"); + if request.want_reply { + self.conn.send(&MessageType::RequestFailure).await?; + } + continue; + } + MessageType::RequestSuccess | MessageType::RequestFailure => { + trace!(?packet.message_type, "ignoring unexpected global request reply"); + continue; + } _ => {} } |
