-
Notifications
You must be signed in to change notification settings - Fork 144
Expand file tree
/
Copy pathsystem_linux.rs
More file actions
116 lines (96 loc) · 3.01 KB
/
system_linux.rs
File metadata and controls
116 lines (96 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use std::sync::atomic::AtomicBool;
use async_trait::async_trait;
use hickory_resolver::TokioResolver;
use rand::seq::IteratorRandom;
use crate::app::dns::{ClashResolver, ResolverKind};
pub struct SystemResolver {
inner: TokioResolver,
ipv6: AtomicBool,
}
/// Bug in libc, use tokio impl instead: https://sourceware.org/bugzilla/show_bug.cgi?id=10652
impl SystemResolver {
pub fn new(ipv6: bool) -> anyhow::Result<Self> {
Ok(Self {
inner: TokioResolver::tokio_from_system_conf()?,
ipv6: AtomicBool::new(ipv6),
})
}
}
#[async_trait]
impl ClashResolver for SystemResolver {
async fn resolve(
&self,
host: &str,
_: bool,
) -> anyhow::Result<Option<std::net::IpAddr>> {
let response = self.inner.lookup_ip(host).await?;
Ok(response
.iter()
.filter(|x| self.ipv6() || x.is_ipv4())
.choose(&mut rand::rng()))
}
async fn resolve_v4(
&self,
host: &str,
_: bool,
) -> anyhow::Result<Option<std::net::Ipv4Addr>> {
let response = self.inner.ipv4_lookup(host).await?;
Ok(response.iter().map(|x| x.0).choose(&mut rand::rng()))
}
async fn resolve_v6(
&self,
host: &str,
_: bool,
) -> anyhow::Result<Option<std::net::Ipv6Addr>> {
let response = self.inner.ipv6_lookup(host).await?;
Ok(response.iter().map(|x| x.0).choose(&mut rand::rng()))
}
async fn cached_for(&self, _: std::net::IpAddr) -> Option<String> {
None
}
async fn exchange(
&self,
_: &hickory_proto::op::Message,
) -> anyhow::Result<hickory_proto::op::Message> {
Err(anyhow::anyhow!("unsupported"))
}
fn ipv6(&self) -> bool {
self.ipv6.load(std::sync::atomic::Ordering::Relaxed)
}
fn set_ipv6(&self, val: bool) {
self.ipv6.store(val, std::sync::atomic::Ordering::Relaxed);
}
fn kind(&self) -> ResolverKind {
ResolverKind::System
}
fn fake_ip_enabled(&self) -> bool {
false
}
async fn is_fake_ip(&self, _: std::net::IpAddr) -> bool {
false
}
async fn reverse_lookup(&self, _: std::net::IpAddr) -> Option<String> {
None
}
}
#[cfg(test)]
mod tests {
use hickory_resolver::TokioResolver;
use crate::app::dns::{ClashResolver, SystemResolver};
#[tokio::test]
async fn test_system_resolver_with_bad_labels() {
let resolver = TokioResolver::tokio_from_system_conf().unwrap();
let response = resolver.lookup_ip("some_under_store.com").await;
assert!(response.is_err());
assert_eq!(
response.unwrap_err().to_string(),
"proto error: Label contains invalid characters: Err(Errors)"
);
}
#[tokio::test]
async fn test_system_resolver_default_config() {
let resolver = SystemResolver::new(false).unwrap();
let response = resolver.resolve("www.google.com", false).await.unwrap();
assert!(response.is_some());
}
}