git.delta.rocks / remowt / refs/commits / 745d95dba7aa

difftreelog

source

cmds/remowt-ssh/src/main.rs3.3 KiBsourcehistory
1use std::borrow::Cow;2use std::ffi::OsString;3use std::os::unix::ffi::OsStringExt;4use std::path::PathBuf;5use std::sync::Arc;67use anyhow::{bail, ensure};8use async_trait::async_trait;9use bifrostlink::Rpc;10use clap::Parser;11use remowt_link_shared::Address;12use russh::client::{connect, Config, Handler, Session};13use tempdir::TempDir;14use tokio::io::{AsyncReadExt, AsyncWriteExt};15use tokio::net::UnixSocket;1617#[derive(Parser)]18struct Opts {19	host: String,20}2122struct MyHandler {23	host: String,24	port: u16,25}26#[async_trait]27impl Handler for MyHandler {28	type Error = russh::Error;29	async fn check_server_key(30		&mut self,31		server_public_key: &russh_keys::key::PublicKey,32	) -> Result<bool, Self::Error> {33		Ok(russh_keys::check_known_hosts(34			&self.host,35			self.port,36			&server_public_key,37		)?)38	}39}4041#[tokio::main(flavor = "current_thread")]42async fn main() -> anyhow::Result<()> {43	let rpc = Rpc::<Address, remowt_link_shared::Error>::new(Address::User);44	tracing_subscriber::fmt::init();45	let opts = Opts::parse();4647	let conf = dbg!(russh_config::parse_home(&opts.host)?);48	println!("connect");49	let mut sess = connect(50		Arc::new(Config {51			..Default::default()52		}),53		dbg!((conf.host_name.clone(), conf.port)),54		MyHandler {55			host: conf.host_name,56			port: conf.port,57		},58	)59	.await?;60	println!("agent");61	let mut agent = russh_keys::agent::client::AgentClient::connect_env().await?;62	for ele in agent.request_identities().await? {63		let (_agent, res) = sess.authenticate_future(conf.user.clone(), ele, agent).await;64		agent = _agent;65		if res? {66			break;67		}68	}69	// let sess = Session::connect(opts.host, openssh::KnownHosts::Strict).await?;7071	let socket = UnixSocket::new_stream()?;7273	println!("mktemp");74	let mut cmd_chan = sess.channel_open_session().await?;75	cmd_chan76		.exec(true, "mktemp -d remowt.XXXXXXXXXXXX --tmpdir")77		.await?;78	let mut stdout = vec![];79	loop {80		let Some(msg) = cmd_chan.wait().await else {81			bail!("unexpected channel end");82		};83		match msg {84			russh::ChannelMsg::Data { data } => stdout.extend(data.as_ref()),85			russh::ChannelMsg::ExitStatus { exit_status } => {86				if exit_status != 0 {87					bail!("mktemp failed");88				}89				break;90			}91			_ => {}92		}93	}9495	ensure!(stdout.ends_with(b"\n"));96	stdout.pop();9798	// Remote host is not neccessary linux, openssh crate makes incorrect assumptions here.99	// TODO: Remove on local close.100	let remote_dir = PathBuf::from(OsString::from_vec(stdout));101	let remote_socket = remote_dir.join("primary.sock");102103	let local_dir = TempDir::new("remowt")?;104	let local_socket = local_dir.path().join("primary.sock");105106	println!("listen");107	socket.bind(&local_socket)?;108	let listener = socket.listen(1)?;109110	eprintln!("forward socket");111112	let mut sock = sess113		.channel_open_direct_streamlocal(dbg!(remote_socket.to_str().expect("path is utf-8")))114		.await?;115116	eprintln!("wait");117	while let Some(v) = sock.wait().await {118		dbg!(v);119	}120121	eprintln!("spawn agent");122123	// let _agent = sess124	// 	.command("/home/lach/.remowt/remowt-agent")125	// 	.arg("agent-real")126	// 	.arg("--path")127	// 	.arg(remote_socket.to_str().expect("path is utf-8"))128	// 	.spawn()129	// 	.await?;130	//131	// let (mut conn, _) = listener.accept().await?;132	// let mut buf = [0u8; 13];133	// conn.read_exact(&mut buf).await?;134	// assert_eq!(&buf, b"REMOWT_HELLO\0");135	// conn.write_all(b"REMOWT_EHLO\0").await?;136	//137	// println!("handshake complete!");138139	Ok(())140}