libp2p_mdns/behaviour/iface/
query.rs1use super::dns;
22use crate::{META_QUERY_SERVICE_FQDN, SERVICE_NAME_FQDN};
23use libp2p_core::{
24 address_translation,
25 multiaddr::{Multiaddr, Protocol},
26};
27use libp2p_identity::PeerId;
28use std::time::Instant;
29use std::{fmt, net::SocketAddr, str, time::Duration};
30use trust_dns_proto::{
31 op::Message,
32 rr::{Name, RData},
33};
34
35#[derive(Debug)]
37pub(crate) enum MdnsPacket {
38 Query(MdnsQuery),
40 Response(MdnsResponse),
42 ServiceDiscovery(MdnsServiceDiscovery),
44}
45
46impl MdnsPacket {
47 pub(crate) fn new_from_bytes(
48 buf: &[u8],
49 from: SocketAddr,
50 ) -> Result<Option<MdnsPacket>, trust_dns_proto::error::ProtoError> {
51 let packet = Message::from_vec(buf)?;
52
53 if packet.query().is_none() {
54 return Ok(Some(MdnsPacket::Response(MdnsResponse::new(&packet, from))));
55 }
56
57 if packet
58 .queries()
59 .iter()
60 .any(|q| q.name().to_utf8() == SERVICE_NAME_FQDN)
61 {
62 return Ok(Some(MdnsPacket::Query(MdnsQuery {
63 from,
64 query_id: packet.header().id(),
65 })));
66 }
67
68 if packet
69 .queries()
70 .iter()
71 .any(|q| q.name().to_utf8() == META_QUERY_SERVICE_FQDN)
72 {
73 return Ok(Some(MdnsPacket::ServiceDiscovery(MdnsServiceDiscovery {
75 from,
76 query_id: packet.header().id(),
77 })));
78 }
79
80 Ok(None)
81 }
82}
83
84pub(crate) struct MdnsQuery {
86 from: SocketAddr,
88 query_id: u16,
90}
91
92impl MdnsQuery {
93 pub(crate) fn remote_addr(&self) -> &SocketAddr {
95 &self.from
96 }
97
98 pub(crate) fn query_id(&self) -> u16 {
100 self.query_id
101 }
102}
103
104impl fmt::Debug for MdnsQuery {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 f.debug_struct("MdnsQuery")
107 .field("from", self.remote_addr())
108 .field("query_id", &self.query_id)
109 .finish()
110 }
111}
112
113pub(crate) struct MdnsServiceDiscovery {
115 from: SocketAddr,
117 query_id: u16,
119}
120
121impl MdnsServiceDiscovery {
122 pub(crate) fn remote_addr(&self) -> &SocketAddr {
124 &self.from
125 }
126
127 pub(crate) fn query_id(&self) -> u16 {
129 self.query_id
130 }
131}
132
133impl fmt::Debug for MdnsServiceDiscovery {
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 f.debug_struct("MdnsServiceDiscovery")
136 .field("from", self.remote_addr())
137 .field("query_id", &self.query_id)
138 .finish()
139 }
140}
141
142pub(crate) struct MdnsResponse {
144 peers: Vec<MdnsPeer>,
145 from: SocketAddr,
146}
147
148impl MdnsResponse {
149 pub(crate) fn new(packet: &Message, from: SocketAddr) -> MdnsResponse {
151 let peers = packet
152 .answers()
153 .iter()
154 .filter_map(|record| {
155 if record.name().to_string() != SERVICE_NAME_FQDN {
156 return None;
157 }
158
159 let record_value = match record.data() {
160 Some(RData::PTR(record)) => record,
161 _ => return None,
162 };
163
164 MdnsPeer::new(packet, record_value, record.ttl())
165 })
166 .collect();
167
168 MdnsResponse { peers, from }
169 }
170
171 pub(crate) fn extract_discovered(
172 &self,
173 now: Instant,
174 local_peer_id: PeerId,
175 ) -> impl Iterator<Item = (PeerId, Multiaddr, Instant)> + '_ {
176 self.discovered_peers()
177 .filter(move |peer| peer.id() != &local_peer_id)
178 .flat_map(move |peer| {
179 let observed = self.observed_address();
180 let new_expiration = now + peer.ttl();
181
182 peer.addresses().iter().filter_map(move |address| {
183 let new_addr = address_translation(address, &observed)?;
184
185 Some((*peer.id(), new_addr, new_expiration))
186 })
187 })
188 }
189
190 pub(crate) fn remote_addr(&self) -> &SocketAddr {
192 &self.from
193 }
194
195 fn observed_address(&self) -> Multiaddr {
196 let obs_ip = Protocol::from(self.remote_addr().ip());
199 let obs_port = Protocol::Udp(self.remote_addr().port());
200
201 Multiaddr::empty().with(obs_ip).with(obs_port)
202 }
203
204 fn discovered_peers(&self) -> impl Iterator<Item = &MdnsPeer> {
208 self.peers.iter()
209 }
210}
211
212impl fmt::Debug for MdnsResponse {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 f.debug_struct("MdnsResponse")
215 .field("from", self.remote_addr())
216 .finish()
217 }
218}
219
220pub(crate) struct MdnsPeer {
222 addrs: Vec<Multiaddr>,
223 peer_id: PeerId,
225 ttl: u32,
227}
228
229impl MdnsPeer {
230 pub(crate) fn new(packet: &Message, record_value: &Name, ttl: u32) -> Option<MdnsPeer> {
232 let mut my_peer_id: Option<PeerId> = None;
233 let addrs = packet
234 .additionals()
235 .iter()
236 .filter_map(|add_record| {
237 if add_record.name() != record_value {
238 return None;
239 }
240
241 if let Some(RData::TXT(ref txt)) = add_record.data() {
242 Some(txt)
243 } else {
244 None
245 }
246 })
247 .flat_map(|txt| txt.iter())
248 .filter_map(|txt| {
249 let addr = match dns::decode_character_string(txt) {
251 Ok(a) => a,
252 Err(_) => return None,
253 };
254 if !addr.starts_with(b"dnsaddr=") {
255 return None;
256 }
257 let addr = match str::from_utf8(&addr[8..]) {
258 Ok(a) => a,
259 Err(_) => return None,
260 };
261 let mut addr = match addr.parse::<Multiaddr>() {
262 Ok(a) => a,
263 Err(_) => return None,
264 };
265 match addr.pop() {
266 Some(Protocol::P2p(peer_id)) => {
267 if let Some(pid) = &my_peer_id {
268 if peer_id != *pid {
269 return None;
270 }
271 } else {
272 my_peer_id.replace(peer_id);
273 }
274 }
275 _ => return None,
276 };
277 Some(addr)
278 })
279 .collect();
280
281 my_peer_id.map(|peer_id| MdnsPeer {
282 addrs,
283 peer_id,
284 ttl,
285 })
286 }
287
288 #[inline]
290 pub(crate) fn id(&self) -> &PeerId {
291 &self.peer_id
292 }
293
294 #[inline]
296 pub(crate) fn ttl(&self) -> Duration {
297 Duration::from_secs(u64::from(self.ttl))
298 }
299
300 pub(crate) fn addresses(&self) -> &Vec<Multiaddr> {
304 &self.addrs
305 }
306}
307
308impl fmt::Debug for MdnsPeer {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 f.debug_struct("MdnsPeer")
311 .field("peer_id", &self.peer_id)
312 .finish()
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use super::super::dns::build_query_response;
319 use super::*;
320
321 #[test]
322 fn test_create_mdns_peer() {
323 let ttl = 300;
324 let peer_id = PeerId::random();
325
326 let mut addr1: Multiaddr = "/ip4/1.2.3.4/tcp/5000".parse().expect("bad multiaddress");
327 let mut addr2: Multiaddr = "/ip6/::1/udp/10000".parse().expect("bad multiaddress");
328 addr1.push(Protocol::P2p(peer_id));
329 addr2.push(Protocol::P2p(peer_id));
330
331 let packets = build_query_response(
332 0xf8f8,
333 peer_id,
334 vec![&addr1, &addr2].into_iter(),
335 Duration::from_secs(60),
336 );
337
338 for bytes in packets {
339 let packet = Message::from_vec(&bytes).expect("unable to parse packet");
340 let record_value = packet
341 .answers()
342 .iter()
343 .filter_map(|record| {
344 if record.name().to_utf8() != SERVICE_NAME_FQDN {
345 return None;
346 }
347 let record_value = match record.data() {
348 Some(RData::PTR(record)) => record,
349 _ => return None,
350 };
351 Some(record_value)
352 })
353 .next()
354 .expect("empty record value");
355
356 let peer = MdnsPeer::new(&packet, record_value, ttl).expect("fail to create peer");
357 assert_eq!(peer.peer_id, peer_id);
358 }
359 }
360}