tun2proxy/src/main.rs

82 lines
2.3 KiB
Rust
Raw Normal View History

2023-03-22 11:17:28 +01:00
use std::net::{SocketAddr, ToSocketAddrs};
2023-03-22 01:02:27 +01:00
2023-03-22 11:17:28 +01:00
use clap::Parser;
2022-08-16 16:18:25 +02:00
use env_logger::Env;
2023-03-22 01:02:27 +01:00
use tun2proxy::tun2proxy::Credentials;
2023-03-20 17:56:54 +01:00
use tun2proxy::{main_entry, ProxyType};
2023-03-20 14:13:06 +08:00
/// Tunnel interface to proxy
#[derive(Parser)]
#[command(author, version, about = "Tunnel interface to proxy.", long_about = None)]
struct Args {
/// Name of the tun interface
2023-03-22 11:17:28 +01:00
#[arg(short, long, value_name = "name", default_value = "tun0")]
2023-03-20 14:13:06 +08:00
tun: String,
2023-03-22 12:08:07 +01:00
/// The proxy URL in the form proto://[username[:password]@]host:port
#[arg(short, long = "proxy", value_parser = proxy_url_parser, value_name = "URL")]
2023-03-22 11:17:28 +01:00
proxy: ArgProxy,
}
2023-03-20 14:13:06 +08:00
2023-03-22 11:17:28 +01:00
#[derive(Clone)]
struct ArgProxy {
proxy_type: ProxyType,
2023-03-20 14:13:06 +08:00
addr: SocketAddr,
credentials: Option<Credentials>,
2023-03-22 11:17:28 +01:00
}
2023-03-22 01:02:27 +01:00
2023-03-22 11:17:28 +01:00
fn proxy_url_parser(s: &str) -> Result<ArgProxy, String> {
let url = url::Url::parse(s).map_err(|_| format!("`{s}` is not a valid proxy URL"))?;
let host = url
.host_str()
.ok_or(format!("`{s}` does not contain a host"))?;
2023-03-22 01:02:27 +01:00
2023-03-22 11:17:28 +01:00
let mut url_host = String::from(host);
let port = url.port().ok_or(format!("`{s}` does not contain a port"))?;
url_host.push(':');
url_host.push_str(port.to_string().as_str());
2023-03-20 14:13:06 +08:00
2023-03-22 11:17:28 +01:00
let mut addr_iter = url_host
.to_socket_addrs()
.map_err(|_| format!("`{host}` could not be resolved"))?;
2021-09-02 11:30:23 +02:00
2023-03-22 11:17:28 +01:00
let addr = addr_iter
.next()
.ok_or(format!("`{host}` does not resolve to a usable IP address"))?;
2021-09-02 11:30:23 +02:00
2023-03-22 11:17:28 +01:00
let credentials = if url.username() == "" && url.password().is_none() {
None
2023-03-22 11:17:28 +01:00
} else {
let username = String::from(url.username());
let password = String::from(url.password().unwrap_or(""));
Some(Credentials::new(&username, &password))
2023-03-22 01:02:27 +01:00
};
2023-03-22 11:17:28 +01:00
let scheme = url.scheme();
let proxy_type = match url.scheme().to_ascii_lowercase().as_str() {
"socks5" => Some(ProxyType::Socks5),
"http" => Some(ProxyType::Http),
_ => None,
2021-09-02 11:30:23 +02:00
}
2023-03-22 11:17:28 +01:00
.ok_or(format!("`{scheme}` is an invalid proxy type"))?;
Ok(ArgProxy {
proxy_type,
addr,
credentials,
})
}
fn main() {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
let args = Args::parse();
let addr = args.proxy.addr;
let proxy_type = args.proxy.proxy_type;
log::info!("Proxy {proxy_type} server: {addr}");
main_entry(&args.tun, addr, proxy_type, args.proxy.credentials);
2021-09-02 11:30:23 +02:00
}