fixed ssh connection deadlock

This commit is contained in:
Eugene Pankov 2022-08-21 00:55:30 +02:00
parent 0c5e3aa36f
commit 564fc1736a
No known key found for this signature in database
GPG key ID: 5896FCBBDD1CF4F4
19 changed files with 227 additions and 144 deletions

37
Cargo.lock generated
View file

@ -649,6 +649,17 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chacha20"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08"
dependencies = [
"cfg-if",
"cipher 0.4.3",
"cpufeatures",
]
[[package]]
name = "checked_int_cast"
version = "1.0.0"
@ -2444,9 +2455,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-src"
version = "111.20.0+1.1.1o"
version = "111.22.0+1.1.1q"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92892c4f87d56e376e469ace79f1128fdaded07646ddf73aa0be4706ff712dec"
checksum = "8f31f0d509d1c1ae9cada2f9539ff8f37933831fd5098879e482aa687d659853"
dependencies = [
"cc",
]
@ -2818,6 +2829,17 @@ dependencies = [
"winapi",
]
[[package]]
name = "poly1305"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
dependencies = [
"cpufeatures",
"opaque-debug",
"universal-hash 0.5.0",
]
[[package]]
name = "polyval"
version = "0.5.3"
@ -3166,14 +3188,15 @@ dependencies = [
[[package]]
name = "russh"
version = "0.34.0-beta.8"
version = "0.34.0-beta.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccd8be93ee0b54a8a6b74c77ecef946185f0acbfb5234ea66666887621381e85"
checksum = "cc91dececaa1d3d96b81bc9b471cf95d32136d1bceb4233ecbe70523175ba219"
dependencies = [
"aes 0.8.1",
"aes-gcm 0.10.1",
"bitflags",
"byteorder",
"chacha20",
"ctr 0.9.1",
"digest 0.10.3",
"flate2",
@ -3185,6 +3208,7 @@ dependencies = [
"num-bigint",
"once_cell",
"openssl",
"poly1305",
"rand",
"russh-cryptovec",
"russh-keys",
@ -3208,9 +3232,9 @@ dependencies = [
[[package]]
name = "russh-keys"
version = "0.22.0-beta.4"
version = "0.22.0-beta.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "727c26a99d90f1b43ed80d42256c7788ccfe0ce4524634298f9bdbb1d5ceb7c6"
checksum = "8859858504ed8ae1064d20c5989201f993969c401149976267b832ab2842e52f"
dependencies = [
"aes 0.8.1",
"bcrypt-pbkdf",
@ -4589,7 +4613,6 @@ dependencies = [
"dialoguer",
"futures",
"notify",
"openssl",
"qrcode",
"rcgen",
"sd-notify",

View file

@ -2,7 +2,7 @@ import subprocess
from textwrap import dedent
from .conftest import ProcessManager
from .util import wait_port, wait_mysql_port, mysql_client_ssl_opt
from .util import wait_port, wait_mysql_port, mysql_client_ssl_opt, mysql_client_opts
class Test:
@ -43,7 +43,7 @@ class Test:
'127.0.0.1',
'--port',
str(wg_ports["mysql"]),
'--enable-cleartext-plugin',
*mysql_client_opts,
mysql_client_ssl_opt,
'db',
],
@ -63,7 +63,7 @@ class Test:
'127.0.0.1',
'--port',
str(wg_ports["mysql"]),
'--enable-cleartext-plugin',
*mysql_client_opts,
mysql_client_ssl_opt,
'db',
],

View file

@ -21,7 +21,7 @@ def wg_port(processes, ssh_port, password_123_hash):
- name: ssh
allow_roles: [role]
ssh:
host: localhost
host: 127.0.0.1
port: {ssh_port}
- name: ssh-bad-domain
allow_roles: [role]
@ -69,7 +69,7 @@ class Test:
stderr=subprocess.PIPE,
)
stdout, stderr = ssh_client.communicate()
stdout, stderr = ssh_client.communicate(timeout=10)
assert b'stdout' == stdout
assert stderr.endswith(b'stderr')

View file

@ -94,16 +94,18 @@ class Test:
ssh_client = processes.start_ssh_client(
'user:ssh@localhost',
'-v',
'-p',
str(wg_ports['ssh']),
'-o',
'IdentityFile=ssh-keys/id_rsa',
'-o',
'PreferredAuthentications=publickey',
'-o', 'PubkeyAcceptedKeyTypes=+ssh-rsa',
'ls',
'/bin/sh',
)
assert ssh_client.communicate()[0] == b'/bin/sh\n'
assert ssh_client.communicate(timeout=10)[0] == b'/bin/sh\n'
assert ssh_client.returncode == 0
ssh_client = processes.start_ssh_client(
@ -114,8 +116,9 @@ class Test:
'IdentityFile=ssh-keys/id_ed25519',
'-o',
'PreferredAuthentications=publickey',
'-o', 'PubkeyAcceptedKeyTypes=+ssh-rsa',
'ls',
'/bin/sh',
)
assert ssh_client.communicate()[0] == b''
assert ssh_client.communicate(timeout=10)[0] == b''
assert ssh_client.returncode != 0

View file

@ -10,9 +10,11 @@ import time
last_port = 1234
mysql_client_ssl_opt = '--ssl'
mysql_client_opts = []
if 'GITHUB_ACTION' in os.environ:
# Github uses MySQL instead of MariaDB
mysql_client_ssl_opt = '--ssl-mode=REQUIRED'
mysql_client_opts = ['--enable-cleartext-plugin']
def alloc_port():

View file

@ -120,7 +120,8 @@ impl Api {
};
let mut auth_state_store = services.auth_state_store.lock().await;
let state_arc = get_auth_state_for_request(&username, session, &mut auth_state_store).await?;
let state_arc =
get_auth_state_for_request(&username, session, &mut auth_state_store).await?;
let mut state = state_arc.lock().await;
let mut cp = services.config_provider.lock().await;

View file

@ -35,7 +35,9 @@ use warpgate_common::{
};
use warpgate_web::Assets;
use crate::common::{endpoint_admin_auth, endpoint_auth, page_auth, COOKIE_MAX_AGE, SESSION_COOKIE_NAME};
use crate::common::{
endpoint_admin_auth, endpoint_auth, page_auth, COOKIE_MAX_AGE, SESSION_COOKIE_NAME,
};
use crate::error::error_page;
use crate::middleware::{CookieHostMiddleware, TicketMiddleware};
use crate::session::{SessionStore, SharedSessionStorage};

View file

@ -5,8 +5,7 @@ use tracing::*;
use crate::session_handle::WarpgateServerHandleFromRequest;
pub async fn span_for_request(req: &Request) -> poem::Result<Span> {
let handle = WarpgateServerHandleFromRequest::from_request_without_body(req)
.await;
let handle = WarpgateServerHandleFromRequest::from_request_without_body(req).await;
Ok(match handle {
Ok(ref handle) => {

View file

@ -1,16 +1,13 @@
#![feature(type_alias_impl_trait, let_else, try_blocks)]
use warpgate_protocol_http::api;
use regex::Regex;
use poem_openapi::OpenApiService;
use regex::Regex;
use warpgate_protocol_http::api;
#[allow(clippy::unwrap_used)]
pub fn main() {
let api_service = OpenApiService::new(
api::get(),
"Warpgate HTTP proxy",
env!("CARGO_PKG_VERSION"),
)
.server("/@warpgate/api");
let api_service =
OpenApiService::new(api::get(), "Warpgate HTTP proxy", env!("CARGO_PKG_VERSION"))
.server("/@warpgate/api");
let spec = api_service.spec();
let re = Regex::new(r"PaginatedResponse<(?P<name>\w+)>").unwrap();

View file

@ -5,7 +5,7 @@ use poem::{Endpoint, Middleware, Request};
use serde::Deserialize;
use warpgate_common::{authorize_ticket, Secret, Services};
use crate::common::{SessionExt};
use crate::common::SessionExt;
pub struct TicketMiddleware {}

View file

@ -12,8 +12,8 @@ bimap = "0.6"
bytes = "1.2"
dialoguer = "0.10"
futures = "0.3"
russh = { version = "0.34.0-beta.8", features = ["openssl"] }
russh-keys = { version = "0.22.0-beta.4", features = ["openssl"] }
russh = { version = "0.34.0-beta.10", features = ["vendored-openssl"] }
russh-keys = { version = "0.22.0-beta.5", features = ["vendored-openssl"] }
sea-orm = { version = "^0.9", features = [
"runtime-tokio-native-tls",
], default-features = false }

View file

@ -1,6 +1,7 @@
use anyhow::Result;
use bytes::{Bytes, BytesMut};
use russh::client::Channel;
use russh::client::Msg;
use russh::Channel;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
use tracing::*;
use uuid::Uuid;
@ -10,7 +11,7 @@ use super::error::SshClientError;
use crate::{ChannelOperation, RCEvent};
pub struct DirectTCPIPChannel {
client_channel: Channel,
client_channel: Channel<Msg>,
channel_id: Uuid,
ops_rx: UnboundedReceiver<ChannelOperation>,
events_tx: UnboundedSender<RCEvent>,
@ -19,7 +20,7 @@ pub struct DirectTCPIPChannel {
impl DirectTCPIPChannel {
pub fn new(
client_channel: Channel,
client_channel: Channel<Msg>,
channel_id: Uuid,
ops_rx: UnboundedReceiver<ChannelOperation>,
events_tx: UnboundedSender<RCEvent>,

View file

@ -1,6 +1,7 @@
use anyhow::Result;
use bytes::{Bytes, BytesMut};
use russh::client::Channel;
use russh::client::Msg;
use russh::Channel;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
use tracing::*;
use uuid::Uuid;
@ -10,7 +11,7 @@ use super::error::SshClientError;
use crate::{ChannelOperation, RCEvent};
pub struct SessionChannel {
client_channel: Channel,
client_channel: Channel<Msg>,
channel_id: Uuid,
ops_rx: UnboundedReceiver<ChannelOperation>,
events_tx: UnboundedSender<RCEvent>,
@ -19,7 +20,7 @@ pub struct SessionChannel {
impl SessionChannel {
pub fn new(
client_channel: Channel,
client_channel: Channel<Msg>,
channel_id: Uuid,
ops_rx: UnboundedReceiver<ChannelOperation>,
events_tx: UnboundedSender<RCEvent>,
@ -102,6 +103,7 @@ impl SessionChannel {
match channel_event {
Some(russh::ChannelMsg::Data { data }) => {
let bytes: &[u8] = &data;
debug!("channel data: {bytes:?}");
self.events_tx.send(RCEvent::Output(
self.channel_id,
Bytes::from(BytesMut::from(bytes)),
@ -137,7 +139,10 @@ impl SessionChannel {
ext,
}).map_err(|_| SshClientError::MpscError)?;
}
None => {
Some(msg) => {
debug!("unhandled channel message: {:?}", msg);
}
None => {
self.events_tx.send(RCEvent::Close(self.channel_id)).map_err(|_| SshClientError::MpscError)?;
break
},

View file

@ -17,7 +17,7 @@ use russh::client::Handle;
use russh::{Preferred, Sig};
use russh_keys::key::{self, PublicKey};
use tokio::sync::mpsc::error::SendError;
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender};
use tokio::sync::mpsc::{self, unbounded_channel, UnboundedReceiver, UnboundedSender};
use tokio::sync::{oneshot, Mutex};
use tokio::task::JoinHandle;
use tracing::*;
@ -84,17 +84,21 @@ pub enum RCEvent {
ext: u32,
},
ConnectionError(ConnectionError),
HostKeyReceived(PublicKey),
HostKeyUnknown(PublicKey, oneshot::Sender<bool>),
// ForwardedTCPIP(Uuid, DirectTCPIPParams),
Done,
}
pub type RCCommandReply = oneshot::Sender<Result<(), SshClientError>>;
#[derive(Debug)]
pub enum SshClientConnectionEvent {
HostKeyReceived(PublicKey),
HostKeyUnknown(PublicKey, oneshot::Sender<bool>),
}
#[derive(Clone, Debug)]
pub enum RCCommand {
Connect(TargetSSHOptions),
Connect(TargetSSHOptions, mpsc::Sender<SshClientConnectionEvent>),
Channel(Uuid, ChannelOperation),
// ForwardTCPIP(String, u32),
// CancelTCPIPForward(String, u32),
@ -304,26 +308,28 @@ impl RemoteClient {
async fn handle_command(&mut self, cmd: RCCommand) -> Result<bool, SshClientError> {
match cmd {
RCCommand::Connect(options) => match self.connect(options).await {
Ok(_) => {
self.set_state(RCState::Connected)
.map_err(SshClientError::other)?;
let ops = self.pending_ops.drain(..).collect::<Vec<_>>();
for (id, op) in ops {
self.apply_channel_op(id, op).await?;
RCCommand::Connect(options, event_sender) => {
match self.connect(options, event_sender).await {
Ok(_) => {
self.set_state(RCState::Connected)
.map_err(SshClientError::other)?;
let ops = self.pending_ops.drain(..).collect::<Vec<_>>();
for (id, op) in ops {
self.apply_channel_op(id, op).await?;
}
// let forwards = self.pending_forwards.drain(..).collect::<Vec<_>>();
// for (address, port) in forwards {
// self.tcpip_forward(address, port).await?;
// }
}
Err(e) => {
debug!("Connect error: {}", e);
let _ = self.tx.send(RCEvent::ConnectionError(e));
self.set_disconnected();
return Ok(true);
}
// let forwards = self.pending_forwards.drain(..).collect::<Vec<_>>();
// for (address, port) in forwards {
// self.tcpip_forward(address, port).await?;
// }
}
Err(e) => {
debug!("Connect error: {}", e);
let _ = self.tx.send(RCEvent::ConnectionError(e));
self.set_disconnected();
return Ok(true);
}
},
}
RCCommand::Channel(ch, op) => {
self.apply_channel_op(ch, op).await?;
}
@ -335,7 +341,11 @@ impl RemoteClient {
Ok(false)
}
async fn connect(&mut self, ssh_options: TargetSSHOptions) -> Result<(), ConnectionError> {
async fn connect(
&mut self,
ssh_options: TargetSSHOptions,
event_sender: mpsc::Sender<SshClientConnectionEvent>,
) -> Result<(), ConnectionError> {
let address_str = format!("{}:{}", ssh_options.host, ssh_options.port);
let address = match address_str
.to_socket_addrs()
@ -381,10 +391,10 @@ impl RemoteClient {
Some(event) = event_rx.recv() => {
match event {
ClientHandlerEvent::HostKeyReceived(key) => {
self.tx.send(RCEvent::HostKeyReceived(key)).map_err(|_| ConnectionError::Internal)?;
event_sender.send(SshClientConnectionEvent::HostKeyReceived(key)).await.map_err(|_| ConnectionError::Internal)?;
}
ClientHandlerEvent::HostKeyUnknown(key, reply) => {
self.tx.send(RCEvent::HostKeyUnknown(key, reply)).map_err(|_| ConnectionError::Internal)?;
event_sender.send(SshClientConnectionEvent::HostKeyUnknown(key, reply)).await.map_err(|_| ConnectionError::Internal)?;
}
_ => {}
}

View file

@ -16,7 +16,7 @@ pub use common::*;
pub use keys::*;
use russh_keys::PublicKeyBase64;
pub use server::run_server;
use tokio::sync::oneshot;
use tokio::sync::{oneshot, mpsc};
use uuid::Uuid;
use warpgate_common::{
ProtocolName, ProtocolServer, Services, SshHostKeyVerificationMode, Target, TargetOptions,
@ -56,31 +56,14 @@ impl ProtocolServer for SSHProtocolServer {
let mut handles = RemoteClient::create(Uuid::new_v4(), self.services.clone());
let _ = handles.command_tx.send((RCCommand::Connect(ssh_options), oneshot::channel().0));
let (tx, mut rx) = mpsc::channel(10);
let _ = handles
.command_tx
.send((RCCommand::Connect(ssh_options, tx), oneshot::channel().0));
while let Some(event) = handles.event_rx.recv().await {
while let Some(event) = rx.recv().await {
match event {
RCEvent::ConnectionError(err) => {
if let ConnectionError::HostKeyMismatch {
ref received_key_type,
ref received_key_base64,
ref known_key_type,
ref known_key_base64,
} = err
{
println!("\n");
println!("Stored key ({}): {}", known_key_type, known_key_base64);
println!(
"Received key ({}): {}",
received_key_type, received_key_base64
);
println!("Host key doesn't match the stored one.");
println!("If you know that the key is correct (e.g. it has been changed),");
println!("you can remove the old key in the Warpgate management UI and try again");
}
return Err(TargetTestError::ConnectionError(format!("{:?}", err)));
}
RCEvent::HostKeyUnknown(key, reply) => {
SshClientConnectionEvent::HostKeyUnknown(key, reply) => {
println!("\nHost key ({}): {}", key.name(), key.public_key_base64());
println!("There is no trusted {} key for this host.", key.name());
@ -111,6 +94,32 @@ impl ProtocolServer for SSHProtocolServer {
}
}
}
SshClientConnectionEvent::HostKeyReceived(_) => (),
}
}
while let Some(event) = handles.event_rx.recv().await {
match event {
RCEvent::ConnectionError(err) => {
if let ConnectionError::HostKeyMismatch {
ref received_key_type,
ref received_key_base64,
ref known_key_type,
ref known_key_base64,
} = err
{
println!("\n");
println!("Stored key ({}): {}", known_key_type, known_key_base64);
println!(
"Received key ({}): {}",
received_key_type, received_key_base64
);
println!("Host key doesn't match the stored one.");
println!("If you know that the key is correct (e.g. it has been changed),");
println!("you can remove the old key in the Warpgate management UI and try again");
}
return Err(TargetTestError::ConnectionError(format!("{:?}", err)));
}
RCEvent::State(state) => match state {
RCState::Connected => {
return Ok(());

View file

@ -7,7 +7,7 @@ use std::net::SocketAddr;
use std::sync::Arc;
use anyhow::Result;
use russh::MethodSet;
use russh::{MethodSet, Preferred};
pub use russh_handler::ServerHandler;
pub use session::ServerSession;
use tokio::io::{AsyncRead, AsyncWrite};
@ -26,7 +26,16 @@ pub async fn run_server(services: Services, address: SocketAddr) -> Result<()> {
connection_timeout: Some(std::time::Duration::from_secs(300)),
methods: MethodSet::PUBLICKEY | MethodSet::PASSWORD | MethodSet::KEYBOARD_INTERACTIVE,
keys: load_host_keys(&config)?,
..Default::default()
preferred: Preferred {
key: &[
russh_keys::key::ED25519,
russh_keys::key::RSA_SHA2_256,
russh_keys::key::RSA_SHA2_512,
russh_keys::key::SSH_RSA,
],
..<_>::default()
},
..<_>::default()
}
};
@ -80,8 +89,9 @@ async fn _run_stream<R>(
handler: ServerHandler,
) -> Result<()>
where
R: AsyncRead + AsyncWrite + Unpin + Debug,
R: AsyncRead + AsyncWrite + Unpin + Debug + Send + 'static,
{
russh::server::run_stream(config, socket, handler).await?;
let session = russh::server::run_stream(config, socket, handler).await?;
session.await?;
Ok(())
}

View file

@ -40,17 +40,17 @@ impl russh::server::Handler for ServerHandler {
async { Ok((self, s)) }.boxed()
}
fn channel_open_session(self, channel: ChannelId, mut session: Session) -> Self::FutureUnit {
fn channel_open_session(self, channel: ChannelId, mut session: Session) -> Self::FutureBool {
async move {
{
let allowed = {
let mut this_session = self.session.lock().await;
let span = this_session.make_logging_span();
this_session
._channel_open_session(ServerChannelId(channel), &mut session)
.instrument(span)
.await?;
}
Ok((self, session))
.await?
};
Ok((self, session, allowed))
}
.boxed()
}
@ -358,11 +358,11 @@ impl russh::server::Handler for ServerHandler {
originator_address: &str,
originator_port: u32,
mut session: Session,
) -> Self::FutureUnit {
) -> Self::FutureBool {
let host_to_connect = host_to_connect.to_string();
let originator_address = originator_address.to_string();
async move {
{
let allowed = {
let mut this_session = self.session.lock().await;
let span = this_session.make_logging_span();
this_session
@ -377,9 +377,9 @@ impl russh::server::Handler for ServerHandler {
&mut session,
)
.instrument(span)
.await?;
}
Ok((self, session))
.await?
};
Ok((self, session, allowed))
}
.boxed()
}

View file

@ -13,7 +13,7 @@ use russh::server::Session;
use russh::{CryptoVec, MethodSet, Sig};
use russh_keys::key::PublicKey;
use russh_keys::PublicKeyBase64;
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tokio::sync::{broadcast, oneshot, Mutex};
use tracing::*;
use uuid::Uuid;
@ -34,7 +34,8 @@ use crate::compat::ContextExt;
use crate::server::service_output::ERASE_PROGRESS_SPINNER;
use crate::{
ChannelOperation, ConnectionError, DirectTCPIPParams, PtyRequest, RCCommand, RCCommandReply,
RCEvent, RCState, RemoteClient, ServerChannelId, SshClientError, X11Request,
RCEvent, RCState, RemoteClient, ServerChannelId, SshClientConnectionEvent, SshClientError,
X11Request,
};
#[derive(Clone)]
@ -309,11 +310,28 @@ impl ServerSession {
TargetSelection::Found(target, ssh_options) => {
if self.rc_state == RCState::NotInitialized {
self.rc_state = RCState::Connecting;
self.send_command(RCCommand::Connect(ssh_options))
let (tx, mut rx) = mpsc::channel(10);
self.send_command(RCCommand::Connect(ssh_options, tx))
.map_err(|_| anyhow::anyhow!("cannot send command"))?;
self.service_output.show_progress();
self.emit_service_message(&format!("Selected target: {}", target.name))
.await?;
while let Some(event) = rx.recv().await {
match event {
SshClientConnectionEvent::HostKeyReceived(key) => {
self.emit_service_message(&format!(
"Host key ({}): {}",
key.name(),
key.public_key_base64()
))
.await?;
}
SshClientConnectionEvent::HostKeyUnknown(key, reply) => {
self.handle_unknown_host_key(key, reply).await?;
}
}
}
}
}
}
@ -521,17 +539,6 @@ impl ServerSession {
})
.await?;
}
RCEvent::HostKeyReceived(key) => {
self.emit_service_message(&format!(
"Host key ({}): {}",
key.name(),
key.public_key_base64()
))
.await?;
}
RCEvent::HostKeyUnknown(key, reply) => {
self.handle_unknown_host_key(key, reply).await?;
}
}
Ok(())
}
@ -623,16 +630,23 @@ impl ServerSession {
&mut self,
server_channel_id: ServerChannelId,
session: &mut Session,
) -> Result<()> {
) -> Result<bool> {
let channel = Uuid::new_v4();
self.channel_map.insert(server_channel_id, channel);
info!(%channel, "Opening session channel");
self.all_channels.push(channel);
self.session_handle = Some(session.handle());
self.send_command_and_wait(RCCommand::Channel(channel, ChannelOperation::OpenShell))
.await?;
Ok(())
match self
.send_command_and_wait(RCCommand::Channel(channel, ChannelOperation::OpenShell))
.await
{
Ok(()) => {
self.all_channels.push(channel);
Ok(true)
}
Err(SshClientError::ChannelFailure) => Ok(false),
Err(x) => Err(x.into()),
}
}
pub async fn _channel_open_direct_tcpip(
@ -640,37 +654,45 @@ impl ServerSession {
channel: ServerChannelId,
params: DirectTCPIPParams,
session: &mut Session,
) -> Result<()> {
) -> Result<bool> {
let uuid = Uuid::new_v4();
self.channel_map.insert(channel, uuid);
info!(%channel, "Opening direct TCP/IP channel from {}:{} to {}:{}", params.originator_address, params.originator_port, params.host_to_connect, params.port_to_connect);
let recorder = self
.traffic_recorder_for(&params.host_to_connect, params.port_to_connect)
.await;
if let Some(recorder) = recorder {
#[allow(clippy::unwrap_used)]
let mut recorder = recorder.connection(TrafficConnectionParams {
dst_addr: Ipv4Addr::from_str("2.2.2.2").unwrap(),
dst_port: params.port_to_connect as u16,
src_addr: Ipv4Addr::from_str("1.1.1.1").unwrap(),
src_port: params.originator_port as u16,
});
if let Err(error) = recorder.write_connection_setup().await {
error!(%channel, ?error, "Failed to record connection setup");
}
self.traffic_connection_recorders.insert(uuid, recorder);
}
self.all_channels.push(uuid);
self.session_handle = Some(session.handle());
self.send_command_and_wait(RCCommand::Channel(
uuid,
ChannelOperation::OpenDirectTCPIP(params),
))
.await?;
Ok(())
match self
.send_command_and_wait(RCCommand::Channel(
uuid,
ChannelOperation::OpenDirectTCPIP(params.clone()),
))
.await
{
Ok(()) => {
self.all_channels.push(uuid);
let recorder = self
.traffic_recorder_for(&params.host_to_connect, params.port_to_connect)
.await;
if let Some(recorder) = recorder {
#[allow(clippy::unwrap_used)]
let mut recorder = recorder.connection(TrafficConnectionParams {
dst_addr: Ipv4Addr::from_str("2.2.2.2").unwrap(),
dst_port: params.port_to_connect as u16,
src_addr: Ipv4Addr::from_str("1.1.1.1").unwrap(),
src_port: params.originator_port as u16,
});
if let Err(error) = recorder.write_connection_setup().await {
error!(%channel, ?error, "Failed to record connection setup");
}
self.traffic_connection_recorders.insert(uuid, recorder);
}
Ok(true)
}
Err(SshClientError::ChannelFailure) => Ok(false),
Err(x) => Err(x.into()),
}
}
pub async fn _channel_pty_request(

View file

@ -19,7 +19,6 @@ dhat = {version = "0.3", optional = true}
dialoguer = "0.10"
futures = "0.3"
notify = "^5.0.0-beta.1"
openssl = {version = "0.10", features = ["vendored"]}# Embed OpenSSL
qrcode = "0.12"
rcgen = {version = "0.9", features = ["zeroize"]}
serde_yaml = "0.8.23"