├── pcaps ├── tun.pcap └── ens160.pcap ├── wireshark.png ├── Cargo.toml ├── README.md └── src └── main.rs /pcaps/tun.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liumuqing/tcp_obfuscator/HEAD/pcaps/tun.pcap -------------------------------------------------------------------------------- /wireshark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liumuqing/tcp_obfuscator/HEAD/wireshark.png -------------------------------------------------------------------------------- /pcaps/ens160.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liumuqing/tcp_obfuscator/HEAD/pcaps/ens160.pcap -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tun_obfuscator" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | pnet = "0.34.0" 10 | tokio-tun = "0.9.1" 11 | tokio = { version = "1.33.0", features = ["full"] } 12 | tracing = "0.1.40" 13 | tracing-subscriber = "0.3.17" 14 | clap = { version = "4.4.7", features = ["derive", "env"] } 15 | ipnet = "2.9.0" 16 | ctrlc = "3.4.1" 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## tun\_obfuscator 2 | 3 | hide your tcp stream from wireshark! 4 | 5 | ## Note 6 | 7 | 1. Don't use this project in a VM that NATed by OSX (bridged vm is ok). Seems the OSX kernel will reassemble those obfuscated segments. 8 | 1. because osx will drops ooo tcp segments 9 | 2. check [this link](https://github.com/canonical/multipass/issues/3038#issuecomment-1665807689) 10 | 2. check [route_localnet](https://github.com/kubernetes/kubernetes/issues/90259) if you want to use this project to mirror from/to 127.0.0.0/8 11 | 12 | ## Let's try 13 | 14 | 1. which servers you want to connect to? 15 | 16 | ``` 17 | $ ping www.baidu.com 18 | PING www.a.shifen.com (180.101.50.188) 56(84) bytes of data. 19 | ... 20 | ``` 21 | 22 | 2. what's your local public ethernet interface + ip? 23 | 24 | ``` 25 | $ ip addr 26 | 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 27 | link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 28 | inet 127.0.0.1/8 scope host lo 29 | valid_lft forever preferred_lft forever 30 | inet6 ::1/128 scope host 31 | valid_lft forever preferred_lft forever 32 | 2: ens160: mtu 1500 qdisc fq_codel state UP group default qlen 1000 33 | link/ether 00:0c:29:83:1c:a4 brd ff:ff:ff:ff:ff:ff 34 | altname enp2s0 35 | inet 192.168.43.83/24 brd 192.168.43.255 scope global dynamic noprefixroute ens160 36 | valid_lft 2636sec preferred_lft 2636sec 37 | inet6 fe80::b254:7af9:54a7:f7e1/64 scope link noprefixroute 38 | valid_lft forever preferred_lft forever 39 | 40 | ``` 41 | 42 | 3. start a terminal and run the obfuscator: 43 | ``` 44 | sudo RUST_LOG=trace ./target/debug/tun_obfuscator --dst 180.101.50.0/24 --dst-virtual 1.1.1.0/24 --src 192.168.43.0/24 --src-virtual 2.2.2.0/24 --interface lima0 --public-ip 192.168.43.194 --gateway 192.168.43.1 45 | 2023-10-26T12:21:10.897437Z INFO tun_obfuscator: creating tun... 46 | 2023-10-26T12:21:10.897660Z INFO tun_obfuscator: tun created, name: obfuscator_tun 47 | 2023-10-26T12:21:10.897668Z INFO tun_obfuscator: executing `sysctl -w net.ipv4.ip_forward=1` 48 | net.ipv4.ip_forward = 1 49 | 2023-10-26T12:21:10.899440Z INFO tun_obfuscator: executing `ip addr add 1.1.0.0/16 dev obfuscator_tun` 50 | 2023-10-26T12:21:10.900488Z INFO tun_obfuscator: executing `iptables -t nat -D POSTROUTING -o obfuscator_tun -j MASQUERADE` 51 | iptables: Bad rule (does a matching rule exist in that chain?). 52 | 2023-10-26T12:21:10.912266Z INFO tun_obfuscator: executing `iptables -t nat -A POSTROUTING -o obfuscator_tun -j MASQUERADE` 53 | 2023-10-26T12:21:10.917233Z INFO tun_obfuscator: executing `sudo iptables -t nat -D POSTROUTING -s 1.1.0.0/16 -o ens160 -j SNAT --to 192.168.43.83` 54 | iptables: Bad rule (does a matching rule exist in that chain?). 55 | 2023-10-26T12:21:10.927210Z INFO tun_obfuscator: executing `sudo iptables -t nat -A POSTROUTING -s 1.1.0.0/16 -o ens160 -j SNAT --to 192.168.43.83` 56 | 2023-10-26T12:21:10.935511Z INFO tun_obfuscator: setup tun and iptables done. 57 | 2023-10-26T12:21:10.935528Z INFO tun_obfuscator: running.. 58 | ``` 59 | 60 | 4. start a new terminal and access via mirror ip: 61 | ``` 62 | $ curl http://1.1.50.188 -v -H Host:www.baidu.com 63 | * Trying 1.1.50.188:80... 64 | * Connected to 1.1.50.188 (1.1.50.188) port 80 (#0) 65 | > GET / HTTP/1.1 66 | > Host:www.baidu.com 67 | > User-Agent: curl/7.81.0 68 | > Accept: */* 69 | > 70 | * Mark bundle as not supporting multiuse 71 | < HTTP/1.1 200 OK 72 | < Accept-Ranges: bytes 73 | < Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform 74 | < Connection: keep-alive 75 | < Content-Length: 2381 76 | < Content-Type: text/html 77 | < Date: Thu, 26 Oct 2023 12:22:48 GMT 78 | < Etag: "588604c8-94d" 79 | < Last-Modified: Mon, 23 Jan 2017 13:27:36 GMT 80 | < Pragma: no-cache 81 | < Server: bfe/1.0.8.18 82 | < Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/ 83 | < 84 | 85 | 百度一下,你就知道

