mirror of
https://github.com/tun2proxy/tun2proxy.git
synced 2025-04-22 06:49:08 +00:00
Use nix crate instead of interacting with libc directly, drop privileges
This commit is contained in:
parent
3dc7fde5e9
commit
15703a4823
6 changed files with 232 additions and 127 deletions
|
@ -10,19 +10,19 @@ clap = { version = "4.1", features = ["derive"] }
|
||||||
ctrlc = "3.2"
|
ctrlc = "3.2"
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
|
fork = "0.1"
|
||||||
hashlink = "0.8"
|
hashlink = "0.8"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
mio = { version = "0.8", features = ["os-poll", "net", "os-ext"] }
|
mio = { version = "0.8", features = ["os-poll", "net", "os-ext"] }
|
||||||
|
nix = { version = "0.26", features = ["process", "signal"] }
|
||||||
|
prctl = "1.0"
|
||||||
smoltcp = { version = "0.9", git = "https://github.com/smoltcp-rs/smoltcp.git", features = ["std"] }
|
smoltcp = { version = "0.9", git = "https://github.com/smoltcp-rs/smoltcp.git", features = ["std"] }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
url = "2.3"
|
url = "2.3"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ctor = "0.1"
|
ctor = "0.1"
|
||||||
fork = "0.1"
|
|
||||||
nix = { version = "0.26", features = ["process", "signal"] }
|
|
||||||
prctl = "1.0"
|
|
||||||
reqwest = { version = "0.11", features = ["blocking", "json"] }
|
reqwest = { version = "0.11", features = ["blocking", "json"] }
|
||||||
serial_test = "1.0"
|
serial_test = "1.0"
|
||||||
test-log = "0.2"
|
test-log = "0.2"
|
||||||
|
|
|
@ -35,6 +35,12 @@ pub enum Error {
|
||||||
|
|
||||||
#[error("&String {0}")]
|
#[error("&String {0}")]
|
||||||
RefString(String),
|
RefString(String),
|
||||||
|
|
||||||
|
#[error("nix::errno::Errno {0:?}")]
|
||||||
|
OSError(#[from] nix::errno::Errno),
|
||||||
|
|
||||||
|
#[error("std::num::ParseIntError {0:?}")]
|
||||||
|
IntParseError(#[from] std::num::ParseIntError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Error {
|
impl From<&str> for Error {
|
||||||
|
|
|
@ -111,25 +111,25 @@ impl Credentials {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main_entry(tun: &str, proxy: Proxy, options: Options) -> Result<(), Error> {
|
pub fn main_entry(tun: &str, proxy: &Proxy, options: Options) -> Result<(), Error> {
|
||||||
let mut ttp = TunToProxy::new(tun, options)?;
|
let mut ttp = TunToProxy::new(tun, options)?;
|
||||||
match proxy.proxy_type {
|
match proxy.proxy_type {
|
||||||
ProxyType::Socks4 => {
|
ProxyType::Socks4 => {
|
||||||
ttp.add_connection_manager(SocksManager::new(
|
ttp.add_connection_manager(SocksManager::new(
|
||||||
proxy.addr,
|
proxy.addr,
|
||||||
SocksVersion::V4,
|
SocksVersion::V4,
|
||||||
proxy.credentials,
|
proxy.credentials.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ProxyType::Socks5 => {
|
ProxyType::Socks5 => {
|
||||||
ttp.add_connection_manager(SocksManager::new(
|
ttp.add_connection_manager(SocksManager::new(
|
||||||
proxy.addr,
|
proxy.addr,
|
||||||
SocksVersion::V5,
|
SocksVersion::V5,
|
||||||
proxy.credentials,
|
proxy.credentials.clone(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ProxyType::Http => {
|
ProxyType::Http => {
|
||||||
ttp.add_connection_manager(HttpManager::new(proxy.addr, proxy.credentials));
|
ttp.add_connection_manager(HttpManager::new(proxy.addr, proxy.credentials.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ttp.run()
|
ttp.run()
|
||||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -1,8 +1,10 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use env_logger::Env;
|
use env_logger::Env;
|
||||||
|
|
||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
use std::process::ExitCode;
|
use std::process::ExitCode;
|
||||||
|
|
||||||
|
use tun2proxy::error::Error;
|
||||||
use tun2proxy::setup::{get_default_cidrs, Setup};
|
use tun2proxy::setup::{get_default_cidrs, Setup};
|
||||||
use tun2proxy::Options;
|
use tun2proxy::Options;
|
||||||
use tun2proxy::{main_entry, Proxy};
|
use tun2proxy::{main_entry, Proxy};
|
||||||
|
@ -63,6 +65,7 @@ fn main() -> ExitCode {
|
||||||
options = options.with_virtual_dns();
|
options = options.with_virtual_dns();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(e) = (|| -> Result<(), Error> {
|
||||||
let mut setup: Setup;
|
let mut setup: Setup;
|
||||||
if args.setup == Some(ArgSetup::Auto) {
|
if args.setup == Some(ArgSetup::Auto) {
|
||||||
let bypass_tun_ip = match args.setup_ip {
|
let bypass_tun_ip = match args.setup_ip {
|
||||||
|
@ -75,15 +78,19 @@ fn main() -> ExitCode {
|
||||||
get_default_cidrs(),
|
get_default_cidrs(),
|
||||||
args.setup_ip.is_some(),
|
args.setup_ip.is_some(),
|
||||||
);
|
);
|
||||||
if let Err(e) = setup.setup() {
|
|
||||||
log::error!("{e}");
|
setup.configure()?;
|
||||||
return ExitCode::FAILURE;
|
|
||||||
}
|
setup.drop_privileges()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = main_entry(&args.tun, args.proxy, options) {
|
main_entry(&args.tun, &args.proxy, options)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})() {
|
||||||
log::error!("{e}");
|
log::error!("{e}");
|
||||||
return ExitCode::FAILURE;
|
std::process::exit(1);
|
||||||
}
|
};
|
||||||
|
|
||||||
ExitCode::SUCCESS
|
ExitCode::SUCCESS
|
||||||
}
|
}
|
||||||
|
|
239
src/setup.rs
239
src/setup.rs
|
@ -1,14 +1,19 @@
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use smoltcp::wire::IpCidr;
|
use smoltcp::wire::IpCidr;
|
||||||
use std::ffi::{CString, OsStr};
|
use std::convert::TryFrom;
|
||||||
use std::io::{BufRead, Write};
|
|
||||||
use std::mem;
|
use std::ffi::OsStr;
|
||||||
|
use std::io::BufRead;
|
||||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||||
use std::os::unix::io::FromRawFd;
|
|
||||||
|
use std::os::fd::RawFd;
|
||||||
|
|
||||||
use std::process::{Command, Output};
|
use std::process::{Command, Output};
|
||||||
use std::ptr::null;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use fork::Fork;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Setup {
|
pub struct Setup {
|
||||||
routes: Vec<IpCidr>,
|
routes: Vec<IpCidr>,
|
||||||
|
@ -17,6 +22,7 @@ pub struct Setup {
|
||||||
tun: String,
|
tun: String,
|
||||||
set_up: bool,
|
set_up: bool,
|
||||||
delete_proxy_route: bool,
|
delete_proxy_route: bool,
|
||||||
|
child: libc::pid_t,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_default_cidrs() -> [IpCidr; 4] {
|
pub fn get_default_cidrs() -> [IpCidr; 4] {
|
||||||
|
@ -54,7 +60,13 @@ where
|
||||||
cmdline.append(&mut args);
|
cmdline.append(&mut args);
|
||||||
let command = cmdline.as_slice().join(" ");
|
let command = cmdline.as_slice().join(" ");
|
||||||
match String::from_utf8(output.stderr.clone()) {
|
match String::from_utf8(output.stderr.clone()) {
|
||||||
Ok(output) => Err(format!("Command `{}` failed: {}", command, output).into()),
|
Ok(output) => Err(format!(
|
||||||
|
"[{}] Command `{}` failed: {}",
|
||||||
|
nix::unistd::getpid(),
|
||||||
|
command,
|
||||||
|
output
|
||||||
|
)
|
||||||
|
.into()),
|
||||||
Err(_) => Err(format!(
|
Err(_) => Err(format!(
|
||||||
"Command `{:?}` failed with exit code {}",
|
"Command `{:?}` failed with exit code {}",
|
||||||
command,
|
command,
|
||||||
|
@ -80,6 +92,7 @@ impl Setup {
|
||||||
routes: routes_cidr,
|
routes: routes_cidr,
|
||||||
set_up: false,
|
set_up: false,
|
||||||
delete_proxy_route: false,
|
delete_proxy_route: false,
|
||||||
|
child: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +126,17 @@ impl Setup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (addr_str, prefix_len_str) = dst_str.split_once(['/']).unwrap();
|
let (addr_str, prefix_len_str) = match dst_str.split_once(['/']) {
|
||||||
|
None => (
|
||||||
|
dst_str,
|
||||||
|
if self.tunnel_bypass_addr.is_ipv6() {
|
||||||
|
"128"
|
||||||
|
} else {
|
||||||
|
"32"
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Some((addr_str, prefix_len_str)) => (addr_str, prefix_len_str),
|
||||||
|
};
|
||||||
|
|
||||||
let cidr: IpCidr = IpCidr::new(
|
let cidr: IpCidr = IpCidr::new(
|
||||||
std::net::IpAddr::from_str(addr_str).unwrap().into(),
|
std::net::IpAddr::from_str(addr_str).unwrap().into(),
|
||||||
|
@ -147,32 +170,29 @@ impl Setup {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_resolv_conf() -> Result<(), Error> {
|
fn setup_resolv_conf() -> Result<(), Error> {
|
||||||
unsafe {
|
let fd = nix::fcntl::open(
|
||||||
let fd = libc::open(
|
"/tmp/tun2proxy-resolv.conf",
|
||||||
CString::new("/tmp/tun2proxy-resolv.conf")?.as_ptr(),
|
nix::fcntl::OFlag::O_RDWR | nix::fcntl::OFlag::O_CLOEXEC | nix::fcntl::OFlag::O_CREAT,
|
||||||
libc::O_RDWR | libc::O_CLOEXEC | libc::O_CREAT,
|
nix::sys::stat::Mode::from_bits(0o644_u32).unwrap(),
|
||||||
);
|
)?;
|
||||||
if fd == -1 {
|
let data = "nameserver 198.18.0.1\n".as_bytes();
|
||||||
return Err("Failed to create temporary file".into());
|
let mut written = 0;
|
||||||
}
|
loop {
|
||||||
let mut f = std::fs::File::from_raw_fd(fd);
|
if written >= data.len() {
|
||||||
f.write_all("nameserver 198.18.0.1\n".as_bytes())?;
|
break;
|
||||||
mem::forget(f);
|
|
||||||
if libc::fchmod(fd, 0o444) == -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());
|
|
||||||
}
|
}
|
||||||
|
written += nix::unistd::write(fd, &data[written..])?;
|
||||||
}
|
}
|
||||||
|
nix::sys::stat::fchmod(fd, nix::sys::stat::Mode::from_bits(0o444_u32).unwrap())?;
|
||||||
|
let source = format!("/proc/self/fd/{}", fd);
|
||||||
|
nix::mount::mount(
|
||||||
|
source.as_str().into(),
|
||||||
|
"/etc/resolv.conf",
|
||||||
|
"".into(),
|
||||||
|
nix::mount::MsFlags::MS_BIND,
|
||||||
|
"".into(),
|
||||||
|
)?;
|
||||||
|
nix::unistd::close(fd)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,42 +214,27 @@ impl Setup {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shutdown(&self) {
|
fn shutdown(&mut self) -> Result<(), Error> {
|
||||||
if !self.set_up {
|
self.set_up = false;
|
||||||
return;
|
log::info!(
|
||||||
}
|
"[{}] Restoring network configuration",
|
||||||
Self::shutdown_with_args(&self.tun, self.tunnel_bypass_addr, self.delete_proxy_route);
|
nix::unistd::getpid()
|
||||||
}
|
);
|
||||||
|
|
||||||
fn shutdown_with_args(tun_name: &str, proxy_ip: IpAddr, delete_proxy_route: bool) {
|
|
||||||
log::info!("Restoring network configuration");
|
|
||||||
let _ = Command::new("ip").args(["link", "del", tun_name]).output();
|
|
||||||
if delete_proxy_route {
|
|
||||||
let _ = Command::new("ip")
|
let _ = Command::new("ip")
|
||||||
.args(["route", "del", proxy_ip.to_string().as_str()])
|
.args(["link", "del", self.tun.as_str()])
|
||||||
|
.output();
|
||||||
|
if self.delete_proxy_route {
|
||||||
|
let _ = Command::new("ip")
|
||||||
|
.args(["route", "del", self.tunnel_bypass_addr.to_string().as_str()])
|
||||||
.output();
|
.output();
|
||||||
}
|
}
|
||||||
unsafe {
|
nix::mount::umount("/etc/resolv.conf")?;
|
||||||
let umount_path = CString::new("/etc/resolv.conf").unwrap();
|
Ok(())
|
||||||
libc::umount(umount_path.as_ptr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn setup(&mut self) -> Result<(), Error> {
|
|
||||||
unsafe {
|
|
||||||
if libc::getuid() != 0 {
|
|
||||||
return Err("Automatic setup requires root privileges".into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.tunnel_bypass_addr.is_loopback() && !self.allow_private {
|
|
||||||
log::warn!(
|
|
||||||
"The proxy address {} is a loopback address. You may need to manually \
|
|
||||||
provide --setup-ip to specify the server IP bypassing the tunnel",
|
|
||||||
self.tunnel_bypass_addr
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_and_handle_signals(&mut self, read_from_child: RawFd, write_to_parent: RawFd) {
|
||||||
|
if let Err(e) = (|| -> Result<(), Error> {
|
||||||
|
nix::unistd::close(read_from_child)?;
|
||||||
run_iproute(
|
run_iproute(
|
||||||
[
|
[
|
||||||
"ip",
|
"ip",
|
||||||
|
@ -245,8 +250,8 @@ impl Setup {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.set_up = true;
|
self.set_up = true;
|
||||||
let tun_name = self.tun.clone();
|
let _tun_name = self.tun.clone();
|
||||||
let proxy_ip = self.tunnel_bypass_addr;
|
let _proxy_ip = self.tunnel_bypass_addr;
|
||||||
|
|
||||||
run_iproute(
|
run_iproute(
|
||||||
["ip", "link", "set", self.tun.as_str(), "up"],
|
["ip", "link", "set", self.tun.as_str(), "up"],
|
||||||
|
@ -256,19 +261,105 @@ impl Setup {
|
||||||
|
|
||||||
let delete_proxy_route = self.route_proxy_address()?;
|
let delete_proxy_route = self.route_proxy_address()?;
|
||||||
self.delete_proxy_route = delete_proxy_route;
|
self.delete_proxy_route = delete_proxy_route;
|
||||||
ctrlc::set_handler(move || {
|
|
||||||
Self::shutdown_with_args(&tun_name, proxy_ip, delete_proxy_route);
|
|
||||||
std::process::exit(0);
|
|
||||||
})?;
|
|
||||||
Self::setup_resolv_conf()?;
|
Self::setup_resolv_conf()?;
|
||||||
self.add_tunnel_routes()?;
|
self.add_tunnel_routes()?;
|
||||||
|
|
||||||
|
// Signal to child that we are done setting up everything.
|
||||||
|
if nix::unistd::write(write_to_parent, &[1])? != 1 {
|
||||||
|
return Err("Failed to write to pipe".into());
|
||||||
|
}
|
||||||
|
nix::unistd::close(write_to_parent)?;
|
||||||
|
|
||||||
|
// Now wait for the termination signals.
|
||||||
|
let mut mask = nix::sys::signal::SigSet::empty();
|
||||||
|
mask.add(nix::sys::signal::SIGINT);
|
||||||
|
mask.add(nix::sys::signal::SIGTERM);
|
||||||
|
mask.add(nix::sys::signal::SIGQUIT);
|
||||||
|
mask.thread_block().unwrap();
|
||||||
|
|
||||||
|
let mut fd = nix::sys::signalfd::SignalFd::new(&mask).unwrap();
|
||||||
|
loop {
|
||||||
|
let res = fd.read_signal().unwrap().unwrap();
|
||||||
|
let signo = nix::sys::signal::Signal::try_from(res.ssi_signo as i32).unwrap();
|
||||||
|
if signo == nix::sys::signal::SIGINT
|
||||||
|
|| signo == nix::sys::signal::SIGTERM
|
||||||
|
|| signo == nix::sys::signal::SIGQUIT
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.shutdown()?;
|
||||||
|
Ok(())
|
||||||
|
})() {
|
||||||
|
log::error!("{e}");
|
||||||
|
self.shutdown().unwrap();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drop_privileges(&self) -> Result<(), Error> {
|
||||||
|
let gid_str = match std::env::var("SUDO_GID") {
|
||||||
|
Ok(uid_str) => uid_str,
|
||||||
|
_ => String::from("65535"),
|
||||||
|
};
|
||||||
|
let gid = gid_str.parse::<u32>()?;
|
||||||
|
nix::unistd::setgid(nix::unistd::Gid::from_raw(gid))?;
|
||||||
|
|
||||||
|
let uid_str = match std::env::var("SUDO_UID") {
|
||||||
|
Ok(uid_str) => uid_str,
|
||||||
|
_ => String::from("65535"),
|
||||||
|
};
|
||||||
|
let uid = uid_str.parse::<u32>()?;
|
||||||
|
nix::unistd::setuid(nix::unistd::Uid::from_raw(uid))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure(&mut self) -> Result<(), Error> {
|
||||||
|
log::info!(
|
||||||
|
"[{}] Setting up network configuration",
|
||||||
|
nix::unistd::getpid()
|
||||||
|
);
|
||||||
|
if nix::unistd::getuid() != 0.into() {
|
||||||
|
return Err("Automatic setup requires root privileges".into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.tunnel_bypass_addr.is_loopback() && !self.allow_private {
|
||||||
|
log::warn!(
|
||||||
|
"The proxy address {} is a loopback address. You may need to manually \
|
||||||
|
provide --setup-ip to specify the server IP bypassing the tunnel",
|
||||||
|
self.tunnel_bypass_addr
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let (read_from_child, write_to_parent) = nix::unistd::pipe()?;
|
||||||
|
match fork::fork() {
|
||||||
|
Ok(Fork::Child) => {
|
||||||
|
prctl::set_death_signal(nix::sys::signal::SIGINT as isize).unwrap();
|
||||||
|
self.setup_and_handle_signals(read_from_child, write_to_parent);
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
Ok(Fork::Parent(child)) => {
|
||||||
|
self.child = child;
|
||||||
|
nix::unistd::close(write_to_parent)?;
|
||||||
|
let mut buf = [0];
|
||||||
|
if nix::unistd::read(read_from_child, &mut buf)? != 1 {
|
||||||
|
return Err("Failed to read from pipe".into());
|
||||||
|
}
|
||||||
|
nix::unistd::close(read_from_child)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err("Failed to fork".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn restore(&mut self) -> Result<(), Error> {
|
||||||
|
nix::sys::signal::kill(
|
||||||
|
nix::unistd::Pid::from_raw(self.child),
|
||||||
|
nix::sys::signal::SIGINT,
|
||||||
|
)?;
|
||||||
|
nix::sys::wait::waitpid(nix::unistd::Pid::from_raw(self.child), None)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Setup {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -64,28 +64,29 @@ mod tests {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
match fork::fork() {
|
let mut setup = Setup::new(
|
||||||
Ok(Fork::Parent(child)) => {
|
|
||||||
test_function();
|
|
||||||
signal::kill(Pid::from_raw(child), signal::SIGINT)
|
|
||||||
.expect("failed to kill child");
|
|
||||||
nix::sys::wait::waitpid(Pid::from_raw(child), None)
|
|
||||||
.expect("failed to wait for child");
|
|
||||||
}
|
|
||||||
Ok(Fork::Child) => {
|
|
||||||
prctl::set_death_signal(signal::SIGKILL as isize).unwrap(); // 9 == SIGKILL
|
|
||||||
|
|
||||||
let _setup = Setup::new(
|
|
||||||
TUN_TEST_DEVICE,
|
TUN_TEST_DEVICE,
|
||||||
&test.proxy.addr.ip(),
|
&test.proxy.addr.ip(),
|
||||||
get_default_cidrs(),
|
get_default_cidrs(),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
setup.configure().unwrap();
|
||||||
|
|
||||||
|
match fork::fork() {
|
||||||
|
Ok(Fork::Parent(child)) => {
|
||||||
|
test_function();
|
||||||
|
signal::kill(Pid::from_raw(child), signal::SIGINT)
|
||||||
|
.expect("failed to kill child");
|
||||||
|
setup.restore().unwrap();
|
||||||
|
}
|
||||||
|
Ok(Fork::Child) => {
|
||||||
|
prctl::set_death_signal(signal::SIGINT as isize).unwrap();
|
||||||
let _ = main_entry(
|
let _ = main_entry(
|
||||||
TUN_TEST_DEVICE,
|
TUN_TEST_DEVICE,
|
||||||
test.proxy,
|
&test.proxy,
|
||||||
Options::new().with_virtual_dns(),
|
Options::new().with_virtual_dns(),
|
||||||
);
|
);
|
||||||
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
Err(_) => panic!(),
|
Err(_) => panic!(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue