1#![cfg(target_os = "linux")]
2
3use futures::stream::TryStreamExt;
4use std::fs;
5use std::fs::Permissions;
6use std::net::IpAddr;
7use std::os::fd::{AsFd, AsRawFd};
8use std::os::unix::fs::PermissionsExt;
9use std::str::FromStr;
10
11use std::collections::HashMap;
12use std::fs::File;
13use std::io::BufRead;
14use std::path::Path;
15
16use rtnetlink::packet_route::route::RouteMessage;
17use rtnetlink::{Handle, IpVersion, LinkMessageBuilder, LinkUnspec, RouteMessageBuilder, new_connection};
18
19use cidr::IpCidr;
20
21type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
22
23use crate::{ETC_RESOLV_CONF_FILE, TproxyArgs, TproxyStateInner, run_command};
24
25static IPV6_DEFAULT_ROUTE: std::sync::LazyLock<IpCidr> = std::sync::LazyLock::new(|| IpCidr::from_str("::/0").unwrap());
26static IPV6_SPACE_LOWER: std::sync::LazyLock<IpCidr> = std::sync::LazyLock::new(|| IpCidr::from_str("::/1").unwrap());
27static IPV6_SPACE_UPPER: std::sync::LazyLock<IpCidr> = std::sync::LazyLock::new(|| IpCidr::from_str("8000::/1").unwrap());
28
29static IPV4_DEFAULT_ROUTE: std::sync::LazyLock<IpCidr> = std::sync::LazyLock::new(|| IpCidr::from_str("0.0.0.0/0").unwrap());
30static IPV4_SPACE_LOWER: std::sync::LazyLock<IpCidr> = std::sync::LazyLock::new(|| IpCidr::from_str("0.0.0.0/1").unwrap());
31static IPV4_SPACE_UPPER: std::sync::LazyLock<IpCidr> = std::sync::LazyLock::new(|| IpCidr::from_str("128.0.0.0/1").unwrap());
32
33static ROUTING_TABLE_MAIN: u32 = 254;
34
35fn bytes_to_string(bytes: Vec<u8>) -> Result<String> {
36 match String::from_utf8(bytes) {
37 Ok(content) => Ok(content),
38 Err(e) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("error converting bytes to string: {e}")).into()),
39 }
40}
41
42async fn netlink_do<F, T, R>(f: F) -> Result<R>
43where
44 F: Fn(Handle) -> T,
45 T: Future<Output = Result<R>>,
46{
47 let action = async || {
48 let (connection, handle, _) = new_connection()?;
49 tokio::spawn(connection);
50 f(handle).await
51 };
52 action().await
53}
54
55async fn ip_route_add_msg(msg: &RouteMessage) -> Result<()> {
56 netlink_do(async |handle| Ok(handle.route().add(msg.clone()).execute().await?)).await
57}
58
59async fn ip_link_get_index(dev: &str) -> Result<u32> {
60 netlink_do(async |handle| {
61 let mut interfaces = handle.link().get().match_name(String::from(dev)).execute();
62 match interfaces.try_next().await? {
63 Some(link) => Ok(link.header.index),
64 None => Err(std::io::Error::new(std::io::ErrorKind::NotFound, "Interface not found").into()),
65 }
66 })
67 .await
68}
69
70async fn ip_route_add(dest: &IpCidr, dev: &str, table: u32) -> Result<RouteMessage> {
71 let index = ip_link_get_index(dev).await?;
72 netlink_do(async |handle| {
73 let route = RouteMessageBuilder::<std::net::IpAddr>::new()
74 .destination_prefix(dest.first_address(), dest.network_length())?
75 .table_id(table)
76 .output_interface(index)
77 .build();
78 handle.route().add(route.clone()).execute().await?;
79 Ok(route)
80 })
81 .await
82}
83
84async fn ip_route_flush(table: u32, ip_version: IpVersion) -> Result<()> {
85 netlink_do(async |handle| {
86 let route = match ip_version {
87 IpVersion::V4 => RouteMessageBuilder::<std::net::Ipv4Addr>::new().table_id(table).build(),
88 IpVersion::V6 => RouteMessageBuilder::<std::net::Ipv6Addr>::new().table_id(table).build(),
89 };
90 let mut routes = handle.route().get(route).execute();
91
92 while let Some(route) = routes.try_next().await? {
93 let msg = route.clone();
94 handle.route().del(msg).execute().await?
95 }
96
97 Ok(())
98 })
99 .await
100}
101
102async fn ip_route_del_msg(msg: &RouteMessage) -> Result<()> {
103 netlink_do(async |handle| Ok(handle.route().del(msg.clone()).execute().await?)).await
104}
105
106async fn ip_link_set_up(dev: &str) -> Result<()> {
107 netlink_do(async |handle| {
108 let msg = LinkMessageBuilder::<LinkUnspec>::default().name(String::from(dev)).up().build();
109 Ok(handle.link().set(msg).execute().await?)
110 })
111 .await
112}
113
114async fn ip_link_del(dev: &str) -> Result<()> {
115 let index = ip_link_get_index(dev).await?;
116 netlink_do(async |handle| Ok(handle.link().del(index).execute().await?)).await
117}
118
119async fn ip_route_show(ip_version: IpVersion, table: u32) -> Result<Vec<RouteMessage>> {
120 netlink_do(async |handle| {
121 let route = match ip_version {
122 IpVersion::V4 => RouteMessageBuilder::<std::net::Ipv4Addr>::new().table_id(table).build(),
123 IpVersion::V6 => RouteMessageBuilder::<std::net::Ipv6Addr>::new().table_id(table).build(),
124 };
125 let mut routes = handle.route().get(route).execute();
126 let mut route_messages = Vec::new();
127 while let Some(route) = routes.try_next().await? {
128 route_messages.push(route);
129 }
130
131 route_messages.sort_by(|entry1: &RouteMessage, entry2: &RouteMessage| {
133 let mut prio1 = 0;
136 let mut prio2 = 0;
137
138 for nla in &entry1.attributes {
139 if let rtnetlink::packet_route::route::RouteAttribute::Priority(prio) = nla {
140 prio1 = *prio
141 }
142 }
143
144 for nla in &entry1.attributes {
145 if let rtnetlink::packet_route::route::RouteAttribute::Priority(prio) = nla {
146 prio2 = *prio
147 }
148 }
149
150 let prio_cmp = prio1.cmp(&prio2);
151 if prio_cmp != std::cmp::Ordering::Equal {
152 return prio_cmp;
153 }
154
155 entry2
156 .header
157 .destination_prefix_length
158 .cmp(&entry1.header.destination_prefix_length)
159 });
160
161 Ok(route_messages)
162 })
163 .await
164}
165
166async fn ip_rule_add(ip_version: IpVersion, fwmark: u32, table: u32) -> Result<()> {
167 netlink_do(async |handle| {
168 if ip_version == IpVersion::V6 {
169 Ok(handle.rule().add().v6().fw_mark(fwmark).table_id(table).execute().await?)
170 } else {
171 Ok(handle.rule().add().v4().fw_mark(fwmark).table_id(table).execute().await?)
172 }
173 })
174 .await
175}
176
177async fn ip_rule_del(ip_version: IpVersion, fwmark: u32) -> Result<()> {
178 netlink_do(async |handle| {
179 let mut rules = handle.rule().get(ip_version.clone()).execute();
180 while let Some(rule) = rules.try_next().await? {
181 if rule.attributes.iter().any(|nla| {
182 if let rtnetlink::packet_route::rule::RuleAttribute::FwMark(mark) = nla {
183 *mark == fwmark
184 } else {
185 false
186 }
187 }) {
188 return Ok(handle.rule().del(rule).execute().await?);
189 }
190 }
191 Ok(())
192 })
193 .await
194}
195
196fn route_msg_to_cidr(msg: &rtnetlink::packet_route::route::RouteMessage) -> Result<IpCidr> {
197 let mut net_addr: Option<IpAddr> = match msg.header.address_family {
198 rtnetlink::packet_route::AddressFamily::Inet => Some(IpAddr::V4(std::net::Ipv4Addr::UNSPECIFIED)),
199 rtnetlink::packet_route::AddressFamily::Inet6 => Some(IpAddr::V6(std::net::Ipv6Addr::UNSPECIFIED)),
200 _ => None,
201 };
202 let prefix_len = msg.header.destination_prefix_length;
203 let attrs = &msg.attributes;
204 for nla in attrs.iter() {
205 if let rtnetlink::packet_route::route::RouteAttribute::Destination(addr) = nla {
206 if let rtnetlink::packet_route::route::RouteAddress::Inet(ip) = addr {
207 net_addr = Some(IpAddr::V4(*ip));
208 } else if let rtnetlink::packet_route::route::RouteAddress::Inet6(ip) = addr {
209 net_addr = Some(IpAddr::V6(*ip));
210 }
211 }
212 }
213
214 if let Some(addr) = net_addr {
215 return create_cidr(addr, prefix_len);
216 }
217
218 Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "failed to find destination in message attributes").into())
219}
220
221fn bool_to_ip_version(is_ipv6: bool) -> IpVersion {
222 if is_ipv6 { IpVersion::V6 } else { IpVersion::V4 }
223}
224
225fn get_table_id(table_name: String) -> Result<u32> {
226 if let Ok(table_id) = u32::from_str(table_name.as_str()) {
227 return Ok(table_id);
228 }
229
230 for path in ["/etc/iproute2/rt_tables", "/usr/share/iproute2/rt_tables"] {
231 let rt_tables = parse_rt_tables(String::from(path))?;
232 if let Some(&id) = rt_tables.get(&table_name) {
233 return Ok(id);
234 }
235 }
236
237 Err(std::io::Error::new(std::io::ErrorKind::NotFound, format!("Routing table '{table_name}' not found")).into())
238}
239
240fn parse_rt_tables<P: AsRef<Path>>(path: P) -> Result<HashMap<String, u32>> {
242 let file = File::open(path)?;
243 let reader = std::io::BufReader::new(file);
244
245 let mut table_map = HashMap::new();
246 table_map.insert("default".to_string(), 253);
248 table_map.insert("main".to_string(), 254);
249 table_map.insert("local".to_string(), 255);
250
251 for line in reader.lines() {
252 let line = line?;
253 let line = line.trim();
254
255 if line.is_empty() || line.starts_with('#') {
257 continue;
258 }
259
260 let parts: Vec<&str> = line.split_whitespace().collect();
261 if parts.len() != 2 {
262 log::debug!("Warning: skipping malformed line: {line}");
263 continue;
264 }
265
266 match parts[0].parse::<u32>() {
267 Ok(id) => {
268 table_map.insert(parts[1].to_string(), id);
269 }
270 Err(_) => {
271 log::debug!("Warning: invalid table ID in line: {line}");
272 }
273 }
274 }
275
276 Ok(table_map)
277}
278
279async fn ip_route_get(search_cidr: &IpCidr, table: u32, strict: bool) -> Result<Option<RouteMessage>> {
281 let ip_version = bool_to_ip_version(search_cidr.is_ipv6());
282 let route_messages = ip_route_show(ip_version, table).await?;
283 for msg in route_messages {
284 let route_cidr = route_msg_to_cidr(&msg)?;
285 if strict && route_cidr == *search_cidr
286 || !strict && route_cidr.contains(&search_cidr.first_address()) && route_cidr.contains(&search_cidr.last_address())
287 {
288 return Ok(Some(msg));
289 }
290 }
291 Ok(None)
292}
293
294async fn route_exists(route: &IpCidr, table: u32, strict: bool) -> Result<bool> {
295 Ok(ip_route_get(route, table, strict).await?.is_some())
296}
297
298fn create_cidr(addr: IpAddr, len: u8) -> Result<IpCidr> {
299 match IpCidr::new(addr, len) {
300 Ok(cidr) => Ok(cidr),
301 Err(_) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, format!("failed to convert {addr}/{len} to CIDR")).into()),
302 }
303}
304
305fn write_buffer_to_fd(fd: std::os::fd::BorrowedFd<'_>, data: &[u8]) -> Result<()> {
306 let mut written = 0;
307 loop {
308 if written >= data.len() {
309 break;
310 }
311 written += nix::unistd::write(fd, &data[written..])?;
312 }
313 Ok(())
314}
315
316fn write_nameserver(fd: std::os::fd::BorrowedFd<'_>, tun_gateway: Option<IpAddr>) -> Result<()> {
317 let tun_gateway = tun_gateway.unwrap_or_else(|| "198.18.0.1".parse().unwrap());
318 let data = format!("nameserver {tun_gateway}\n");
319 nix::sys::stat::fchmod(fd.as_fd(), nix::sys::stat::Mode::from_bits(0o444).unwrap())?;
320 write_buffer_to_fd(fd, data.as_bytes())?;
321 Ok(())
322}
323
324fn ip_forwarding_file_path(ipv6: bool) -> &'static str {
325 if ipv6 {
326 "/proc/sys/net/ipv6/conf/all/forwarding"
327 } else {
328 "/proc/sys/net/ipv4/ip_forward"
329 }
330}
331
332fn ip_fowarding_enabled(ipv6: bool) -> Result<bool> {
333 let path = ip_forwarding_file_path(ipv6);
334 Ok(bytes_to_string(fs::read(path)?)?.trim() == "1")
335}
336
337fn configure_ip_forwarding(ipv6: bool, enable: bool) -> Result<()> {
338 let path = ip_forwarding_file_path(ipv6);
339 fs::write(path, if enable { "1\n" } else { "0\n" })?;
340 Ok(())
341}
342
343fn setup_resolv_conf(restore: &mut TproxyStateInner) -> Result<()> {
344 let tun_gateway = restore.tproxy_args.as_ref().map(|args| args.tun_gateway);
345 let file = tempfile::Builder::new()
351 .permissions(Permissions::from_mode(0o644))
352 .rand_bytes(32)
353 .tempfile()?;
354 write_nameserver(file.as_fd(), tun_gateway)?;
355 let source = format!("/proc/self/fd/{}", file.as_raw_fd());
356 let flags = nix::mount::MsFlags::MS_BIND;
357 let mount1 = nix::mount::mount(source.as_str().into(), ETC_RESOLV_CONF_FILE, "".into(), flags, "".into());
358 if mount1.is_ok() {
359 restore.umount_resolvconf = true;
360 let flags = nix::mount::MsFlags::MS_REMOUNT | nix::mount::MsFlags::MS_RDONLY | nix::mount::MsFlags::MS_BIND;
361 if nix::mount::mount("".into(), ETC_RESOLV_CONF_FILE, "".into(), flags, "".into()).is_err() {
362 log::warn!("failed to remount /etc/resolv.conf as readonly");
363 }
364 }
365 drop(file);
366 if mount1.is_err() {
367 log::warn!("failed to bind mount custom resolv.conf onto /etc/resolv.conf, resorting to direct write");
368
369 restore.restore_resolvconf_content = Some(fs::read(ETC_RESOLV_CONF_FILE)?);
370
371 let flags = nix::fcntl::OFlag::O_WRONLY | nix::fcntl::OFlag::O_CLOEXEC | nix::fcntl::OFlag::O_TRUNC;
372 let fd = nix::fcntl::open(ETC_RESOLV_CONF_FILE, flags, nix::sys::stat::Mode::from_bits(0o644).unwrap())?;
373 write_nameserver(fd.as_fd(), tun_gateway)?;
374 }
375 Ok(())
376}
377
378async fn do_bypass_ip(state: &mut TproxyStateInner, ip: &IpCidr) -> Result<bool> {
379 let route_info = ip_route_show(bool_to_ip_version(ip.is_ipv6()), ROUTING_TABLE_MAIN).await?;
380
381 let cidr = *ip;
382
383 for route_message in route_info {
384 let route_cidr = match route_msg_to_cidr(&route_message) {
385 Ok(cidr) => cidr,
386 Err(_) => {
387 log::debug!("failed to convert route message to CIDR: {route_message:?}");
388 continue;
389 }
390 };
391
392 if !route_cidr.contains(&cidr.first_address()) || !route_cidr.contains(&cidr.last_address()) {
394 continue;
395 }
396
397 if route_cidr.network_length() != 0 {
400 break;
401 }
402
403 let mut new_route_message = route_message.clone();
404 let dst_attr = rtnetlink::packet_route::route::RouteAttribute::Destination(match cidr.first_address() {
405 IpAddr::V4(ip) => rtnetlink::packet_route::route::RouteAddress::Inet(ip),
406 IpAddr::V6(ip) => rtnetlink::packet_route::route::RouteAddress::Inet6(ip),
407 });
408 new_route_message.header.destination_prefix_length = cidr.network_length();
409
410 let mut dst_index = None;
411 new_route_message.attributes.iter().enumerate().for_each(|(i, nla)| {
412 if let rtnetlink::packet_route::route::RouteAttribute::Destination(_) = nla {
413 dst_index = Some(i);
414 }
415 });
416
417 match dst_index {
418 Some(index) => new_route_message.attributes[index] = dst_attr,
419 None => new_route_message.attributes.push(dst_attr),
420 }
421
422 let result = ip_route_add_msg(&new_route_message).await;
423 let mut route_exists = false;
424
425 if let Err(err) = &result {
426 if let Some(io_err) = err.downcast_ref::<std::io::Error>() {
427 route_exists = io_err.kind() == std::io::ErrorKind::AlreadyExists;
428 }
429 result?;
430 }
431
432 if !route_exists {
433 log::debug!("added bypass route: {new_route_message:?}");
434 state.remove_routes.push(new_route_message);
435 } else {
436 log::debug!("bypass route already exists: {new_route_message:?}");
437 }
438
439 return Ok(true);
440 }
441 Ok(false)
442}
443
444fn setup_gateway_mode(state: &mut TproxyStateInner, tun_name: &String) -> Result<()> {
445 let args = &["-t", "nat", "-A", "POSTROUTING", "-o", tun_name.as_str(), "-j", "MASQUERADE"];
447 run_command("iptables", args)?;
448
449 let args = &["-A", "FORWARD", "-o", tun_name.as_str(), "-j", "ACCEPT"];
451 run_command("iptables", args)?;
452
453 let args = &[
455 "-A",
456 "FORWARD",
457 "-i",
458 tun_name.as_str(),
459 "-m",
460 "state",
461 "--state",
462 "RELATED,ESTABLISHED",
463 "-j",
464 "ACCEPT",
465 ];
466 run_command("iptables", args)?;
467
468 if !ip_fowarding_enabled(false)? {
469 log::debug!("IP forwarding not enabled");
470 configure_ip_forwarding(false, true)?;
471
472 state.restore_ip_forwarding = true;
473 }
474
475 let mut restore_gateway_mode = Vec::new();
476
477 restore_gateway_mode.push(format!("-t nat -D POSTROUTING -o {tun_name} -j MASQUERADE"));
479
480 restore_gateway_mode.push(format!("-D FORWARD -o {tun_name} -j ACCEPT"));
482
483 restore_gateway_mode.push(format!("-D FORWARD -i {tun_name} -m state --state RELATED,ESTABLISHED -j ACCEPT"));
485
486 state.restore_gateway_mode = Some(restore_gateway_mode);
487 log::debug!("restore gateway mode: {:?}", state.restore_gateway_mode);
488
489 Ok(())
490}
491
492async fn setup_fwmark_table(state: &mut TproxyStateInner, tproxy_args: &TproxyArgs) -> Result<()> {
493 let Some(fwmark) = tproxy_args.socket_fwmark else {
494 return Err(Box::new(std::io::Error::other("fwmark is None")));
495 };
496
497 let table = get_table_id(tproxy_args.socket_fwmark_table.clone())?;
498
499 ip_rule_add(IpVersion::V4, fwmark, table).await?;
501 ip_rule_add(IpVersion::V6, fwmark, table).await?;
502
503 ip_route_flush(table, IpVersion::V4).await?;
505 ip_route_flush(table, IpVersion::V6).await?;
506
507 let ipv4_routes = ip_route_show(IpVersion::V4, table).await?;
508 let ipv6_routes = ip_route_show(IpVersion::V6, table).await?;
509
510 for route in ipv4_routes.iter().chain(ipv6_routes.iter()) {
511 let mut cloned_route = route.clone();
512
513 cloned_route.header.table = 0;
514
515 let mut tbl_index = None;
516 cloned_route.attributes.iter().enumerate().for_each(|(i, nla)| {
517 if let rtnetlink::packet_route::route::RouteAttribute::Table(_) = nla {
518 tbl_index = Some(i);
519 }
520 });
521
522 if let Some(tbl_index) = tbl_index {
523 cloned_route.attributes[tbl_index] = rtnetlink::packet_route::route::RouteAttribute::Table(table);
524 } else {
525 cloned_route
526 .attributes
527 .push(rtnetlink::packet_route::route::RouteAttribute::Table(table));
528 }
529
530 ip_route_add_msg(route).await?;
531 }
532
533 state.restore_socket_fwmark = Vec::from([
534 crate::FwmarkRestore {
535 ip_version: IpVersion::V4,
536 fwmark,
537 table,
538 },
539 crate::FwmarkRestore {
540 ip_version: IpVersion::V6,
541 fwmark,
542 table,
543 },
544 ]);
545 log::debug!("restore socket fwmark: {:?}", state.restore_socket_fwmark);
546
547 Ok(())
548}
549
550async fn detect_routing_loop(proxy_cidr: &IpCidr, tun_name: &str) -> Result<()> {
551 let tun_interface_id = ip_link_get_index(tun_name).await?;
552 log::debug!("tun ({tun_name}) interface id: {tun_interface_id}");
553 let mut routing_loop = false;
554
555 let proxy_route = ip_route_get(proxy_cidr, ROUTING_TABLE_MAIN, false).await?;
556 if let Some(route) = proxy_route {
557 route.attributes.iter().for_each(|nla| {
558 if let rtnetlink::packet_route::route::RouteAttribute::Oif(index) = nla {
559 log::debug!("proxy route output interface index: {index}");
560 if *index == tun_interface_id {
561 routing_loop = true;
562 }
563 }
564 });
565 if routing_loop {
566 return Err(std::io::Error::other("routing loop detected".to_string()).into());
567 }
568 } else {
569 return Err(std::io::Error::new(std::io::ErrorKind::NotFound, format!("route to proxy {proxy_cidr} not found")).into());
570 }
571 Ok(())
572}
573
574pub(crate) async fn _tproxy_setup_inner(tproxy_args: &TproxyArgs, state: &mut TproxyStateInner) -> Result<()> {
575 let tun_name = &tproxy_args.tun_name;
576
577 let proxy_cidr = IpCidr::new_host(tproxy_args.proxy_addr.ip());
578
579 flush_dns_cache()?;
580
581 if tproxy_args.gateway_mode {
583 setup_gateway_mode(state, tun_name)?;
584 }
585
586 if tproxy_args.socket_fwmark.is_some() {
588 setup_fwmark_table(state, tproxy_args).await?;
589 }
590
591 ip_link_set_up(tun_name).await?;
593
594 for ip in tproxy_args.bypass_ips.iter() {
595 do_bypass_ip(state, ip).await?;
596 }
597
598 if tproxy_args.bypass_ips.is_empty() {
599 do_bypass_ip(state, &proxy_cidr).await?;
600 }
601
602 if tproxy_args.ipv4_default_route {
603 if !route_exists(&IPV4_DEFAULT_ROUTE, ROUTING_TABLE_MAIN, true).await? {
604 state
605 .remove_routes
606 .push(ip_route_add(&IPV4_DEFAULT_ROUTE, tun_name, ROUTING_TABLE_MAIN).await?);
607 } else {
608 state
609 .remove_routes
610 .push(ip_route_add(&IPV4_SPACE_LOWER, tun_name, ROUTING_TABLE_MAIN).await?);
611 state
612 .remove_routes
613 .push(ip_route_add(&IPV4_SPACE_UPPER, tun_name, ROUTING_TABLE_MAIN).await?);
614 }
615 } else {
616 let default_route = ip_route_get(&IPV4_DEFAULT_ROUTE, ROUTING_TABLE_MAIN, true).await?;
619
620 if let Some(msg) = default_route {
621 ip_route_del_msg(&msg).await?;
622 state.restore_routes.push(msg.clone());
623 } else {
624 log::debug!("no IPv4 default route found");
625 }
626 }
627
628 if tproxy_args.ipv6_default_route {
629 if !route_exists(&IPV6_DEFAULT_ROUTE, ROUTING_TABLE_MAIN, true).await? {
630 state
631 .remove_routes
632 .push(ip_route_add(&IPV6_DEFAULT_ROUTE, tun_name, ROUTING_TABLE_MAIN).await?);
633 } else {
634 state
635 .remove_routes
636 .push(ip_route_add(&IPV6_SPACE_LOWER, tun_name, ROUTING_TABLE_MAIN).await?);
637 state
638 .remove_routes
639 .push(ip_route_add(&IPV6_SPACE_UPPER, tun_name, ROUTING_TABLE_MAIN).await?);
640 }
641 } else {
642 let default_route = ip_route_get(&IPV6_DEFAULT_ROUTE, ROUTING_TABLE_MAIN, true).await?;
645
646 if let Some(msg) = default_route {
647 ip_route_del_msg(&msg).await?;
648 state.restore_routes.push(msg.clone());
649 } else {
650 log::debug!("no IPv6 default route found");
651 }
652 }
653
654 setup_resolv_conf(state)?;
655
656 detect_routing_loop(&proxy_cidr, tun_name).await?;
657
658 Ok(())
659}
660
661pub(crate) async fn _tproxy_setup(tproxy_args: &TproxyArgs) -> Result<TproxyStateInner> {
662 let mut state: TproxyStateInner = TproxyStateInner {
663 tproxy_args: Some(tproxy_args.clone()),
664 ..Default::default()
665 };
666 let result = _tproxy_setup_inner(tproxy_args, &mut state).await;
667 if result.is_err() {
668 let remove_result = _tproxy_remove(&mut state).await;
669 if let Err(remove_result) = &remove_result {
670 log::error!("tproxy removal failed: {remove_result}");
671 }
672 result?;
673 }
674 Ok(state)
675}
676
677pub(crate) async fn _tproxy_remove(state: &mut TproxyStateInner) -> Result<()> {
678 if state.tproxy_removed_done {
679 return Ok(());
680 }
681
682 state.tproxy_removed_done = true;
683 let tproxy_args = state
684 .tproxy_args
685 .as_ref()
686 .ok_or(std::io::Error::new(std::io::ErrorKind::InvalidData, "tproxy_args is None"))?;
687
688 for route in &state.restore_routes {
689 log::debug!("restoring route: {route:?}");
690 if let Err(err) = ip_route_add_msg(route).await {
691 log::debug!("ip route add {route:?} error: {err}");
692 }
693 }
694
695 for route in &state.remove_routes {
696 log::debug!("removing route: {route:?}");
697 if let Err(err) = ip_route_del_msg(route).await {
698 log::debug!("ip route del {route:?} error: {err}");
699 }
700 }
701
702 if let Some(gateway_restore) = &state.restore_gateway_mode {
703 for restore in gateway_restore {
704 log::debug!("restore gateway mode: iptables {restore}");
705
706 if let Err(_err) = run_command("iptables", &restore.split(' ').collect::<Vec<&str>>()) {
707 log::debug!("command \"iptables {restore}\" error: {_err}");
708 }
709 }
710 }
711
712 for entry in &state.restore_socket_fwmark {
713 log::debug!(
714 "restore socket fwmark: ip rule del {} table {} (v: {:?})",
715 entry.fwmark,
716 entry.table,
717 entry.ip_version
718 );
719
720 if let Err(_err) = ip_rule_del(entry.ip_version.clone(), entry.fwmark).await {
721 log::debug!("ip_rule_del error: {_err}");
722 }
723
724 if let Err(err) = ip_rule_del(entry.ip_version.clone(), entry.fwmark).await {
725 log::debug!("ip rule del fwmark {} (v: {:?}) error: {err}", entry.fwmark, entry.ip_version);
726 }
727 if let Err(err) = ip_route_flush(entry.table, entry.ip_version.clone()).await {
728 log::debug!("ip route flush table {} (v: {:?}) error: {err}", entry.table, entry.ip_version);
729 }
730 }
731
732 if state.restore_ip_forwarding {
733 log::debug!("restore ip forwarding");
734
735 if let Err(_err) = configure_ip_forwarding(false, false) {
736 log::debug!("error restoring IP forwarding: {_err}");
737 }
738 }
739
740 log::debug!("deleting link: {}", tproxy_args.tun_name);
741 if let Err(err) = ip_link_del(&tproxy_args.tun_name).await {
743 log::debug!("ip link del {} error: {err}", tproxy_args.tun_name);
744 }
745
746 if state.umount_resolvconf {
747 log::debug!("unmounting {ETC_RESOLV_CONF_FILE}");
748 nix::mount::umount(ETC_RESOLV_CONF_FILE)?;
749 }
750
751 if let Some(data) = &state.restore_resolvconf_content {
752 fs::write(ETC_RESOLV_CONF_FILE, data)?;
753 }
754
755 flush_dns_cache()?;
756
757 Ok(())
758}
759
760pub(crate) fn flush_dns_cache() -> Result<()> {
761 Ok(())
763}