use rand_core::RngCore;
pub use {smol, smol::prelude::*};
pub async fn gen_key() -> x25519_dalek::StaticSecret {
let mut key: [u8; 32] = [0u8; 32];
rand_core::OsRng.fill_bytes(&mut key);
let key: x25519_dalek::StaticSecret = x25519_dalek::StaticSecret::from(key);
return key;
}
#[async_recursion::async_recursion]
pub async fn get_key() -> x25519_dalek::StaticSecret {
let home: String = dirs::home_dir()
.unwrap()
.into_os_string()
.into_string()
.unwrap();
let keyfile: String = home + "/tunnel-private.key";
let key: x25519_dalek::StaticSecret = match std::fs::read(&keyfile) {
Ok(v) => {
if v.len() != 32 {
std::fs::remove_file(&keyfile).unwrap();
return get_key().await;
}
let mut k: [u8; 32] = [0u8; 32];
for i in 0..32 {
k[i] = v[i];
}
x25519_dalek::StaticSecret::from(k)
}
Err(_) => {
let key: x25519_dalek::StaticSecret = gen_key().await;
let keyfile_value: [u8; 32] = key.to_bytes();
std::fs::write(&keyfile, keyfile_value).unwrap();
key
}
};
return key;
}
pub async fn client(
pk: x25519_dalek::PublicKey,
client: std::net::SocketAddr,
server: std::net::SocketAddr,
) {
let tunnel_stats: std::sync::Arc<sosistab::StatsGatherer> =
std::sync::Arc::new(sosistab::StatsGatherer::new_active());
let tunnel_client: sosistab::ClientConfig =
sosistab::ClientConfig::new(sosistab::Protocol::DirectUdp, server, pk, tunnel_stats);
let tunnel_conn: sosistab::Session = tunnel_client.connect().await.unwrap();
let tunnel_conn: sosistab::Multiplex = tunnel_conn.multiplex();
let tcp_server: smol::net::TcpListener = smol::net::TcpListener::bind(client).await.unwrap();
let mut tcp_in = tcp_server.incoming();
loop {
let tcp_conn: smol::net::TcpStream = tcp_in.next().await.unwrap().unwrap();
let tunnel_conn: sosistab::RelConn = tunnel_conn.open_conn(None).await.unwrap();
smol::spawn(
smol::io::copy(tunnel_conn.clone(), tcp_conn.clone())
.race(smol::io::copy(tcp_conn, tunnel_conn)),
)
.detach();
}
}
pub async fn server(
sk: x25519_dalek::StaticSecret,
server: std::net::SocketAddr,
tunnel_to: std::net::SocketAddr,
) {
let tunnel_server: sosistab::Listener = sosistab::Listener::listen_udp(
server,
sk,
|_size: usize, _peer: std::net::SocketAddr| { },
|_size: usize, _peer: std::net::SocketAddr| { },
)
.await
.unwrap();
loop {
let tunnel_conn: sosistab::Session = tunnel_server.accept_session().await.unwrap();
let tunnel_conn: sosistab::Multiplex = tunnel_conn.multiplex();
smol::spawn(async move {
loop {
let tunnel_conn: sosistab::RelConn = tunnel_conn.accept_conn().await.unwrap();
let tcp_conn = smol::net::TcpStream::connect(tunnel_to).await.unwrap();
smol::spawn(
smol::io::copy(tunnel_conn.clone(), tcp_conn.clone())
.race(smol::io::copy(tcp_conn, tunnel_conn)),
)
.detach();
}
})
.detach();
}
}
pub async fn async_server(tunnel_server: &str, tunnel_to: &str) -> anyhow::Result<()> {
let listen = tunnel_server.parse::<std::net::SocketAddr>()?;
let to = tunnel_to.parse::<std::net::SocketAddr>()?;
let key = get_key().await;
let pubkey_bytes = x25519_dalek::PublicKey::from(&key).to_bytes();
let pubkey: String = {
let mut pk: String = String::new();
for i in 0..32 {
let it = pubkey_bytes[i];
let it: String = format!("{:02X}", it);
pk.extend(it.chars());
}
pk
};
println!("You public key is {}", pubkey);
server(key, listen, to).await;
Ok(())
}
pub async fn async_client(
tunnel_client: &str,
tunnel_server: &str,
pubkey: &str,
) -> anyhow::Result<()> {
let listen = tunnel_client.parse::<std::net::SocketAddr>()?;
let server = tunnel_server.parse::<std::net::SocketAddr>()?;
let pk: [u8; 32] = {
let mut key: [u8; 32] = [0u8; 32];
let mut n: usize = 0;
for i in (0..(pubkey.len())).step_by(2) {
let it: &str = &pubkey[i..=i + 1];
let it: u8 = u8::from_str_radix(it, 16).unwrap();
key[n] = it;
n += 1;
}
key
};
client(x25519_dalek::PublicKey::from(pk), listen, server).await;
Ok(())
}
pub fn run_server(tunnel_server: &str, tunnel_to: &str) {
smol::block_on(async {
if let Err(e) = async_server(tunnel_server, tunnel_to).await {
eprintln!("{:?}", e);
}
});
}
pub fn run_client(tunnel_client: &str, tunnel_server: &str, pubkey: &str) {
smol::block_on(async {
if let Err(e) = async_client(tunnel_client, tunnel_server, pubkey).await {
eprintln!("{:?}", e);
}
});
}