1use std::io::{Cursor, Read, Write};
4
5use anyhow::Result;
6
7use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
8use socket2::{Domain, Protocol, Type};
9
10pub const TYPE_A: u16 = 1;
11pub const TYPE_PTR: u16 = 12;
12pub const TYPE_TXT: u16 = 16;
13pub const TYPE_AAAA: u16 = 28;
14pub const TYPE_SRV: u16 = 33;
15pub const QTYPE_ANY: u16 = 0xff;
16
17fn encode_label(label: &str, out: &mut Vec<u8>) -> Result<()> {
18 for seg in label.split(".") {
19 let bytes = seg.as_bytes();
20 out.write_u8(bytes.len() as u8)?;
21 out.write_all(bytes)?;
22 }
23 out.write_u8(0)?;
24 Ok(())
25}
26
27fn create_query(label: &str, qtype: u16) -> Result<Vec<u8>> {
28 let mut out = Vec::with_capacity(512);
29 out.write_u16::<BigEndian>(0)?; out.write_u16::<BigEndian>(0)?; out.write_u16::<BigEndian>(1)?; out.write_u16::<BigEndian>(0)?; out.write_u16::<BigEndian>(0)?; out.write_u16::<BigEndian>(0)?; encode_label(label, &mut out)?;
37
38 out.write_u16::<BigEndian>(qtype)?;
39 out.write_u16::<BigEndian>(0x0001)?; Ok(out)
41}
42
43fn read_label(data: &[u8], cursor: &mut Cursor<&[u8]>) -> Result<String> {
44 let mut out = Vec::new();
45 loop {
46 let n = cursor.read_u8()?;
47 if n == 0 {
48 break;
49 } else if n & 0xc0 == 0xc0 {
50 let off = {
51 let off = n & 0x3f;
52 ((off as usize) << 8) | (cursor.read_u8()? as u16) as usize
53 };
54 let frag = read_label(data, &mut Cursor::new(&data[off..]))?;
55 out.extend_from_slice(frag.as_bytes());
56 break;
57 } else {
58 let mut b = vec![0; n as usize];
59 cursor.read_exact(&mut b)?;
60 out.extend_from_slice(&b);
61 out.extend_from_slice(b".");
62 }
63 }
64 Ok(std::str::from_utf8(&out)?.to_owned())
65}
66
67#[derive(Debug, Eq, PartialEq, Hash)]
68pub struct RR {
69 pub name: String,
70 pub typ: u16,
71 pub class: u16,
72 pub ttl: u32,
73 pub rdata: Vec<u8>,
74}
75
76#[derive(Debug, Eq, PartialEq, Hash)]
77pub struct Query {
78 pub name: String,
79 pub typ: u16,
80 pub class: u16,
81}
82
83#[derive(Debug, Eq, PartialEq, Hash)]
84pub struct DnsMessage {
85 pub source: std::net::SocketAddr,
86 pub transaction: u16,
87 pub flags: u16,
88 pub queries: Vec<Query>,
89 pub answers: Vec<RR>,
90 pub authority: Vec<RR>,
91 pub additional: Vec<RR>,
92}
93
94impl RR {
95 pub fn dump(&self, indent: usize) {
96 println!(
97 "{} {} {}",
98 " ".to_owned().repeat(indent),
99 self.name,
100 self.typ
101 )
102 }
103}
104
105impl Query {
106 pub fn dump(&self, indent: usize) {
107 println!(
108 "{} {} {}",
109 " ".to_owned().repeat(indent),
110 self.name,
111 self.typ
112 )
113 }
114}
115
116impl DnsMessage {
117 pub fn dump(&self) {
118 println!("{:?} {} {:x}", self.source, self.transaction, self.flags);
119 println!(" queries:");
120 for queries in &self.queries {
121 queries.dump(4);
122 }
123 println!(" answers:");
124 for answer in &self.answers {
125 answer.dump(4);
126 }
127 println!(" authority:");
128 for authority in &self.authority {
129 authority.dump(4);
130 }
131 println!(" additional:");
132 for additional in &self.additional {
133 additional.dump(4);
134 }
135 }
136}
137
138fn parse_rr(data: &[u8], cursor: &mut Cursor<&[u8]>) -> Result<RR> {
139 let name = read_label(data, cursor)?;
140 let typ = cursor.read_u16::<BigEndian>()?;
141 let class = cursor.read_u16::<BigEndian>()?;
142 let ttl = cursor.read_u32::<BigEndian>()?;
143 let dlen = cursor.read_u16::<BigEndian>()?;
144 let mut rdata = vec![0; dlen as usize];
145 cursor.read_exact(&mut rdata)?;
146
147 Ok(RR {
148 name,
149 typ,
150 class,
151 ttl,
152 rdata,
153 })
154}
155
156fn parse_q(data: &[u8], cursor: &mut Cursor<&[u8]>) -> Result<Query> {
157 let name = read_label(data, cursor)?;
158 let typ = cursor.read_u16::<BigEndian>()?;
159 let class = cursor.read_u16::<BigEndian>()?;
160
161 Ok(Query { name, typ, class })
162}
163
164fn parse_dns(data: &[u8], source: std::net::SocketAddr) -> Result<DnsMessage> {
165 let mut cursor = Cursor::new(data);
166 let transaction = cursor.read_u16::<BigEndian>()?;
167 let flags = cursor.read_u16::<BigEndian>()?;
168 let nquestions = cursor.read_u16::<BigEndian>()?;
169 let nanswers = cursor.read_u16::<BigEndian>()?;
170 let nauthority = cursor.read_u16::<BigEndian>()?;
171 let nadditional = cursor.read_u16::<BigEndian>()?;
172
173 let mut queries = Vec::new();
174 let mut answers = Vec::new();
175 let mut additional = Vec::new();
176 let mut authority = Vec::new();
177
178 for _ in 0..nquestions {
179 queries.push(parse_q(data, &mut cursor)?);
180 }
181 for _ in 0..nanswers {
182 answers.push(parse_rr(data, &mut cursor)?);
183 }
184 for _ in 0..nauthority {
185 authority.push(parse_rr(data, &mut cursor)?);
186 }
187 for _ in 0..nadditional {
188 additional.push(parse_rr(data, &mut cursor)?);
189 }
190
191 Ok(DnsMessage {
192 source,
193 transaction,
194 flags,
195 queries,
196 answers,
197 authority,
198 additional,
199 })
200}
201
202async fn discoverv4(
203 label: &str,
204 qtype: u16,
205 sender: tokio::sync::mpsc::UnboundedSender<DnsMessage>,
206 cancel: tokio_util::sync::CancellationToken,
207) -> Result<()> {
208 let stdsocket = socket2::Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP))?;
209 stdsocket.set_reuse_address(true)?;
210 #[cfg(not(target_os = "windows"))]
211 stdsocket.set_reuse_port(true)?;
212 let addr: std::net::SocketAddrV4 = "0.0.0.0:5353".parse()?;
213 stdsocket.bind(&socket2::SockAddr::from(addr))?;
214 let maddr: std::net::Ipv4Addr = "224.0.0.251".parse()?;
215 stdsocket.join_multicast_v4(&maddr, &std::net::Ipv4Addr::UNSPECIFIED)?;
216 stdsocket.set_nonblocking(true)?;
217 let socket = tokio::net::UdpSocket::from_std(stdsocket.into())?;
218 let query = create_query(label, qtype)?;
219 socket.send_to(&query, "224.0.0.251:5353").await?;
220 loop {
221 let mut buf = vec![0; 1024];
222 let (n, addr) = tokio::select! {
224 v = socket.recv_from(&mut buf) => v?,
225 _ = cancel.cancelled() => return Ok(())
226 };
227
228 buf.resize(n, 0);
229 let dns = parse_dns(&buf, addr)?;
230 if dns.flags == 0 {
231 continue;
233 }
234 sender.send(dns)?;
235 }
236}
237
238async fn discoverv6(
239 label: &str,
240 qtype: u16,
241 interface: u32,
242 sender: tokio::sync::mpsc::UnboundedSender<DnsMessage>,
243 cancel: tokio_util::sync::CancellationToken,
244) -> Result<()> {
245 let stdsocket = socket2::Socket::new(Domain::IPV6, Type::DGRAM, Some(Protocol::UDP))?;
246 stdsocket.set_reuse_address(true)?;
247 #[cfg(not(target_os = "windows"))]
248 stdsocket.set_reuse_port(true)?;
249 let addr: std::net::SocketAddrV6 = "[::]:5353".parse()?;
250 stdsocket.bind(&socket2::SockAddr::from(addr))?;
251 let maddr: std::net::Ipv6Addr = "ff02::fb".parse()?;
252 stdsocket.join_multicast_v6(&maddr, interface)?;
253 stdsocket.set_multicast_if_v6(interface)?;
254 stdsocket.set_nonblocking(true)?;
255 let socket = tokio::net::UdpSocket::from_std(stdsocket.into())?;
256 let query = create_query(label, qtype)?;
257 socket.send_to(&query, "[ff02::fb]:5353").await?;
258 loop {
259 let mut buf = vec![0; 1024];
260 let (n, addr) = tokio::select! {
262 v = socket.recv_from(&mut buf) => v?,
263 _ = cancel.cancelled() => return Ok(())
264 };
265 buf.resize(n, 0);
266 let dns = parse_dns(&buf, addr)?;
267 if dns.flags == 0 {
268 continue;
270 }
271 sender.send(dns)?;
272 }
273}
274
275pub async fn discover(
276 label: &str,
277 qtype: u16,
278 sender: tokio::sync::mpsc::UnboundedSender<DnsMessage>,
279 stop: tokio_util::sync::CancellationToken,
280) -> Result<()> {
281 let ifaces = if_addrs::get_if_addrs();
282 if let Ok(ifaces) = ifaces {
283 for iface in ifaces {
284 let stop_child = stop.child_token();
285 if !iface.ip().is_ipv6() {
286 continue;
287 }
288 if let Some(index) = iface.index {
289 let sender2 = sender.clone();
290 let label = label.to_owned();
291 tokio::spawn(async move {
292 _ = discoverv6(&label, qtype, index, sender2, stop_child).await;
293 });
294 }
295 }
296 };
297
298 let stop_child = stop.child_token();
299 let label = label.to_owned();
300 tokio::spawn(async move {
301 _ = discoverv4(&label, qtype, sender, stop_child).await;
302 });
303
304 Ok(())
305}