关于百度 About Baidu

©2017 Baidu 使用百度前必读  意见反馈 京ICP证030173号 

86 | * Connection #0 to host 1.1.50.188 left intact 87 | ``` 88 | 89 | 5. let's check the tcp stream in wireshark 90 | ![wireshark](./wireshark.png) 91 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(ip_bits)] 2 | 3 | use tokio; 4 | use tokio::time::Duration; 5 | use tokio::io::{AsyncReadExt, AsyncWriteExt, WriteHalf}; 6 | use tokio_tun::Tun; 7 | use std::net::Ipv4Addr; 8 | 9 | use pnet::packet::{Packet, MutablePacket, PacketSize}; 10 | use pnet::packet::ip::IpNextHeaderProtocols; 11 | use pnet::packet::ipv4::{MutableIpv4Packet, Ipv4Packet}; 12 | use pnet::packet::tcp::{MutableTcpPacket, TcpPacket, TcpFlags}; 13 | use pnet::packet::tcp; 14 | use pnet::packet::ipv4; 15 | 16 | use ipnet::Ipv4Net; 17 | 18 | use std::sync::Arc; 19 | use std::process::exit; 20 | use tokio::sync::Mutex; 21 | 22 | use tracing::{trace, info, error}; 23 | 24 | #[derive(Clone, Debug)] 25 | struct NetMapping { 26 | dst: Ipv4Net, 27 | src: Ipv4Net, 28 | src_virtual: Ipv4Net, 29 | dst_virtual: Ipv4Net, 30 | dst_local: Ipv4Net, 31 | } 32 | 33 | async fn nat_packet(network_mapping: NetMapping, writer: Arc>>, buf: Vec) { 34 | 35 | let ipv4 = Ipv4Packet::new(&buf).unwrap(); 36 | let tcp = TcpPacket::new(ipv4.payload()).unwrap(); 37 | 38 | let mut new_ipv4_buf = vec![0 as u8; buf.len()]; 39 | let mut new_ipv4 = MutableIpv4Packet::new(&mut new_ipv4_buf).unwrap(); 40 | new_ipv4.clone_from(&ipv4); 41 | 42 | let mut direction_forward = false; 43 | 44 | if network_mapping.dst_virtual.contains(&ipv4.get_destination()) && network_mapping.src.contains(&ipv4.get_source()) && network_mapping.dst_virtual.network() != ipv4.get_source() { 45 | let new_dest = Ipv4Addr::from_bits((ipv4.get_destination().to_bits() & network_mapping.dst_virtual.hostmask().to_bits()) | network_mapping.dst.network().to_bits()); 46 | new_ipv4.set_destination(new_dest); 47 | 48 | let new_src = Ipv4Addr::from_bits((ipv4.get_source().to_bits() & network_mapping.src.hostmask().to_bits()) | network_mapping.src_virtual.network().to_bits()); 49 | new_ipv4.set_source(new_src); 50 | direction_forward = true; 51 | } 52 | else if network_mapping.dst_virtual.contains(&ipv4.get_destination()) && network_mapping.dst_virtual.network() == ipv4.get_source() { 53 | let new_dest = Ipv4Addr::from_bits((ipv4.get_destination().to_bits() & network_mapping.dst_virtual.hostmask().to_bits()) | network_mapping.dst.network().to_bits()); 54 | new_ipv4.set_destination(new_dest); 55 | 56 | let new_src = Ipv4Addr::from_bits((ipv4.get_destination().to_bits() & network_mapping.dst.hostmask().to_bits()) | network_mapping.dst_local.network().to_bits()); 57 | new_ipv4.set_source(new_src); 58 | direction_forward = true; 59 | } 60 | 61 | else if network_mapping.src_virtual.contains(&ipv4.get_destination()) && network_mapping.dst.contains(&ipv4.get_source()) && !network_mapping.dst_virtual.contains(&ipv4.get_destination()) { 62 | let new_dest = Ipv4Addr::from_bits((ipv4.get_destination().to_bits() & network_mapping.src_virtual.hostmask().to_bits()) | network_mapping.src.network().to_bits()); 63 | new_ipv4.set_destination(new_dest); 64 | 65 | let new_src = Ipv4Addr::from_bits((ipv4.get_source().to_bits() & network_mapping.dst.hostmask().to_bits()) | network_mapping.dst_virtual.network().to_bits()); 66 | new_ipv4.set_source(new_src); 67 | } 68 | else if network_mapping.dst.contains(&ipv4.get_source()) && network_mapping.dst_local.contains(&ipv4.get_destination()) { 69 | let new_dest = network_mapping.dst_virtual.network(); 70 | new_ipv4.set_destination(new_dest); 71 | 72 | let new_src = Ipv4Addr::from_bits((ipv4.get_source().to_bits() & network_mapping.dst.hostmask().to_bits()) | network_mapping.dst_virtual.network().to_bits()); 73 | new_ipv4.set_source(new_src); 74 | } 75 | else { 76 | trace!("drop ipv4 {:?}", ipv4); 77 | return 78 | } 79 | trace!("new ipv4 {:?}", new_ipv4); 80 | 81 | if (!direction_forward) || 82 | (tcp.get_flags() & (TcpFlags::SYN | TcpFlags::FIN | TcpFlags::RST | TcpFlags::URG | TcpFlags::CWR | TcpFlags::ECE)) != 0 || 83 | tcp.payload().len() <= 2 { 84 | 85 | let mut tcp_buf = vec![0 as u8; tcp.packet_size() + tcp.payload().len()]; 86 | let mut new_tcp = MutableTcpPacket::new(&mut tcp_buf).unwrap(); 87 | 88 | new_tcp.clone_from(&tcp); 89 | new_tcp.set_checksum( 90 | tcp::ipv4_checksum(&new_tcp.to_immutable(), &new_ipv4.get_source(), &new_ipv4.get_destination())); 91 | 92 | new_ipv4.set_payload(&new_tcp.packet()[..new_tcp.packet_size() + tcp.payload().len()]); 93 | new_ipv4.set_total_length(new_ipv4.get_header_length() as u16 * 4 + new_tcp.packet_size() as u16 + tcp.payload().len() as u16); 94 | new_ipv4.set_checksum(ipv4::checksum(&new_ipv4.to_immutable())); 95 | 96 | writer.lock().await.write(&new_ipv4.packet()[..new_ipv4.packet_size()]).await.unwrap(); 97 | 98 | } else { 99 | 100 | let payload_length = tcp.payload().len(); 101 | 102 | let segments = [ 103 | (2, payload_length, false), 104 | (1, payload_length, true), 105 | (0, 2, true), 106 | ]; 107 | 108 | for (start, end, good) in segments { 109 | let mut new_payload = Vec::from(&tcp.payload()[start..end]); 110 | if !good { 111 | new_payload.copy_from_slice(&vec![0x41; end-start]); 112 | } 113 | 114 | let mut tcp_buf = vec![0 as u8; tcp.packet_size() + new_payload.len()]; 115 | tcp_buf[..tcp.packet_size()].copy_from_slice(&tcp.packet()[..tcp.packet_size()]); 116 | let mut new_tcp = MutableTcpPacket::new(&mut tcp_buf).unwrap(); 117 | new_tcp.set_payload(&new_payload); 118 | 119 | new_ipv4.set_total_length(new_ipv4.get_header_length() as u16 * 4 + new_tcp.packet_size() as u16 + new_tcp.payload().len() as u16); 120 | 121 | new_tcp.set_sequence(tcp.get_sequence().wrapping_add(start as u32)); 122 | new_tcp.set_checksum( 123 | tcp::ipv4_checksum(&new_tcp.to_immutable(), &new_ipv4.get_source(), &new_ipv4.get_destination())); 124 | new_ipv4.set_payload(&new_tcp.packet()[..new_tcp.packet_size() + new_tcp.payload().len()]); 125 | new_ipv4.set_checksum(ipv4::checksum(&new_ipv4.to_immutable())); 126 | writer.lock().await.write(&new_ipv4.packet()[..new_ipv4.packet_size()]).await.unwrap(); 127 | 128 | tokio::time::sleep(Duration::from_millis(1)).await; 129 | 130 | } 131 | } 132 | } 133 | 134 | /// just a system 135 | fn system(cmdline: &str, allow_fail: bool) -> bool { 136 | use std::process::Command; 137 | info!("executing `{}`", cmdline); 138 | let args: Vec<&str> = cmdline.split(" ").collect(); 139 | let mut cmd = Command::new(args[0]); 140 | cmd.args(&args[1..]); 141 | let status = cmd.status(); 142 | 143 | let Ok(status) = status else { error!("cannot execute `{}`", cmdline); exit(1)}; 144 | 145 | if !status.success() && !allow_fail{ 146 | error!("`{}` returns non-zero", cmdline); 147 | exit(1); 148 | } 149 | return status.success(); 150 | } 151 | 152 | //fn init_tun(network_mapping: &NetMapping, tun_name: &str, interface: &str, public_ip: &str, gateway: &str) -> bool { 153 | fn init_tun(network_mapping: &NetMapping, tun_name: &str, interface: &str, public_ip: &str) { 154 | 155 | system(&format!("iptables -I DOCKER-USER -j ACCEPT"), true); // special hack for docker env 156 | system(&format!("sysctl -w net.ipv4.ip_forward=1"), false); 157 | 158 | system(&format!("ip addr add {} dev {}", network_mapping.dst_virtual.to_string(), tun_name), false); 159 | if network_mapping.dst_virtual != network_mapping.src_virtual { 160 | system(&format!("ip addr add {} dev {}", network_mapping.src_virtual.to_string(), tun_name), false); 161 | } 162 | system(&format!("ip addr add {} dev {}", network_mapping.dst_local.to_string(), tun_name), false); 163 | //let has_route = system(&format!("ip route add {} via {}", network_mapping.dst.to_string(), gateway), true); 164 | //system(&format!("iptables -t nat -D POSTROUTING -s {} -o {} -j MASQUERADE", network_mapping.src_virtual.trunc().to_string(), interface), true); 165 | //system(&format!("iptables -t nat -A POSTROUTING -s {} -o {} -j MASQUERADE", network_mapping.src_virtual.trunc().to_string(), interface), false); 166 | //system(&format!("iptables -t nat -D POSTROUTING -o {} -j MASQUERADE", tun_name), true); 167 | //system(&format!("iptables -t nat -A POSTROUTING -o {} -j MASQUERADE", tun_name), false); 168 | 169 | system(&format!("sudo iptables -t nat -D POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.src_virtual.trunc().to_string(), interface, public_ip), true); 170 | system(&format!("sudo iptables -t nat -A POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.src_virtual.trunc().to_string(), interface, public_ip), false); 171 | if network_mapping.dst_virtual != network_mapping.src_virtual { 172 | system(&format!("sudo iptables -t nat -D POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.dst_virtual.trunc().to_string(), interface, public_ip), true); 173 | system(&format!("sudo iptables -t nat -A POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.dst_virtual.trunc().to_string(), interface, public_ip), false); 174 | } 175 | system(&format!("sudo iptables -t nat -D POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.dst_local.trunc().to_string(), interface, public_ip), true); 176 | system(&format!("sudo iptables -t nat -A POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.dst_local.trunc().to_string(), interface, public_ip), false); 177 | 178 | info!("setup tun and iptables done."); 179 | //return has_route; 180 | } 181 | 182 | //fn uninit_tun(network_mapping: &NetMapping, tun_name: &str, interface: &str, public_ip: &str, gateway: &str, has_route: bool) { 183 | fn uninit_tun(network_mapping: &NetMapping, tun_name: &str, interface: &str, public_ip: &str) { 184 | system(&format!("ip addr del {} dev {}", network_mapping.src_virtual.to_string(), tun_name), true); 185 | if network_mapping.dst_virtual != network_mapping.src_virtual { 186 | system(&format!("ip addr del {} dev {}", network_mapping.dst_virtual.to_string(), tun_name), true); 187 | } 188 | system(&format!("ip addr del {} dev {}", network_mapping.dst_local.to_string(), tun_name), true); 189 | //if has_route { 190 | // system(&format!("ip route del {} via {}", network_mapping.dst.to_string(), gateway), false); 191 | //} 192 | system(&format!("sudo iptables -t nat -D POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.src_virtual.trunc().to_string(), interface, public_ip), true); 193 | if network_mapping.dst_virtual != network_mapping.src_virtual { 194 | system(&format!("sudo iptables -t nat -D POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.dst_virtual.trunc().to_string(), interface, public_ip), true); 195 | } 196 | system(&format!("sudo iptables -t nat -D POSTROUTING -s {} -o {} -j SNAT --to {}", network_mapping.dst_local.trunc().to_string(), interface, public_ip), true); 197 | } 198 | 199 | use clap::Parser; 200 | 201 | /// Simple program to greet a person 202 | #[derive(Parser, Debug)] 203 | #[command(author, version, about, long_about = None)] 204 | struct Args { 205 | /// the target network, e.g 192.168.0.0/16 206 | #[arg(long)] 207 | dst: String, 208 | 209 | /// the target network, e.g 192.168.0.0/16 210 | #[arg(long)] 211 | dst_virtual: String, 212 | 213 | /// the target network, e.g 192.168.0.0/16 214 | #[arg(long)] 215 | dst_local: String, 216 | 217 | /// the local network, with a local address. e.g 127.168.0.0/16 218 | #[arg(long)] 219 | src: Option, 220 | 221 | /// the local network, with a local address. e.g 127.168.0.0/16 222 | #[arg(long)] 223 | src_virtual: Option, 224 | 225 | 226 | /// the public interface, e.g eth1, ens160, etc. 227 | #[arg(short, long)] 228 | interface: String, 229 | 230 | /// the public ip address, e.g 172.16.90.128, etc. 231 | #[arg(short, long)] 232 | public_ip: String, 233 | 234 | // /// the public ip address, e.g 172.16.90.128, etc. 235 | // #[arg(short, long)] 236 | // gateway: String, 237 | } 238 | 239 | 240 | #[tokio::main] 241 | async fn main() { 242 | use tracing_subscriber; 243 | tracing_subscriber::fmt::init(); 244 | 245 | let args = Args::parse(); 246 | 247 | let dst = args.dst.parse().unwrap_or_else(|_|{error!("cannot parse network `{}`", args.dst); exit(1);}); 248 | let dst_virtual = args.dst_virtual.parse().unwrap_or_else(|_|{error!("cannot parse network `{}`", args.dst_virtual); exit(1);}); 249 | let dst_local = args.dst_local.parse().unwrap_or_else(|_|{error!("cannot parse network `{}`", args.dst_local); exit(1);}); 250 | let src = match args.src { 251 | Some(src) => src.parse().unwrap_or_else(|_|{error!("cannot parse network `{}`", src); exit(1);}), 252 | None => dst_virtual, 253 | }; 254 | let src_virtual = match args.src_virtual { 255 | Some(src_virtual) => src_virtual.parse().unwrap_or_else(|_|{error!("cannot parse network `{}`", src_virtual); exit(1);}), 256 | None => dst_virtual, 257 | }; 258 | 259 | let net_mapping = NetMapping { 260 | dst: dst, 261 | src: src, 262 | src_virtual: src_virtual, 263 | dst_virtual: dst_virtual, 264 | dst_local: dst_local, 265 | }; 266 | 267 | assert!(net_mapping.src.hostmask() == net_mapping.src_virtual.hostmask()); 268 | assert!(net_mapping.dst.hostmask() == net_mapping.dst_virtual.hostmask()); 269 | 270 | 271 | 272 | info!("creating tun..."); 273 | let tun = Tun::builder() 274 | .name("obfuscator_tun") // if name is empty, then it is set by kernel. 275 | .tap(false) // false (default): TUN, true: TAP. 276 | .packet_info(false) // false: IFF_NO_PI, default is true. 277 | .up() // or set it up manually using `sudo ip link set up`. 278 | .try_build() // or `.try_build_mq(queues)` for multi-queue support. 279 | .unwrap_or_else(|_| { 280 | error!("cannot create tun, run with root?"); 281 | exit(1); 282 | }); 283 | info!("tun created, name: {}", tun.name()); 284 | 285 | //let has_route = init_tun(&net_mapping, tun.name(), &args.interface, &args.public_ip, &args.gateway); 286 | init_tun(&net_mapping, tun.name(), &args.interface, &args.public_ip); 287 | 288 | let net_mapping_to_move = net_mapping.clone(); 289 | let tun_name = tun.name().to_owned(); 290 | 291 | 292 | let (mut reader, writer) = tokio::io::split(tun); 293 | let writer = Arc::new(Mutex::new(writer)); 294 | let net_mapping = net_mapping.clone(); 295 | info!("running.."); 296 | tokio::task::spawn( async move { 297 | let mut buf = [0u8; 4096]; 298 | loop { 299 | let n = reader.read(&mut buf).await.unwrap(); 300 | let mut buf = Vec::from(&buf[..n]); 301 | 302 | let Some(ipv4) = Ipv4Packet::new(&mut buf) else { continue } ; 303 | if ipv4.get_version() != 4 { continue } 304 | 305 | trace!("{:?}", ipv4); 306 | 307 | if ipv4.get_next_level_protocol() != IpNextHeaderProtocols::Tcp { continue } 308 | 309 | let Some(_tcp) = TcpPacket::new(ipv4.payload()) else {continue}; 310 | 311 | // forward this packet 312 | let writer = writer.clone(); 313 | tokio::task::spawn( 314 | nat_packet(net_mapping.clone(), writer, buf) 315 | ); 316 | } 317 | } ); 318 | 319 | tokio::signal::ctrl_c().await.expect("failed to listen for event"); 320 | //uninit_tun(&net_mapping_to_move, &tun_name, &args.interface, &args.public_ip, &args.gateway, has_route); 321 | uninit_tun(&net_mapping_to_move, &tun_name, &args.interface, &args.public_ip); 322 | } 323 | --------------------------------------------------------------------------------