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