1 // Copyright 2015-2018 Benjamin Fry <benjaminfry@me.com>
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 
8 //! `DnsResponse` wraps a `Message` and any associated connection details
9 
10 use std::future::Future;
11 use std::io;
12 use std::ops::{Deref, DerefMut};
13 use std::pin::Pin;
14 use std::slice::{Iter, IterMut};
15 use std::task::{Context, Poll};
16 
17 use futures_channel::oneshot;
18 use futures_util::ready;
19 use smallvec::SmallVec;
20 
21 use crate::error::{ProtoError, ProtoResult};
22 use crate::op::{Message, ResponseCode};
23 use crate::rr::rdata::SOA;
24 use crate::rr::RecordType;
25 
26 /// A future returning a DNS response
27 pub struct DnsResponseFuture(DnsResponseFutureInner);
28 
29 impl Future for DnsResponseFuture {
30     type Output = Result<DnsResponse, ProtoError>;
31 
poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>32     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
33         use DnsResponseFutureInner::*;
34         Poll::Ready(match &mut self.0 {
35             Timeout(fut) => match ready!(fut.as_mut().poll(cx)) {
36                 Ok(x) => x,
37                 Err(e) => Err(e.into()),
38             },
39             Receiver(ref mut fut) => match ready!(Pin::new(fut).poll(cx)) {
40                 Ok(x) => x,
41                 Err(_) => Err(ProtoError::from("the completion was canceled")),
42             },
43             Error(err) => Err(err.take().expect("cannot poll after complete")),
44             Boxed(fut) => ready!(fut.as_mut().poll(cx)),
45         })
46     }
47 }
48 
49 impl From<TimeoutFuture> for DnsResponseFuture {
from(f: TimeoutFuture) -> Self50     fn from(f: TimeoutFuture) -> Self {
51         DnsResponseFuture(DnsResponseFutureInner::Timeout(f))
52     }
53 }
54 
55 impl From<oneshot::Receiver<ProtoResult<DnsResponse>>> for DnsResponseFuture {
from(receiver: oneshot::Receiver<ProtoResult<DnsResponse>>) -> Self56     fn from(receiver: oneshot::Receiver<ProtoResult<DnsResponse>>) -> Self {
57         DnsResponseFuture(DnsResponseFutureInner::Receiver(receiver))
58     }
59 }
60 
61 impl From<ProtoError> for DnsResponseFuture {
from(e: ProtoError) -> Self62     fn from(e: ProtoError) -> Self {
63         DnsResponseFuture(DnsResponseFutureInner::Error(Some(e)))
64     }
65 }
66 
67 impl<F> From<Pin<Box<F>>> for DnsResponseFuture
68 where
69     F: Future<Output = Result<DnsResponse, ProtoError>> + Send + 'static,
70 {
from(f: Pin<Box<F>>) -> Self71     fn from(f: Pin<Box<F>>) -> Self {
72         DnsResponseFuture(DnsResponseFutureInner::Boxed(
73             f as Pin<Box<dyn Future<Output = Result<DnsResponse, ProtoError>> + Send>>,
74         ))
75     }
76 }
77 
78 enum DnsResponseFutureInner {
79     Timeout(TimeoutFuture),
80     Receiver(oneshot::Receiver<ProtoResult<DnsResponse>>),
81     Error(Option<ProtoError>),
82     Boxed(Pin<Box<dyn Future<Output = Result<DnsResponse, ProtoError>> + Send>>),
83 }
84 
85 type TimeoutFuture = Pin<
86     Box<dyn Future<Output = Result<Result<DnsResponse, ProtoError>, io::Error>> + Send + 'static>,
87 >;
88 
89 // TODO: this needs to have the IP addr of the remote system...
90 // TODO: see https://github.com/bluejekyll/trust-dns/issues/383 for removing vec of messages and instead returning a Stream
91 /// A DNS response object
92 ///
93 /// For Most DNS requests, only one response is expected, the exception is a multicast request.
94 #[derive(Clone, Debug)]
95 pub struct DnsResponse(SmallVec<[Message; 1]>);
96 
97 // TODO: when `impl Trait` lands in stable, remove this, and expose FlatMap over answers, et al.
98 impl DnsResponse {
99     /// Get all the messages in the Response
messages(&self) -> Iter<'_, Message>100     pub fn messages(&self) -> Iter<'_, Message> {
101         self.0.as_slice().iter()
102     }
103 
104     /// Get all the messages in the Response
messages_mut(&mut self) -> IterMut<'_, Message>105     pub fn messages_mut(&mut self) -> IterMut<'_, Message> {
106         self.0.as_mut_slice().iter_mut()
107     }
108 
109     /// returns the number of messages in the response
len(&self) -> usize110     pub fn len(&self) -> usize {
111         self.0.len()
112     }
113 
114     /// returns the number of messages in the response
is_empty(&self) -> bool115     pub fn is_empty(&self) -> bool {
116         self.0.is_empty()
117     }
118 
119     /// Retrieves the SOA from the response. This will only exist if it was an authoritative response.
soa(&self) -> Option<SOA>120     pub fn soa(&self) -> Option<SOA> {
121         self.name_servers()
122             .iter()
123             .filter_map(|record| record.rdata().as_soa())
124             .next()
125             .cloned()
126     }
127 
128     /// Looks in the authority section for an SOA record from the response, and returns the negative_ttl, None if not available.
129     ///
130     /// ```text
131     /// [RFC 2308](https://tools.ietf.org/html/rfc2308#section-5) DNS NCACHE March 1998
132     ///
133     /// 5 - Caching Negative Answers
134     ///
135     ///   Like normal answers negative answers have a time to live (TTL).  As
136     ///   there is no record in the answer section to which this TTL can be
137     ///   applied, the TTL must be carried by another method.  This is done by
138     ///   including the SOA record from the zone in the authority section of
139     ///   the reply.  When the authoritative server creates this record its TTL
140     ///   is taken from the minimum of the SOA.MINIMUM field and SOA's TTL.
141     ///   This TTL decrements in a similar manner to a normal cached answer and
142     ///   upon reaching zero (0) indicates the cached negative answer MUST NOT
143     ///   be used again.
144     ///
145     ///   A negative answer that resulted from a name error (NXDOMAIN) should
146     ///   be cached such that it can be retrieved and returned in response to
147     ///   another query for the same <QNAME, QCLASS> that resulted in the
148     ///   cached negative response.
149     ///
150     ///   A negative answer that resulted from a no data error (NODATA) should
151     ///   be cached such that it can be retrieved and returned in response to
152     ///   another query for the same <QNAME, QTYPE, QCLASS> that resulted in
153     ///   the cached negative response.
154     ///
155     ///   The NXT record, if it exists in the authority section of a negative
156     ///   answer received, MUST be stored such that it can be be located and
157     ///   returned with SOA record in the authority section, as should any SIG
158     ///   records in the authority section.  For NXDOMAIN answers there is no
159     ///   "necessary" obvious relationship between the NXT records and the
160     ///   QNAME.  The NXT record MUST have the same owner name as the query
161     ///   name for NODATA responses.
162     ///
163     ///   Negative responses without SOA records SHOULD NOT be cached as there
164     ///   is no way to prevent the negative responses looping forever between a
165     ///   pair of servers even with a short TTL.
166     ///
167     ///   Despite the DNS forming a tree of servers, with various mis-
168     ///   configurations it is possible to form a loop in the query graph, e.g.
169     ///   two servers listing each other as forwarders, various lame server
170     ///   configurations.  Without a TTL count down a cache negative response
171     ///   when received by the next server would have its TTL reset.  This
172     ///   negative indication could then live forever circulating between the
173     ///   servers involved.
174     ///
175     ///   As with caching positive responses it is sensible for a resolver to
176     ///   limit for how long it will cache a negative response as the protocol
177     ///   supports caching for up to 68 years.  Such a limit should not be
178     ///   greater than that applied to positive answers and preferably be
179     ///   tunable.  Values of one to three hours have been found to work well
180     ///   and would make sensible a default.  Values exceeding one day have
181     ///   been found to be problematic.
182     /// ```
negative_ttl(&self) -> Option<u32>183     pub fn negative_ttl(&self) -> Option<u32> {
184         // TODO: should this ensure that the SOA zone matches the Queried Zone?
185         self.name_servers()
186             .iter()
187             .filter_map(|record| record.rdata().as_soa().map(|soa| (record.ttl(), soa)))
188             .next()
189             .map(|(ttl, soa)| (ttl as u32).min(soa.minimum()).max(0))
190     }
191 
192     /// Does the response contain any records matching the query name and type?
contains_answer(&self) -> bool193     pub fn contains_answer(&self) -> bool {
194         for q in self.queries() {
195             let found = match q.query_type() {
196                 RecordType::ANY => self.all_sections().any(|r| r.name() == q.name()),
197                 RecordType::SOA => {
198                     // for SOA name must be part of the SOA zone
199                     self.all_sections()
200                         .filter(|r| r.record_type().is_soa())
201                         .any(|r| r.name().zone_of(q.name()))
202                 }
203                 q_type => {
204                     if !self.answers().is_empty() {
205                         true
206                     } else {
207                         self.all_sections()
208                             .filter(|r| r.record_type() == q_type)
209                             .any(|r| r.name() == q.name())
210                     }
211                 }
212             };
213 
214             if found {
215                 return true;
216             }
217         }
218 
219         false
220     }
221 
222     /// Retrieve the type of the negative response.
223     ///   The Various types should be handled when caching or otherwise differently.
224     ///
225     /// See [NegativeType]
negative_type(&self) -> Option<NegativeType>226     pub fn negative_type(&self) -> Option<NegativeType> {
227         let response_code = self.response_code();
228         let ttl_from_soa = self.negative_ttl();
229         let has_soa = ttl_from_soa.map_or(false, |_| true);
230         let has_ns_records = self.name_servers().iter().any(|r| r.record_type().is_ns());
231         let has_cname = self.answers().iter().any(|r| r.record_type().is_cname());
232         let has_non_cname = self.answers().iter().any(|r| !r.record_type().is_cname());
233         let has_additionals = self.additional_count() > 0;
234 
235         match (
236             response_code,
237             has_soa,
238             has_ns_records,
239             has_cname,
240             has_non_cname,
241             has_additionals,
242         ) {
243             (ResponseCode::NXDomain, true, true, _, false, _) => Some(NegativeType::NameErrorType1),
244             (ResponseCode::NXDomain, true, false, _, false, _) => {
245                 Some(NegativeType::NameErrorType2)
246             }
247             (ResponseCode::NXDomain, false, false, true, false, _) => {
248                 Some(NegativeType::NameErrorType3)
249             }
250             (ResponseCode::NXDomain, false, true, _, false, _) => {
251                 Some(NegativeType::NameErrorType4)
252             }
253             (ResponseCode::NoError, true, true, false, false, _) => Some(NegativeType::NoDataType1),
254             (ResponseCode::NoError, true, false, false, false, _) => {
255                 Some(NegativeType::NoDataType2)
256             }
257             (ResponseCode::NoError, false, false, false, false, false) => {
258                 Some(NegativeType::NoDataType3)
259             }
260             (ResponseCode::NoError, false, true, _, false, _) => Some(NegativeType::Referral),
261             _ => None,
262         }
263     }
264 }
265 
266 impl Deref for DnsResponse {
267     type Target = Message;
268 
deref(&self) -> &Self::Target269     fn deref(&self) -> &Self::Target {
270         &self.0[0]
271     }
272 }
273 
274 impl DerefMut for DnsResponse {
deref_mut(&mut self) -> &mut Self::Target275     fn deref_mut(&mut self) -> &mut Self::Target {
276         &mut self.0[0]
277     }
278 }
279 
280 impl From<DnsResponse> for Message {
from(mut response: DnsResponse) -> Message281     fn from(mut response: DnsResponse) -> Message {
282         response.0.remove(0)
283     }
284 }
285 
286 impl From<Message> for DnsResponse {
from(message: Message) -> DnsResponse287     fn from(message: Message) -> DnsResponse {
288         DnsResponse(SmallVec::from([message]))
289     }
290 }
291 
292 impl From<SmallVec<[Message; 1]>> for DnsResponse {
from(messages: SmallVec<[Message; 1]>) -> DnsResponse293     fn from(messages: SmallVec<[Message; 1]>) -> DnsResponse {
294         debug_assert!(
295             !messages.is_empty(),
296             "There should be at least one message in any DnsResponse"
297         );
298         DnsResponse(messages)
299     }
300 }
301 
302 /// ```text
303 /// [RFC 2308](https://tools.ietf.org/html/rfc2308#section-2) DNS NCACHE March 1998
304 ///
305 ///
306 /// 2 - Negative Responses
307 ///
308 ///    The most common negative responses indicate that a particular RRset
309 ///    does not exist in the DNS.  The first sections of this document deal
310 ///    with this case.  Other negative responses can indicate failures of a
311 ///    nameserver, those are dealt with in section 7 (Other Negative
312 ///    Responses).
313 ///
314 ///    A negative response is indicated by one of the following conditions:
315 ///
316 /// 2.1 - Name Error
317 ///
318 ///    Name errors (NXDOMAIN) are indicated by the presence of "Name Error"
319 ///    in the RCODE field.  In this case the domain referred to by the QNAME
320 ///    does not exist.  Note: the answer section may have SIG and CNAME RRs
321 ///    and the authority section may have SOA, NXT [RFC2065] and SIG RRsets.
322 ///
323 ///    It is possible to distinguish between a referral and a NXDOMAIN
324 ///    response by the presense of NXDOMAIN in the RCODE regardless of the
325 ///    presence of NS or SOA records in the authority section.
326 ///
327 ///    NXDOMAIN responses can be categorised into four types by the contents
328 ///    of the authority section.  These are shown below along with a
329 ///    referral for comparison.  Fields not mentioned are not important in
330 ///    terms of the examples.
331 ///
332 ///    See [NegativeType] below:
333 ///        [NegativeType::NameErrorType1]
334 ///        [NegativeType::NameErrorType2]
335 ///        [NegativeType::NameErrorType3]
336 ///        [NegativeType::NameErrorType4]
337 ///        [NegativeType::Referral]
338 ///
339 ///    Note, in the four examples of NXDOMAIN responses, it is known that
340 ///    the name "AN.EXAMPLE." exists, and has as its value a CNAME record.
341 ///    The NXDOMAIN refers to "TRIPPLE.XX", which is then known not to
342 ///    exist.  On the other hand, in the referral example, it is shown that
343 ///    "AN.EXAMPLE" exists, and has a CNAME RR as its value, but nothing is
344 ///    known one way or the other about the existence of "TRIPPLE.XX", other
345 ///    than that "NS1.XX" or "NS2.XX" can be consulted as the next step in
346 ///    obtaining information about it.
347 ///
348 ///    Where no CNAME records appear, the NXDOMAIN response refers to the
349 ///    name in the label of the RR in the question section.
350 ///
351 /// 2.1.1 Special Handling of Name Error
352 ///
353 ///    This section deals with errors encountered when implementing negative
354 ///    caching of NXDOMAIN responses.
355 ///
356 ///    There are a large number of resolvers currently in existence that
357 ///    fail to correctly detect and process all forms of NXDOMAIN response.
358 ///    Some resolvers treat a TYPE 1 NXDOMAIN response as a referral.  To
359 ///    alleviate this problem it is recommended that servers that are
360 ///    authoritative for the NXDOMAIN response only send TYPE 2 NXDOMAIN
361 ///    responses, that is the authority section contains a SOA record and no
362 ///    NS records.  If a non- authoritative server sends a type 1 NXDOMAIN
363 ///    response to one of these old resolvers, the result will be an
364 ///    unnecessary query to an authoritative server.  This is undesirable,
365 ///    but not fatal except when the server is being used a FORWARDER.  If
366 ///    however the resolver is using the server as a FORWARDER to such a
367 ///    resolver it will be necessary to disable the sending of TYPE 1
368 ///    NXDOMAIN response to it, use TYPE 2 NXDOMAIN instead.
369 ///
370 ///    Some resolvers incorrectly continue processing if the authoritative
371 ///    answer flag is not set, looping until the query retry threshold is
372 ///    exceeded and then returning SERVFAIL.  This is a problem when your
373 ///    nameserver is listed as a FORWARDER for such resolvers.  If the
374 ///    nameserver is used as a FORWARDER by such resolver, the authority
375 ///    flag will have to be forced on for NXDOMAIN responses to these
376 ///    resolvers.  In practice this causes no problems even if turned on
377 ///    always, and has been the default behaviour in BIND from 4.9.3
378 ///    onwards.
379 ///
380 /// 2.2 - No Data
381 ///
382 ///    NODATA is indicated by an answer with the RCODE set to NOERROR and no
383 ///    relevant answers in the answer section.  The authority section will
384 ///    contain an SOA record, or there will be no NS records there.
385 ///    NODATA responses have to be algorithmically determined from the
386 ///    response's contents as there is no RCODE value to indicate NODATA.
387 ///    In some cases to determine with certainty that NODATA is the correct
388 ///    response it can be necessary to send another query.
389 ///
390 ///    The authority section may contain NXT and SIG RRsets in addition to
391 ///    NS and SOA records.  CNAME and SIG records may exist in the answer
392 ///    section.
393 ///
394 ///    It is possible to distinguish between a NODATA and a referral
395 ///    response by the presence of a SOA record in the authority section or
396 ///    the absence of NS records in the authority section.
397 ///
398 ///    NODATA responses can be categorised into three types by the contents
399 ///    of the authority section.  These are shown below along with a
400 ///    referral for comparison.  Fields not mentioned are not important in
401 ///    terms of the examples.
402 ///
403 ///    See [NegativeType] below:
404 ///        [NegativeType::NoDataType1]
405 ///        [NegativeType::NoDataType2]
406 ///        [NegativeType::NoDataType3]
407 ///
408 ///    These examples, unlike the NXDOMAIN examples above, have no CNAME
409 ///    records, however they could, in just the same way that the NXDOMAIN
410 ///    examples did, in which case it would be the value of the last CNAME
411 ///    (the QNAME) for which NODATA would be concluded.
412 ///
413 /// 2.2.1 - Special Handling of No Data
414 ///
415 ///    There are a large number of resolvers currently in existence that
416 ///    fail to correctly detect and process all forms of NODATA response.
417 ///    Some resolvers treat a TYPE 1 NODATA response as a referral.  To
418 ///    alleviate this problem it is recommended that servers that are
419 ///    authoritative for the NODATA response only send TYPE 2 NODATA
420 ///    responses, that is the authority section contains a SOA record and no
421 ///    NS records.  Sending a TYPE 1 NODATA response from a non-
422 ///    authoritative server to one of these resolvers will only result in an
423 ///    unnecessary query.  If a server is listed as a FORWARDER for another
424 ///    resolver it may also be necessary to disable the sending of TYPE 1
425 ///    NODATA response for non-authoritative NODATA responses.
426 ///    Some name servers fail to set the RCODE to NXDOMAIN in the presence
427 ///    of CNAMEs in the answer section.  If a definitive NXDOMAIN / NODATA
428 ///    answer is required in this case the resolver must query again using
429 ///    the QNAME as the query label.
430 ///
431 /// 3 - Negative Answers from Authoritative Servers
432 ///
433 ///    Name servers authoritative for a zone MUST include the SOA record of
434 ///    the zone in the authority section of the response when reporting an
435 ///    NXDOMAIN or indicating that no data of the requested type exists.
436 ///    This is required so that the response may be cached.  The TTL of this
437 ///    record is set from the minimum of the MINIMUM field of the SOA record
438 ///    and the TTL of the SOA itself, and indicates how long a resolver may
439 ///    cache the negative answer.  The TTL SIG record associated with the
440 ///    SOA record should also be trimmed in line with the SOA's TTL.
441 ///
442 ///    If the containing zone is signed [RFC2065] the SOA and appropriate
443 ///    NXT and SIG records MUST be added.
444 ///
445 /// ```
446 #[derive(Clone, Copy, Eq, PartialEq, Debug)]
447 pub enum NegativeType {
448     /// ```text
449     ///            NXDOMAIN RESPONSE: TYPE 1.
450     ///
451     ///            Header:
452     ///                RDCODE=NXDOMAIN
453     ///            Query:
454     ///                AN.EXAMPLE. A
455     ///            Answer:
456     ///                AN.EXAMPLE. CNAME TRIPPLE.XX.
457     ///            Authority:
458     ///                XX. SOA NS1.XX. HOSTMASTER.NS1.XX. ....
459     ///                XX. NS NS1.XX.
460     ///                XX. NS NS2.XX.
461     ///            Additional:
462     ///                NS1.XX. A 127.0.0.2
463     ///                NS2.XX. A 127.0.0.3
464     /// ```
465     NameErrorType1,
466 
467     /// ```text
468     ///            NXDOMAIN RESPONSE: TYPE 2.
469     ///
470     ///            Header:
471     ///                RDCODE=NXDOMAIN
472     ///            Query:
473     ///                AN.EXAMPLE. A
474     ///            Answer:
475     ///                AN.EXAMPLE. CNAME TRIPPLE.XX.
476     ///            Authority:
477     ///                XX. SOA NS1.XX. HOSTMASTER.NS1.XX. ....
478     ///            Additional:
479     ///                <empty>
480     /// ```
481     NameErrorType2,
482 
483     /// ```text
484     ///            NXDOMAIN RESPONSE: TYPE 3.
485     ///
486     ///            Header:
487     ///                RDCODE=NXDOMAIN
488     ///            Query:
489     ///                AN.EXAMPLE. A
490     ///            Answer:
491     ///                AN.EXAMPLE. CNAME TRIPPLE.XX.
492     ///            Authority:
493     ///                <empty>
494     ///            Additional:
495     ///                <empty>
496     /// ```
497     NameErrorType3,
498 
499     /// ```text
500     ///            NXDOMAIN RESPONSE: TYPE 4
501     ///
502     ///            Header:
503     ///                RDCODE=NXDOMAIN
504     ///            Query:
505     ///                AN.EXAMPLE. A
506     ///            Answer:
507     ///                AN.EXAMPLE. CNAME TRIPPLE.XX.
508     ///            Authority:
509     ///                XX. NS NS1.XX.
510     ///                XX. NS NS2.XX.
511     ///            Additional:
512     ///                NS1.XX. A 127.0.0.2
513     ///                NS2.XX. A 127.0.0.3
514     /// ```
515     NameErrorType4,
516 
517     /// ```text
518     ///            NODATA RESPONSE: TYPE 1.
519     ///
520     ///            Header:
521     ///                RDCODE=NOERROR
522     ///            Query:
523     ///                ANOTHER.EXAMPLE. A
524     ///            Answer:
525     ///                <empty>
526     ///            Authority:
527     ///                EXAMPLE. SOA NS1.XX. HOSTMASTER.NS1.XX. ....
528     ///                EXAMPLE. NS NS1.XX.
529     ///                EXAMPLE. NS NS2.XX.
530     ///            Additional:
531     ///                NS1.XX. A 127.0.0.2
532     ///                NS2.XX. A 127.0.0.3
533     /// ```
534     NoDataType1,
535 
536     /// ```text
537     ///            NO DATA RESPONSE: TYPE 2.
538     ///
539     ///            Header:
540     ///                RDCODE=NOERROR
541     ///            Query:
542     ///                ANOTHER.EXAMPLE. A
543     ///            Answer:
544     ///                <empty>
545     ///            Authority:
546     ///                EXAMPLE. SOA NS1.XX. HOSTMASTER.NS1.XX. ....
547     ///            Additional:
548     ///                <empty>
549     /// ```
550     NoDataType2,
551 
552     /// ```text
553     ///            NO DATA RESPONSE: TYPE 3.
554     ///            Header:
555     ///                RDCODE=NOERROR
556     ///            Query:
557     ///                ANOTHER.EXAMPLE. A
558     ///            Answer:
559     ///                <empty>
560     ///            Authority:
561     ///                <empty>
562     ///            Additional:
563     ///                <empty>
564     /// ```
565     NoDataType3,
566 
567     /// ```text
568     ///            REFERRAL RESPONSE.
569     ///
570     ///            Header:
571     ///                RDCODE=NOERROR
572     ///            Query:
573     ///                AN.EXAMPLE. A
574     ///            Answer:
575     ///                AN.EXAMPLE. CNAME TRIPPLE.XX.
576     ///            Authority:
577     ///                XX. NS NS1.XX.
578     ///                XX. NS NS2.XX.
579     ///            Additional:
580     ///                NS1.XX. A 127.0.0.2
581     ///                NS2.XX. A 127.0.0.3
582     ///
583     ///            REFERRAL RESPONSE.
584     ///
585     ///            Header:
586     ///                RDCODE=NOERROR
587     ///            Query:
588     ///                ANOTHER.EXAMPLE. A
589     ///            Answer:
590     ///                <empty>
591     ///            Authority:
592     ///                EXAMPLE. NS NS1.XX.
593     ///                EXAMPLE. NS NS2.XX.
594     ///            Additional:
595     ///                NS1.XX. A 127.0.0.2
596     ///                NS2.XX. A 127.0.0.3
597     /// ```
598     Referral,
599 }
600 
601 impl NegativeType {
602     /// The response contains an SOA record
is_authoritative(&self) -> bool603     pub fn is_authoritative(&self) -> bool {
604         matches!(
605             self,
606             NegativeType::NameErrorType1
607                 | NegativeType::NameErrorType2
608                 | NegativeType::NoDataType1
609                 | NegativeType::NoDataType2
610         )
611     }
612 }
613 
614 #[cfg(test)]
615 mod tests {
616     use crate::op::{Message, Query, ResponseCode};
617     use crate::rr::rdata::SOA;
618     use crate::rr::RData;
619     use crate::rr::{Name, Record, RecordType};
620 
621     use super::*;
622 
xx() -> Name623     fn xx() -> Name {
624         Name::from_ascii("XX.").unwrap()
625     }
626 
ns1() -> Name627     fn ns1() -> Name {
628         Name::from_ascii("NS1.XX.").unwrap()
629     }
630 
ns2() -> Name631     fn ns2() -> Name {
632         Name::from_ascii("NS1.XX.").unwrap()
633     }
634 
hostmaster() -> Name635     fn hostmaster() -> Name {
636         Name::from_ascii("HOSTMASTER.NS1.XX.").unwrap()
637     }
638 
tripple_xx() -> Name639     fn tripple_xx() -> Name {
640         Name::from_ascii("TRIPPLE.XX.").unwrap()
641     }
642 
example() -> Name643     fn example() -> Name {
644         Name::from_ascii("EXAMPLE.").unwrap()
645     }
646 
an_example() -> Name647     fn an_example() -> Name {
648         Name::from_ascii("AN.EXAMPLE.").unwrap()
649     }
650 
another_example() -> Name651     fn another_example() -> Name {
652         Name::from_ascii("ANOTHER.EXAMPLE.").unwrap()
653     }
654 
an_cname_record() -> Record655     fn an_cname_record() -> Record {
656         Record::from_rdata(an_example(), 88640, RData::CNAME(tripple_xx()))
657     }
658 
ns1_record() -> Record659     fn ns1_record() -> Record {
660         Record::from_rdata(xx(), 88640, RData::NS(ns1()))
661     }
662 
ns2_record() -> Record663     fn ns2_record() -> Record {
664         Record::from_rdata(xx(), 88640, RData::NS(ns2()))
665     }
666 
ns1_a() -> Record667     fn ns1_a() -> Record {
668         Record::from_rdata(xx(), 88640, RData::A([127, 0, 0, 2].into()))
669     }
670 
ns2_a() -> Record671     fn ns2_a() -> Record {
672         Record::from_rdata(xx(), 88640, RData::A([127, 0, 0, 3].into()))
673     }
674 
soa() -> Record675     fn soa() -> Record {
676         Record::from_rdata(
677             example(),
678             88640,
679             RData::SOA(SOA::new(ns1(), hostmaster(), 1, 2, 3, 4, 5)),
680         )
681     }
682 
an_query() -> Query683     fn an_query() -> Query {
684         Query::query(an_example(), RecordType::A)
685     }
686 
another_query() -> Query687     fn another_query() -> Query {
688         Query::query(another_example(), RecordType::A)
689     }
690 
691     #[test]
test_contains_answer()692     fn test_contains_answer() {
693         let mut message = Message::default();
694         message.set_response_code(ResponseCode::NXDomain);
695         message.add_query(Query::query(Name::root(), RecordType::A));
696         message.add_answer(Record::from_rdata(
697             Name::root(),
698             88640,
699             RData::A([127, 0, 0, 2].into()),
700         ));
701 
702         let response = DnsResponse::from(message);
703 
704         assert!(response.contains_answer())
705     }
706 
707     #[test]
test_nx_type1()708     fn test_nx_type1() {
709         let mut message = Message::default();
710         message.set_response_code(ResponseCode::NXDomain);
711         message.add_query(an_query());
712         message.add_answer(an_cname_record());
713         message.add_name_server(soa());
714         message.add_name_server(ns1_record());
715         message.add_name_server(ns2_record());
716         message.add_additional(ns1_a());
717         message.add_additional(ns2_a());
718 
719         let response = DnsResponse::from(message);
720         let ty = response.negative_type();
721 
722         assert!(response.contains_answer());
723         assert_eq!(ty.unwrap(), NegativeType::NameErrorType1);
724     }
725 
726     #[test]
test_nx_type2()727     fn test_nx_type2() {
728         let mut message = Message::default();
729         message.set_response_code(ResponseCode::NXDomain);
730         message.add_query(an_query());
731         message.add_answer(an_cname_record());
732         message.add_name_server(soa());
733 
734         let response = DnsResponse::from(message);
735         let ty = response.negative_type();
736 
737         assert!(response.contains_answer());
738         assert_eq!(ty.unwrap(), NegativeType::NameErrorType2);
739     }
740 
741     #[test]
test_nx_type3()742     fn test_nx_type3() {
743         let mut message = Message::default();
744         message.set_response_code(ResponseCode::NXDomain);
745         message.add_query(an_query());
746         message.add_answer(an_cname_record());
747 
748         let response = DnsResponse::from(message);
749         let ty = response.negative_type();
750 
751         assert!(response.contains_answer());
752         assert_eq!(ty.unwrap(), NegativeType::NameErrorType3);
753     }
754 
755     #[test]
test_nx_type4()756     fn test_nx_type4() {
757         let mut message = Message::default();
758         message.set_response_code(ResponseCode::NXDomain);
759         message.add_query(an_query());
760         message.add_answer(an_cname_record());
761         message.add_name_server(ns1_record());
762         message.add_name_server(ns2_record());
763         message.add_additional(ns1_a());
764         message.add_additional(ns2_a());
765 
766         let response = DnsResponse::from(message);
767         let ty = response.negative_type();
768 
769         assert!(response.contains_answer());
770         assert_eq!(ty.unwrap(), NegativeType::NameErrorType4);
771     }
772 
773     #[test]
test_no_data_type1()774     fn test_no_data_type1() {
775         let mut message = Message::default();
776         message.set_response_code(ResponseCode::NoError);
777         message.add_query(another_query());
778         message.add_name_server(soa());
779         message.add_name_server(ns1_record());
780         message.add_name_server(ns2_record());
781         message.add_additional(ns1_a());
782         message.add_additional(ns2_a());
783         let response = DnsResponse::from(message);
784         let ty = response.negative_type();
785 
786         assert!(!response.contains_answer());
787         assert_eq!(ty.unwrap(), NegativeType::NoDataType1);
788     }
789 
790     #[test]
test_no_data_type2()791     fn test_no_data_type2() {
792         let mut message = Message::default();
793         message.set_response_code(ResponseCode::NoError);
794         message.add_query(another_query());
795         message.add_name_server(soa());
796 
797         let response = DnsResponse::from(message);
798         let ty = response.negative_type();
799 
800         assert!(!response.contains_answer());
801         assert_eq!(ty.unwrap(), NegativeType::NoDataType2);
802     }
803 
804     #[test]
test_no_data_type3()805     fn test_no_data_type3() {
806         let mut message = Message::default();
807         message.set_response_code(ResponseCode::NoError);
808         message.add_query(another_query());
809 
810         let response = DnsResponse::from(message);
811         let ty = response.negative_type();
812 
813         assert!(!response.contains_answer());
814         assert_eq!(ty.unwrap(), NegativeType::NoDataType3);
815     }
816 
817     #[test]
referral()818     fn referral() {
819         let mut message = Message::default();
820         message.set_response_code(ResponseCode::NoError);
821         message.add_query(an_query());
822         message.add_answer(an_cname_record());
823         message.add_name_server(ns1_record());
824         message.add_name_server(ns2_record());
825         message.add_additional(ns1_a());
826         message.add_additional(ns2_a());
827 
828         let response = DnsResponse::from(message);
829         let ty = response.negative_type();
830 
831         assert!(response.contains_answer());
832         assert_eq!(ty.unwrap(), NegativeType::Referral);
833 
834         let mut message = Message::default();
835         message.set_response_code(ResponseCode::NoError);
836         message.add_query(another_query());
837         message.add_name_server(ns1_record());
838         message.add_name_server(ns2_record());
839         message.add_additional(ns1_a());
840         message.add_additional(ns2_a());
841 
842         let response = DnsResponse::from(message);
843         let ty = response.negative_type();
844 
845         assert!(!response.contains_answer());
846         assert_eq!(ty.unwrap(), NegativeType::Referral);
847     }
848 
849     #[test]
contains_soa()850     fn contains_soa() {
851         let mut message = Message::default();
852         message.set_response_code(ResponseCode::NoError);
853         message.add_query(Query::query(an_example(), RecordType::SOA));
854         message.add_name_server(soa());
855 
856         let response = DnsResponse::from(message);
857 
858         assert!(response.contains_answer());
859     }
860 
861     #[test]
contains_any()862     fn contains_any() {
863         let mut message = Message::default();
864         message.set_response_code(ResponseCode::NoError);
865         message.add_query(Query::query(xx(), RecordType::ANY));
866         message.add_name_server(ns1_record());
867         message.add_additional(ns1_a());
868 
869         let response = DnsResponse::from(message);
870 
871         assert!(response.contains_answer());
872     }
873 }
874