#![deny(unused)]
#![deny(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
mod connect;
#[cfg(target_family = "unix")]
mod daemon;
mod error;
mod ext;
mod io;
mod oneself;
mod rand;
#[cfg(target_os = "linux")]
mod route;
mod server;
use std::{net::SocketAddr, path::PathBuf};
use cidr::IpCidr;
use clap::{Args, Parser, Subcommand};
use tracing::Level;
use crate::connect::Fallback;
#[cfg(feature = "jemalloc")]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
#[cfg(feature = "tcmalloc")]
#[global_allocator]
static ALLOC: tcmalloc::TCMalloc = tcmalloc::TCMalloc;
#[cfg(feature = "mimalloc")]
#[global_allocator]
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
#[cfg(feature = "snmalloc")]
#[global_allocator]
static ALLOC: snmalloc_rs::SnMalloc = snmalloc_rs::SnMalloc;
#[cfg(feature = "rpmalloc")]
#[global_allocator]
static ALLOC: rpmalloc::RpMalloc = rpmalloc::RpMalloc;
type Result<T, E = error::Error> = std::result::Result<T, E>;
#[derive(Parser)]
#[clap(author, version, about, arg_required_else_help = true)]
#[command(args_conflicts_with_subcommands = true)]
struct Opt {
#[command(subcommand)]
commands: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
Run(BootArgs),
#[cfg(target_family = "unix")]
Start(BootArgs),
#[cfg(target_family = "unix")]
Restart(BootArgs),
#[cfg(target_family = "unix")]
Stop,
#[cfg(target_family = "unix")]
PS,
#[cfg(target_family = "unix")]
Log,
#[clap(name = "self")]
Oneself {
#[command(subcommand)]
command: Oneself,
},
}
#[derive(Args, Clone)]
pub struct AuthMode {
#[arg(short, long, requires = "password")]
username: Option<String>,
#[arg(short, long, requires = "username")]
password: Option<String>,
}
#[derive(Subcommand, Clone)]
pub enum Proxy {
Http {
#[command(flatten)]
auth: AuthMode,
},
Https {
#[command(flatten)]
auth: AuthMode,
#[arg(long, requires = "tls_key")]
tls_cert: Option<PathBuf>,
#[arg(long, requires = "tls_cert")]
tls_key: Option<PathBuf>,
},
Socks5 {
#[command(flatten)]
auth: AuthMode,
},
Auto {
#[command(flatten)]
auth: AuthMode,
#[arg(long, requires = "tls_key")]
tls_cert: Option<PathBuf>,
#[arg(long, requires = "tls_cert")]
tls_key: Option<PathBuf>,
},
}
#[derive(Args, Clone)]
pub struct BootArgs {
#[arg(
long,
short = 'L',
env = "VPROXY_LOG",
default_value = "info",
global = true,
verbatim_doc_comment
)]
log: Level,
#[arg(
long,
short = 'b',
default_value = "127.0.0.1:1080",
verbatim_doc_comment
)]
bind: SocketAddr,
#[arg(long, short = 'c', default_value = "1024", verbatim_doc_comment)]
concurrent: u32,
#[arg(long, short = 'w', verbatim_doc_comment)]
workers: Option<usize>,
#[arg(long, short = 'i', verbatim_doc_comment)]
cidr: Option<IpCidr>,
#[arg(long, short = 'r', verbatim_doc_comment)]
cidr_range: Option<u8>,
#[arg(long, short, verbatim_doc_comment)]
fallback: Option<Fallback>,
#[arg(long, short = 't', default_value = "10", verbatim_doc_comment)]
connect_timeout: u64,
#[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
#[arg(long, default_value = "30", verbatim_doc_comment)]
tcp_user_timeout: Option<u64>,
#[arg(long, default_value = "true", verbatim_doc_comment)]
reuseaddr: Option<bool>,
#[command(subcommand)]
proxy: Proxy,
}
#[derive(Subcommand, Clone)]
pub enum Oneself {
Update,
Uninstall,
}
fn main() -> Result<()> {
let opt = Opt::parse();
#[cfg(target_family = "unix")]
let daemon = daemon::Daemon::default();
match opt.commands {
Commands::Run(args) => server::run(args),
#[cfg(target_family = "unix")]
Commands::Start(args) => daemon.start(args),
#[cfg(target_family = "unix")]
Commands::Restart(args) => daemon.restart(args),
#[cfg(target_family = "unix")]
Commands::Stop => daemon.stop(),
#[cfg(target_family = "unix")]
Commands::PS => daemon.status(),
#[cfg(target_family = "unix")]
Commands::Log => daemon.log(),
Commands::Oneself { command } => match command {
Oneself::Update => oneself::update(),
Oneself::Uninstall => oneself::uninstall(),
},
}
}