1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2
3use anyhow::Result;
4use foctet_core::id::NodeId;
5use hickory_resolver::config::{ResolverConfig, ResolverOpts};
6use hickory_resolver::error::ResolveError;
7use hickory_resolver::system_conf;
8use hickory_resolver::TokioAsyncResolver;
9use hickory_resolver::{
10 lookup::{Ipv4Lookup, Ipv6Lookup, TxtLookup},
11 lookup_ip::LookupIp,
12};
13use stackaddr::{Protocol, StackAddr};
14
15const DNS_NODEID_PREFIX: &str = "_nodeid.";
17
18pub enum Resolved {
20 One(IpAddr),
22 Many(Vec<IpAddr>),
24 NodeIds(Vec<NodeId>),
27}
28
29#[derive(Debug, Clone)]
30pub enum ResolverOption {
31 Default,
32 System,
33 Cloudflare,
34 Google,
35 Quad9,
36 Custom(ResolverConfig, ResolverOpts),
37}
38
39pub struct Resolver {
40 resolver: TokioAsyncResolver,
41}
42
43impl Resolver {
44 pub fn new() -> Result<Self> {
46 Ok(Self {
47 resolver: TokioAsyncResolver::tokio(
48 ResolverConfig::cloudflare(),
49 ResolverOpts::default(),
50 ),
51 })
52 }
53 pub fn custom(cfg: ResolverConfig, opts: ResolverOpts) -> Self {
55 Self {
56 resolver: TokioAsyncResolver::tokio(cfg, opts),
57 }
58 }
59 pub fn system() -> Result<Self> {
61 let (cfg, opts) = system_conf::read_system_conf()?;
62 Ok(Self::custom(cfg, opts))
63 }
64
65 pub fn from_option(option: ResolverOption) -> Result<Self> {
66 match option {
67 ResolverOption::Default => Self::new(),
68 ResolverOption::System => Self::system(),
69 ResolverOption::Cloudflare => Ok(Self::custom(
70 ResolverConfig::cloudflare(),
71 ResolverOpts::default(),
72 )),
73 ResolverOption::Google => Ok(Self::custom(
74 ResolverConfig::google(),
75 ResolverOpts::default(),
76 )),
77 ResolverOption::Quad9 => Ok(Self::custom(
78 ResolverConfig::quad9(),
79 ResolverOpts::default(),
80 )),
81 ResolverOption::Custom(cfg, opts) => Ok(Self::custom(cfg, opts)),
82 }
83 }
84
85 pub async fn lookup_ip(&self, name: String) -> Result<Vec<IpAddr>, ResolveError> {
86 let lookup: LookupIp = self.resolver.lookup_ip(name).await?;
87 let mut ips = Vec::new();
88 for ip in lookup.into_iter() {
89 ips.push(ip);
90 }
91 Ok(ips)
92 }
93
94 pub async fn ipv4_lookup(&self, name: String) -> Result<Vec<Ipv4Addr>, ResolveError> {
95 let lookup: Ipv4Lookup = self.resolver.ipv4_lookup(name).await?;
96 let mut ips = Vec::new();
97 for ip in lookup.into_iter() {
98 ips.push(ip.0);
99 }
100 Ok(ips)
101 }
102
103 pub async fn ipv6_lookup(&self, name: String) -> Result<Vec<Ipv6Addr>, ResolveError> {
104 let lookup: Ipv6Lookup = self.resolver.ipv6_lookup(name).await?;
105 let mut ips = Vec::new();
106 for ip in lookup.into_iter() {
107 ips.push(ip.0);
108 }
109 Ok(ips)
110 }
111
112 pub async fn txt_lookup(&self, name: String) -> Result<TxtLookup, ResolveError> {
113 self.resolver.txt_lookup(name).await
114 }
115
116 pub async fn resolve(&self, name: String) -> Result<Resolved, ResolveError> {
117 let ips = self.lookup_ip(name.clone()).await?;
118 if ips.len() == 1 {
119 return Ok(Resolved::One(ips[0]));
120 }
121 if ips.len() > 1 {
122 return Ok(Resolved::Many(ips));
123 }
124 let name = [DNS_NODEID_PREFIX, &name].concat();
125 let txts = self.txt_lookup(name).await?;
126 let mut node_ids = Vec::new();
127 for txt in txts {
128 if let Some(chars) = txt.txt_data().first() {
130 let s = match std::str::from_utf8(chars) {
131 Ok(s) => s,
132 Err(_) => continue,
133 };
134 match NodeId::from_base32(s) {
135 Ok(node_id) => {
136 node_ids.push(node_id);
137 }
138 Err(_) => {
139 }
141 }
142 }
143 }
144 Ok(Resolved::NodeIds(node_ids))
145 }
146
147 pub async fn resolve_addr(&self, addr: &mut StackAddr) -> Result<()> {
148 if addr.resolved() {
149 return Ok(());
150 }
151 let dns = if let Some(dns) = addr.get_dns() {
152 dns
153 } else {
154 return Err(anyhow::anyhow!("Invalid address(No DNS)"));
155 };
156 match dns {
157 Protocol::Dns(name) => {
158 let ips = self.lookup_ip(name.to_string()).await?;
159 for ip in ips {
160 addr.resolve(ip);
161 break;
162 }
163 }
164 Protocol::Dns4(name) => {
165 let ips = self.ipv4_lookup(name.to_string()).await?;
166 for ip in ips {
167 addr.resolve(IpAddr::V4(ip));
168 break;
169 }
170 }
171 Protocol::Dns6(name) => {
172 let ips = self.ipv6_lookup(name.to_string()).await?;
173 for ip in ips {
174 addr.resolve(IpAddr::V6(ip));
175 break;
176 }
177 }
178 _ => {
179 return Err(anyhow::anyhow!("Invalid address. Not supported"));
180 }
181 }
182 if addr.resolved() {
183 return Ok(());
184 } else {
185 return Err(anyhow::anyhow!("Invalid address. Not resolved"));
186 }
187 }
188}