mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-23 07:19:08 +00:00
Add auto setup method
This commit is contained in:
parent
d4127af422
commit
1a4a8c4c16
5 changed files with 205 additions and 1 deletions
|
@ -7,9 +7,11 @@ version = "0.1.1"
|
|||
[dependencies]
|
||||
base64 = { version = "0.21" }
|
||||
clap = { version = "4.1", features = ["derive"] }
|
||||
ctrlc = "3.2"
|
||||
dotenvy = "0.15"
|
||||
env_logger = "0.10"
|
||||
hashlink = "0.8"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
mio = { version = "0.8", features = ["os-poll", "net", "os-ext"] }
|
||||
smoltcp = { version = "0.9", git = "https://github.com/smoltcp-rs/smoltcp.git", features = ["std"] }
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("std::ffi::NulError {0:?}")]
|
||||
Nul(#[from] std::ffi::NulError),
|
||||
|
||||
#[error("ctrlc::Error {0:?}")]
|
||||
Send(#[from] ctrlc::Error),
|
||||
|
||||
#[error("std::io::Error {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
|
@ -19,7 +25,7 @@ pub enum Error {
|
|||
Bind(#[from] smoltcp::socket::udp::BindError),
|
||||
|
||||
#[error("smoltcp::socket::tcp::SendError {0:?}")]
|
||||
Send(#[from] smoltcp::socket::tcp::SendError),
|
||||
SontrolHandler(#[from] smoltcp::socket::tcp::SendError),
|
||||
|
||||
#[error("&str {0}")]
|
||||
Str(String),
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::net::{SocketAddr, ToSocketAddrs};
|
|||
|
||||
mod error;
|
||||
mod http;
|
||||
pub mod setup;
|
||||
mod socks5;
|
||||
mod tun2proxy;
|
||||
mod virtdevice;
|
||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -1,6 +1,8 @@
|
|||
use clap::Parser;
|
||||
use env_logger::Env;
|
||||
use std::process::exit;
|
||||
|
||||
use tun2proxy::setup::{get_default_cidrs, Setup};
|
||||
use tun2proxy::Options;
|
||||
use tun2proxy::{main_entry, Proxy};
|
||||
|
||||
|
@ -25,6 +27,10 @@ struct Args {
|
|||
default_value = "virtual"
|
||||
)]
|
||||
dns: ArgDns,
|
||||
|
||||
/// Setup
|
||||
#[arg(short, long, value_name = "method", value_enum)]
|
||||
setup: ArgSetup,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
|
||||
|
@ -33,6 +39,11 @@ enum ArgDns {
|
|||
None,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, clap::ValueEnum)]
|
||||
enum ArgSetup {
|
||||
Auto,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
dotenvy::dotenv().ok();
|
||||
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
|
||||
|
@ -47,7 +58,17 @@ fn main() {
|
|||
options = options.with_virtual_dns();
|
||||
}
|
||||
|
||||
let mut setup: Setup;
|
||||
if args.setup == ArgSetup::Auto {
|
||||
setup = Setup::new(&args.tun, &args.proxy.addr.ip(), get_default_cidrs());
|
||||
if let Err(e) = setup.setup() {
|
||||
log::error!("{e}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = main_entry(&args.tun, args.proxy, options) {
|
||||
log::error!("{e}");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
174
src/setup.rs
Normal file
174
src/setup.rs
Normal file
|
@ -0,0 +1,174 @@
|
|||
use crate::error::Error;
|
||||
use smoltcp::wire::IpCidr;
|
||||
use std::ffi::CString;
|
||||
use std::io::{BufRead, Write};
|
||||
use std::mem;
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::process::Command;
|
||||
use std::ptr::null;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Setup {
|
||||
routes: Vec<IpCidr>,
|
||||
proxy_addr: IpAddr,
|
||||
tun: String,
|
||||
set_up: bool,
|
||||
}
|
||||
|
||||
pub fn get_default_cidrs() -> [IpCidr; 4] {
|
||||
[
|
||||
IpCidr::new(Ipv4Addr::from_str("0.0.0.0").unwrap().into(), 1),
|
||||
IpCidr::new(Ipv4Addr::from_str("128.0.0.0").unwrap().into(), 1),
|
||||
IpCidr::new(Ipv6Addr::from_str("::").unwrap().into(), 1),
|
||||
IpCidr::new(Ipv6Addr::from_str("8000::").unwrap().into(), 1),
|
||||
]
|
||||
}
|
||||
|
||||
impl Setup {
|
||||
pub fn new(
|
||||
tun: impl Into<String>,
|
||||
proxy_addr: &IpAddr,
|
||||
routes: impl IntoIterator<Item = IpCidr>,
|
||||
) -> Self {
|
||||
let routes_cidr = routes.into_iter().collect();
|
||||
Self {
|
||||
tun: tun.into(),
|
||||
proxy_addr: *proxy_addr,
|
||||
routes: routes_cidr,
|
||||
set_up: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_default_route(&mut self) -> Result<(), Error> {
|
||||
let route_show_args = if self.proxy_addr.is_ipv6() {
|
||||
Vec::from(["-6", "route", "show"])
|
||||
} else {
|
||||
Vec::from(["-4", "route", "show"])
|
||||
};
|
||||
|
||||
let e = Error::from("failed to get routing table");
|
||||
let routes = Command::new("ip")
|
||||
.args(route_show_args.as_slice())
|
||||
.output()
|
||||
.map_err(|_| e)?;
|
||||
|
||||
// Equivalent of `ip route | grep '^default' | cut -d ' ' -f 2-`
|
||||
let mut default_route_args = Vec::<String>::new();
|
||||
for result in routes.stdout.lines() {
|
||||
let line = result.unwrap();
|
||||
let split = line.split_whitespace();
|
||||
for (i, route_component) in split.enumerate() {
|
||||
if i == 0 && route_component != "default" {
|
||||
break;
|
||||
} else if i == 0 {
|
||||
continue;
|
||||
}
|
||||
default_route_args.push(String::from(route_component));
|
||||
}
|
||||
if !default_route_args.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let e = Error::from("failed to clone default route for proxy");
|
||||
let mut proxy_route = vec!["route".to_string(), "add".to_string()];
|
||||
proxy_route.push(self.proxy_addr.to_string());
|
||||
proxy_route.extend(default_route_args.clone());
|
||||
Command::new("ip")
|
||||
.args(proxy_route)
|
||||
.output()
|
||||
.map_err(|_| e)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_resolv_conf() -> Result<(), Error> {
|
||||
unsafe {
|
||||
let fd = libc::open(
|
||||
CString::new("/tmp/tun2proxy-resolv.conf")?.as_ptr(),
|
||||
libc::O_RDWR | libc::O_CLOEXEC | libc::O_CREAT,
|
||||
);
|
||||
if fd == -1 {
|
||||
return Err("Failed to create temporary file".into());
|
||||
}
|
||||
let mut f = std::fs::File::from_raw_fd(fd);
|
||||
f.write_all("nameserver 198.18.0.1\n".as_bytes())?;
|
||||
mem::forget(f);
|
||||
if libc::fchmod(fd, 0o644) == -1 {
|
||||
return Err("Failed to change ownership of /etc/resolv.conf".into());
|
||||
}
|
||||
let fd_path = format!("/proc/self/fd/{}", fd);
|
||||
if libc::mount(
|
||||
CString::new(fd_path)?.as_ptr(),
|
||||
CString::new("/etc/resolv.conf")?.as_ptr(),
|
||||
CString::new("resolvconf")?.as_ptr(),
|
||||
libc::MS_BIND,
|
||||
null(),
|
||||
) == -1
|
||||
{
|
||||
return Err("Failed to mount /etc/resolv.conf".into());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_tunnel_routes(&self) -> Result<(), Error> {
|
||||
for route in &self.routes {
|
||||
let e = Error::from(format!(
|
||||
"failed to set up routing of {} through {}",
|
||||
route, self.tun
|
||||
));
|
||||
Command::new("ip")
|
||||
.args([
|
||||
"route",
|
||||
"add",
|
||||
route.to_string().as_str(),
|
||||
"dev",
|
||||
self.tun.as_str(),
|
||||
])
|
||||
.output()
|
||||
.map_err(|_| e)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn shutdown(tun_name: String) {
|
||||
let _ = Command::new("ip")
|
||||
.args(["link", "del", tun_name.as_str()])
|
||||
.output();
|
||||
unsafe {
|
||||
let umount_path = CString::new("/etc/resolv.conf").unwrap();
|
||||
libc::umount(umount_path.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup(&mut self) -> Result<(), Error> {
|
||||
self.set_up = true;
|
||||
let tun_name = self.tun.clone();
|
||||
|
||||
// TODO: This is not optimal.
|
||||
ctrlc::set_handler(move || {
|
||||
Self::shutdown(tun_name.clone());
|
||||
std::process::exit(0);
|
||||
})?;
|
||||
|
||||
let e = Error::from("failed to create tunnel device");
|
||||
Command::new("ip")
|
||||
.args(["tuntap", "add", "name", self.tun.as_str(), "mode", "tun"])
|
||||
.output()
|
||||
.map_err(|_| e)?;
|
||||
|
||||
let e = Error::from("failed to bring up tunnel device");
|
||||
Command::new("ip")
|
||||
.args(["link", "set", self.tun.as_str(), "up"])
|
||||
.output()
|
||||
.map_err(|_| e)?;
|
||||
|
||||
self.clone_default_route()?;
|
||||
Self::setup_resolv_conf()?;
|
||||
self.add_tunnel_routes()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue