mirror of https://github.com/ospab/ostp.git
feat(cli): add --import, --proxy-env, interactive link prompt, and TUN safety guard for Linux
This commit is contained in:
parent
5b3a9f2e14
commit
eef8869731
|
|
@ -15,6 +15,27 @@ pub async fn run_native_tunnel(
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use std::os::windows::process::CommandExt;
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
use std::io::{self, IsTerminal, Write};
|
||||||
|
if io::stdout().is_terminal() {
|
||||||
|
println!("\n===================================================================");
|
||||||
|
println!("WARNING: TUN mode will modify the system routing table.");
|
||||||
|
println!("If you are connected to a headless server via SSH, you may lose");
|
||||||
|
println!("your connection when default routes are redirected into the tunnel.");
|
||||||
|
println!("===================================================================\n");
|
||||||
|
print!("Are you sure you want to initialize the TUN interface? [yes/no]: ");
|
||||||
|
io::stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let mut input = String::new();
|
||||||
|
io::stdin().read_line(&mut input).unwrap();
|
||||||
|
let ans = input.trim().to_lowercase();
|
||||||
|
if ans != "y" && ans != "yes" {
|
||||||
|
return Err(anyhow!("TUN initialization aborted by user. Run without TUN to use as a local proxy."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let debug = config.debug;
|
let debug = config.debug;
|
||||||
tracing::info!("Initializing NATIVE TUN tunnel (smoltcp)...");
|
tracing::info!("Initializing NATIVE TUN tunnel (smoltcp)...");
|
||||||
|
|
||||||
|
|
@ -31,7 +52,7 @@ pub async fn run_native_tunnel(
|
||||||
.address((10, 1, 0, 2))
|
.address((10, 1, 0, 2))
|
||||||
.netmask((255, 255, 255, 0))
|
.netmask((255, 255, 255, 0))
|
||||||
.destination((10, 1, 0, 1))
|
.destination((10, 1, 0, 1))
|
||||||
.mtu(config.ostp.mtu.saturating_sub(48).max(500) as u16)
|
.mtu(config.ostp.mtu as u16)
|
||||||
.up();
|
.up();
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|
|
||||||
110
ostp/src/main.rs
110
ostp/src/main.rs
|
|
@ -46,6 +46,18 @@ struct Args {
|
||||||
/// Update OSTP: re-run the install script to fetch and install the latest version
|
/// Update OSTP: re-run the install script to fetch and install the latest version
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
update: bool,
|
update: bool,
|
||||||
|
|
||||||
|
/// Import a share link (ostp://...) into the configuration file and exit
|
||||||
|
#[arg(long)]
|
||||||
|
import: Option<String>,
|
||||||
|
|
||||||
|
/// Output shell export commands for proxy (eval $(ostp --proxy-env))
|
||||||
|
#[arg(long)]
|
||||||
|
proxy_env: bool,
|
||||||
|
|
||||||
|
/// Output shell export commands to clear proxy (eval $(ostp --proxy-env-clear))
|
||||||
|
#[arg(long)]
|
||||||
|
proxy_env_clear: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ostp_link(link: &str) -> Result<ClientConfig> {
|
fn parse_ostp_link(link: &str) -> Result<ClientConfig> {
|
||||||
|
|
@ -512,6 +524,35 @@ async fn run_app() -> Result<()> {
|
||||||
return cmd_update();
|
return cmd_update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if args.proxy_env {
|
||||||
|
let mut port = 1088;
|
||||||
|
if args.config.exists() {
|
||||||
|
if let Ok(content) = fs::read_to_string(&args.config) {
|
||||||
|
let mut stripped = json_comments::StripComments::new(content.as_bytes());
|
||||||
|
if let Ok(config) = serde_json::from_reader::<_, UnifiedConfig>(&mut stripped) {
|
||||||
|
if let AppMode::Client(c) = config.mode {
|
||||||
|
if let Some(bind) = c.socks5_bind {
|
||||||
|
if let Some(p) = bind.split(':').last().and_then(|s| s.parse::<u16>().ok()) {
|
||||||
|
port = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!("export http_proxy=\"socks5://127.0.0.1:{}\"", port);
|
||||||
|
println!("export https_proxy=\"socks5://127.0.0.1:{}\"", port);
|
||||||
|
println!("export all_proxy=\"socks5://127.0.0.1:{}\"", port);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.proxy_env_clear {
|
||||||
|
println!("unset http_proxy");
|
||||||
|
println!("unset https_proxy");
|
||||||
|
println!("unset all_proxy");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if args.generate_key {
|
if args.generate_key {
|
||||||
let mut new_keys = Vec::new();
|
let mut new_keys = Vec::new();
|
||||||
for _ in 0..args.count {
|
for _ in 0..args.count {
|
||||||
|
|
@ -548,10 +589,77 @@ async fn run_app() -> Result<()> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(import_url) = args.import {
|
||||||
|
println!("[ostp] Importing configuration from share link...");
|
||||||
|
let client_cfg = parse_ostp_link(&import_url)
|
||||||
|
.map_err(|e| anyhow!("Share Link Error: {e}"))?;
|
||||||
|
let unified = UnifiedConfig {
|
||||||
|
mode: AppMode::Client(client_cfg),
|
||||||
|
log_level: Some("info".to_string()),
|
||||||
|
};
|
||||||
|
let content = serde_json::to_string_pretty(&unified)?;
|
||||||
|
if let Some(parent) = args.config.parent() {
|
||||||
|
if !parent.as_os_str().is_empty() {
|
||||||
|
fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fs::write(&args.config, content)?;
|
||||||
|
println!("[ostp] Configuration successfully imported and saved to {:?}", args.config);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(url) = args.url {
|
if let Some(url) = args.url {
|
||||||
println!("[ostp] Connecting via share link...");
|
println!("[ostp] Connecting via share link...");
|
||||||
let client_cfg = parse_ostp_link(&url)
|
let mut client_cfg = parse_ostp_link(&url)
|
||||||
.map_err(|e| anyhow!("Share Link Error: {e}"))?;
|
.map_err(|e| anyhow!("Share Link Error: {e}"))?;
|
||||||
|
|
||||||
|
// Interactive prompt for URL launch
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
print!("Enable TUN (VPN) mode? [y/N]: ");
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
let mut input = String::new();
|
||||||
|
std::io::stdin().read_line(&mut input).unwrap();
|
||||||
|
if input.trim().eq_ignore_ascii_case("y") {
|
||||||
|
if let Some(tun) = &mut client_cfg.tun {
|
||||||
|
tun.enable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print!("Enable connection multiplexing (mux)? [y/N]: ");
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
input.clear();
|
||||||
|
std::io::stdin().read_line(&mut input).unwrap();
|
||||||
|
if input.trim().eq_ignore_ascii_case("y") {
|
||||||
|
print!("How many sessions? [5]: ");
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
input.clear();
|
||||||
|
std::io::stdin().read_line(&mut input).unwrap();
|
||||||
|
let mut sessions = 5;
|
||||||
|
if !input.trim().is_empty() {
|
||||||
|
if let Ok(s) = input.trim().parse() {
|
||||||
|
sessions = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if client_cfg.mux.is_none() {
|
||||||
|
client_cfg.mux = Some(MuxConfig {
|
||||||
|
enabled: Some(true),
|
||||||
|
sessions: Some(sessions),
|
||||||
|
});
|
||||||
|
} else if let Some(mux) = &mut client_cfg.mux {
|
||||||
|
mux.enabled = Some(true);
|
||||||
|
mux.sessions = Some(sessions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print!("Enable debug mode? [y/N]: ");
|
||||||
|
std::io::stdout().flush().unwrap();
|
||||||
|
input.clear();
|
||||||
|
std::io::stdin().read_line(&mut input).unwrap();
|
||||||
|
if input.trim().eq_ignore_ascii_case("y") {
|
||||||
|
client_cfg.debug = Some(true);
|
||||||
|
}
|
||||||
|
|
||||||
return run_client_directly(client_cfg).await;
|
return run_client_directly(client_cfg).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue