web_analyzer/
domain_dns_mobile.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4pub struct DnsRecords {
5 pub a: Vec<String>,
6 pub aaaa: Vec<String>,
7 pub mx: Vec<String>,
8 pub ns: Vec<String>,
9 pub soa: Vec<String>,
10 pub txt: Vec<String>,
11 pub cname: Vec<String>,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct DomainDnsResult {
16 pub timestamp: String,
17 pub domain: String,
18 pub records: DnsRecords,
19 pub response_time_ms: u128,
20}
21
22use chrono::Utc;
23use hickory_resolver::config::*;
24use hickory_resolver::AsyncResolver;
25use std::time::Instant;
26
27pub async fn get_dns_records(
28 domain: &str,
29 progress_tx: Option<tokio::sync::mpsc::Sender<crate::ScanProgress>>,
30) -> Result<DomainDnsResult, Box<dyn std::error::Error + Send + Sync>> {
31 let start_time = Instant::now();
32
33 if let Some(t) = &progress_tx {
34 let _ = t
35 .send(crate::ScanProgress {
36 module: "DNS Records".into(),
37 percentage: 10.0,
38 message: "Initializing native DNS resolver".into(),
39 status: "Info".into(),
40 })
41 .await;
42 }
43
44 let resolver = AsyncResolver::tokio(ResolverConfig::cloudflare(), ResolverOpts::default());
46
47 let mut records_meta = DnsRecords {
48 a: vec![],
49 aaaa: vec![],
50 mx: vec![],
51 ns: vec![],
52 soa: vec![],
53 txt: vec![],
54 cname: vec![],
55 };
56
57 if let Some(t) = &progress_tx {
58 let _ = t
59 .send(crate::ScanProgress {
60 module: "DNS Records".into(),
61 percentage: 30.0,
62 message: "Looking up A and AAAA records".into(),
63 status: "Info".into(),
64 })
65 .await;
66 }
67
68 if let Ok(response) = resolver.ipv4_lookup(domain).await {
69 for ip in response.iter() {
70 records_meta.a.push(ip.to_string());
71 }
72 }
73
74 if let Ok(response) = resolver.ipv6_lookup(domain).await {
75 for ip in response.iter() {
76 records_meta.aaaa.push(ip.to_string());
77 }
78 }
79
80 if let Some(t) = &progress_tx {
81 let _ = t
82 .send(crate::ScanProgress {
83 module: "DNS Records".into(),
84 percentage: 50.0,
85 message: "Looking up MX and NS records".into(),
86 status: "Info".into(),
87 })
88 .await;
89 }
90
91 if let Ok(response) = resolver.mx_lookup(domain).await {
92 for mx in response.iter() {
93 records_meta.mx.push(format!("{} {}", mx.preference(), mx.exchange()));
94 }
95 }
96
97 if let Ok(response) = resolver.ns_lookup(domain).await {
98 for ns in response.iter() {
99 records_meta.ns.push(ns.to_string());
100 }
101 }
102
103 if let Some(t) = &progress_tx {
104 let _ = t
105 .send(crate::ScanProgress {
106 module: "DNS Records".into(),
107 percentage: 70.0,
108 message: "Looking up TXT records".into(),
109 status: "Info".into(),
110 })
111 .await;
112 }
113
114 if let Ok(response) = resolver.txt_lookup(domain).await {
115 for txt in response.iter() {
116 records_meta.txt.push(txt.to_string());
117 }
118 }
119
120 if let Some(t) = &progress_tx {
121 let _ = t
122 .send(crate::ScanProgress {
123 module: "DNS Records".into(),
124 percentage: 90.0,
125 message: "Looking up CNAME and SOA records".into(),
126 status: "Info".into(),
127 })
128 .await;
129 }
130
131 use hickory_resolver::proto::rr::RecordType;
132
133 if let Ok(response) = resolver.lookup(domain, RecordType::CNAME).await {
134 for record in response.iter() {
135 if let Some(cname) = record.as_cname() {
136 records_meta.cname.push(cname.to_string());
137 }
138 }
139 }
140
141 if let Ok(response) = resolver.lookup(domain, RecordType::SOA).await {
142 for record in response.iter() {
143 if let Some(soa) = record.as_soa() {
144 records_meta.soa.push(format!("{} {}", soa.mname(), soa.rname()));
145 }
146 }
147 }
148
149 let response_time_ms = start_time.elapsed().as_millis();
150
151 if let Some(t) = &progress_tx {
152 let _ = t
153 .send(crate::ScanProgress {
154 module: "DNS Records".into(),
155 percentage: 100.0,
156 message: "DNS analysis completed successfully".into(),
157 status: "Info".into(),
158 })
159 .await;
160 }
161
162 Ok(DomainDnsResult {
163 timestamp: Utc::now().to_rfc3339(),
164 domain: domain.to_string(),
165 records: records_meta,
166 response_time_ms,
167 })
168}