1use std::ffi::CString;
2use std::fmt;
3use std::ptr;
4
5use crate::error::{Error, Result};
6use crate::string::AresBuf;
7use crate::utils::{dns_string_as_str, status_to_result};
8
9use super::enums::{
10 DnsCls, DnsFlags, DnsOpcode, DnsParseFlags, DnsRcode, DnsRecordType, DnsSection,
11};
12use super::rr::DnsRr;
13
14pub struct DnsRecord {
22 dnsrec: *mut c_ares_sys::ares_dns_record_t,
23}
24
25impl DnsRecord {
26 pub(crate) unsafe fn from_raw(dnsrec: *mut c_ares_sys::ares_dns_record_t) -> DnsRecord {
34 DnsRecord { dnsrec }
35 }
36
37 pub(crate) fn as_raw(&self) -> *const c_ares_sys::ares_dns_record_t {
39 self.dnsrec
40 }
41
42 pub fn parse(data: &[u8], flags: DnsParseFlags) -> Result<DnsRecord> {
47 let mut dnsrec: *mut c_ares_sys::ares_dns_record_t = ptr::null_mut();
48 let status = unsafe {
49 c_ares_sys::ares_dns_parse(data.as_ptr(), data.len(), flags.bits(), &raw mut dnsrec)
50 };
51 status_to_result(status)?;
52 Ok(DnsRecord { dnsrec })
53 }
54
55 pub fn id(&self) -> u16 {
57 unsafe { c_ares_sys::ares_dns_record_get_id(self.dnsrec) }
58 }
59
60 pub fn flags(&self) -> DnsFlags {
62 let raw = unsafe { c_ares_sys::ares_dns_record_get_flags(self.dnsrec) };
63 DnsFlags::from_bits_truncate(raw)
64 }
65
66 pub fn opcode(&self) -> DnsOpcode {
68 let raw = unsafe { c_ares_sys::ares_dns_record_get_opcode(self.dnsrec) };
69 DnsOpcode::from(raw)
70 }
71
72 pub fn rcode(&self) -> DnsRcode {
74 let raw = unsafe { c_ares_sys::ares_dns_record_get_rcode(self.dnsrec) };
75 DnsRcode::from(raw)
76 }
77
78 pub fn query_count(&self) -> usize {
80 unsafe { c_ares_sys::ares_dns_record_query_cnt(self.dnsrec) }
81 }
82
83 pub fn query_get(&self, idx: usize) -> Result<(&str, DnsRecordType, DnsCls)> {
87 let mut name: *const core::ffi::c_char = ptr::null();
88 let mut qtype = c_ares_sys::ares_dns_rec_type_t::ARES_REC_TYPE_A;
89 let mut qclass = c_ares_sys::ares_dns_class_t::ARES_CLASS_IN;
90 let status = unsafe {
91 c_ares_sys::ares_dns_record_query_get(
92 self.dnsrec,
93 idx,
94 &raw mut name,
95 &raw mut qtype,
96 &raw mut qclass,
97 )
98 };
99 status_to_result(status)?;
100 let name_str = unsafe { dns_string_as_str(name) };
101 Ok((name_str, DnsRecordType::from(qtype), DnsCls::from(qclass)))
102 }
103
104 pub fn queries(&self) -> impl Iterator<Item = (&str, DnsRecordType, DnsCls)> {
106 (0..self.query_count()).map_while(move |i| self.query_get(i).ok())
107 }
108
109 pub fn rr_count(&self, section: DnsSection) -> usize {
111 unsafe { c_ares_sys::ares_dns_record_rr_cnt(self.dnsrec, section.into()) }
112 }
113
114 pub fn rr(&self, section: DnsSection, idx: usize) -> Option<&DnsRr> {
118 let rr =
119 unsafe { c_ares_sys::ares_dns_record_rr_get_const(self.dnsrec, section.into(), idx) };
120 (!rr.is_null()).then(|| unsafe { &*rr.cast::<DnsRr>() })
121 }
122
123 pub fn rrs(&self, section: DnsSection) -> impl Iterator<Item = &DnsRr> {
125 (0..self.rr_count(section)).map_while(move |i| self.rr(section, i))
126 }
127
128 pub fn new(id: u16, flags: DnsFlags, opcode: DnsOpcode, rcode: DnsRcode) -> Result<DnsRecord> {
148 let mut dnsrec: *mut c_ares_sys::ares_dns_record_t = ptr::null_mut();
149 let status = unsafe {
150 c_ares_sys::ares_dns_record_create(
151 &raw mut dnsrec,
152 id,
153 flags.bits(),
154 opcode.into(),
155 rcode.into(),
156 )
157 };
158 status_to_result(status)?;
159 Ok(DnsRecord { dnsrec })
160 }
161
162 pub fn set_id(&mut self, id: u16) -> &mut Self {
164 unsafe { c_ares_sys::ares_dns_record_set_id(self.dnsrec, id) };
165 self
166 }
167
168 pub fn query_add(
173 &mut self,
174 name: &str,
175 qtype: DnsRecordType,
176 qclass: DnsCls,
177 ) -> Result<&mut Self> {
178 let c_name = CString::new(name).map_err(|_| Error::EBADSTR)?;
179 let status = unsafe {
180 c_ares_sys::ares_dns_record_query_add(
181 self.dnsrec,
182 c_name.as_ptr(),
183 qtype.into(),
184 qclass.into(),
185 )
186 };
187 status_to_result(status)?;
188 Ok(self)
189 }
190
191 pub fn query_set_name(&mut self, idx: usize, name: &str) -> Result<&mut Self> {
195 let c_name = CString::new(name).map_err(|_| Error::EBADSTR)?;
196 let status = unsafe {
197 c_ares_sys::ares_dns_record_query_set_name(self.dnsrec, idx, c_name.as_ptr())
198 };
199 status_to_result(status)?;
200 Ok(self)
201 }
202
203 pub fn query_set_type(&mut self, idx: usize, qtype: DnsRecordType) -> Result<&mut Self> {
208 let status =
209 unsafe { c_ares_sys::ares_dns_record_query_set_type(self.dnsrec, idx, qtype.into()) };
210 status_to_result(status)?;
211 Ok(self)
212 }
213
214 pub fn rr_add(
219 &mut self,
220 section: DnsSection,
221 name: &str,
222 rr_type: DnsRecordType,
223 rclass: DnsCls,
224 ttl: u32,
225 ) -> Result<&mut DnsRr> {
226 let c_name = CString::new(name).map_err(|_| Error::EBADSTR)?;
227 let mut rr_out: *mut c_ares_sys::ares_dns_rr_t = ptr::null_mut();
228 let status = unsafe {
229 c_ares_sys::ares_dns_record_rr_add(
230 &raw mut rr_out,
231 self.dnsrec,
232 section.into(),
233 c_name.as_ptr(),
234 rr_type.into(),
235 rclass.into(),
236 ttl,
237 )
238 };
239 status_to_result(status)?;
240 Ok(unsafe { &mut *rr_out.cast::<DnsRr>() })
241 }
242
243 pub fn rr_mut(&mut self, section: DnsSection, idx: usize) -> Option<&mut DnsRr> {
247 let rr = unsafe { c_ares_sys::ares_dns_record_rr_get(self.dnsrec, section.into(), idx) };
248 (!rr.is_null()).then(|| unsafe { &mut *rr.cast::<DnsRr>() })
249 }
250
251 pub fn rrs_mut(&mut self, section: DnsSection) -> impl Iterator<Item = &mut DnsRr> {
253 let count = self.rr_count(section);
254 let dnsrec = self.dnsrec;
255 (0..count).map_while(move |i| {
256 let rr = unsafe { c_ares_sys::ares_dns_record_rr_get(dnsrec, section.into(), i) };
257 (!rr.is_null()).then(|| unsafe { &mut *rr.cast::<DnsRr>() })
258 })
259 }
260
261 pub fn rr_del(&mut self, section: DnsSection, idx: usize) -> Result<&mut Self> {
263 let status =
264 unsafe { c_ares_sys::ares_dns_record_rr_del(self.dnsrec, section.into(), idx) };
265 status_to_result(status)?;
266 Ok(self)
267 }
268
269 pub fn write(&self) -> Result<AresBuf> {
271 let mut buf: *mut core::ffi::c_uchar = ptr::null_mut();
272 let mut buf_len: usize = 0;
273 let status =
274 unsafe { c_ares_sys::ares_dns_write(self.dnsrec, &raw mut buf, &raw mut buf_len) };
275 status_to_result(status)?;
276 Ok(AresBuf::new(buf, buf_len))
277 }
278
279 pub fn try_clone(&self) -> Result<DnsRecord> {
281 let dup = unsafe { c_ares_sys::ares_dns_record_duplicate(self.dnsrec) };
282 if dup.is_null() {
283 Err(Error::ENOMEM)
284 } else {
285 Ok(DnsRecord { dnsrec: dup })
286 }
287 }
288}
289
290impl Drop for DnsRecord {
291 fn drop(&mut self) {
292 unsafe { c_ares_sys::ares_dns_record_destroy(self.dnsrec) }
293 }
294}
295
296unsafe impl Send for DnsRecord {}
297unsafe impl Sync for DnsRecord {}
298
299impl fmt::Debug for DnsRecord {
300 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
301 f.debug_struct("DnsRecord")
302 .field("id", &self.id())
303 .field("flags", &self.flags())
304 .field("opcode", &self.opcode())
305 .field("rcode", &self.rcode())
306 .field("query_count", &self.query_count())
307 .field("answer_count", &self.rr_count(DnsSection::Answer))
308 .field("authority_count", &self.rr_count(DnsSection::Authority))
309 .field("additional_count", &self.rr_count(DnsSection::Additional))
310 .finish()
311 }
312}
313
314#[cfg(test)]
315mod tests {
316 use std::net::Ipv4Addr;
317
318 use crate::dns::*;
319 use crate::error::Error;
320
321 #[test]
322 fn parse_invalid_data() {
323 let result = DnsRecord::parse(&[], DnsParseFlags::empty());
324 assert!(result.is_err());
325 }
326
327 #[test]
328 fn parse_short_data() {
329 let result = DnsRecord::parse(&[0; 4], DnsParseFlags::empty());
330 assert!(result.is_err());
331 }
332
333 #[test]
336 fn parse_minimal_query() {
337 #[rustfmt::skip]
338 let data: &[u8] = &[
339 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, ];
349 let rec = DnsRecord::parse(data, DnsParseFlags::empty()).expect("parse should succeed");
350 assert_eq!(rec.id(), 1);
351 assert!(rec.flags().contains(DnsFlags::RD));
352 assert_eq!(rec.opcode(), DnsOpcode::Query);
353 assert_eq!(rec.rcode(), DnsRcode::NoError);
354 assert_eq!(rec.query_count(), 1);
355
356 let (name, qtype, qclass) = rec.query_get(0).expect("query_get should succeed");
357 assert_eq!(name, "");
358 assert_eq!(qtype, DnsRecordType::A);
359 assert_eq!(qclass, DnsCls::IN);
360
361 assert_eq!(rec.rr_count(DnsSection::Answer), 0);
362 assert!(rec.rr(DnsSection::Answer, 0).is_none());
363 }
364
365 #[test]
366 fn query_get_preserves_unknown_query_type() {
367 #[rustfmt::skip]
368 let data: &[u8] = &[
369 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x01, ];
379 let rec = DnsRecord::parse(data, DnsParseFlags::empty()).expect("parse should succeed");
380 assert_eq!(rec.query_count(), 1);
381 let (_, qtype, qclass) = rec.query_get(0).expect("query_get");
382 assert_eq!(qtype, DnsRecordType::UNKNOWN(0xff00));
383 assert_eq!(qclass, DnsCls::IN);
384 }
385
386 #[test]
388 fn parse_a_response() {
389 #[rustfmt::skip]
390 let data: &[u8] = &[
391 0x00, 0x02, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, b'e', b'x', b'a', b'm', b'p', b'l', b'e',
399 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x04, 0x01, 0x02, 0x03, 0x04, ];
410 let rec = DnsRecord::parse(data, DnsParseFlags::empty()).expect("parse should succeed");
411 assert_eq!(rec.id(), 2);
412 assert!(rec.flags().contains(DnsFlags::QR));
413 assert!(rec.flags().contains(DnsFlags::RD));
414 assert!(rec.flags().contains(DnsFlags::RA));
415 assert_eq!(rec.rr_count(DnsSection::Answer), 1);
416
417 let rr = rec.rr(DnsSection::Answer, 0).expect("rr should exist");
418 assert_eq!(rr.rr_type(), DnsRecordType::A);
419 assert_eq!(rr.dns_class(), DnsCls::IN);
420 assert_eq!(rr.ttl(), 300);
421 assert_eq!(rr.name(), "example");
422
423 let addr = rr.get_addr(DnsRrKey::A_ADDR).expect("should have addr");
424 assert_eq!(addr, Ipv4Addr::new(1, 2, 3, 4));
425 }
426
427 #[test]
428 fn rr_preserves_unknown_class_on_raw_rr() {
429 #[rustfmt::skip]
430 let data: &[u8] = &[
431 0x00, 0x03, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07, b'e', b'x', b'a', b'm', b'p', b'l', b'e',
439 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
449 let rec = DnsRecord::parse(data, DnsParseFlags::empty()).expect("parse should succeed");
450 let rr = rec.rr(DnsSection::Answer, 0).expect("rr should exist");
451
452 assert_eq!(rr.rr_type(), DnsRecordType::RAW_RR);
455 assert_eq!(rr.dns_class(), DnsCls::UNKNOWN(0xff00));
456 assert!(matches!(rr.as_typed(), TypedRr::RawRr(_)));
457 }
458
459 #[test]
460 fn dns_record_is_send() {
461 fn assert_send<T: Send>() {}
462 assert_send::<DnsRecord>();
463 }
464
465 #[test]
466 fn dns_record_is_sync() {
467 fn assert_sync<T: Sync>() {}
468 assert_sync::<DnsRecord>();
469 }
470
471 #[test]
472 fn create_empty_record() {
473 let rec = DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError)
474 .expect("create should succeed");
475 assert_eq!(rec.id(), 0);
476 assert!(rec.flags().contains(DnsFlags::RD));
477 assert_eq!(rec.opcode(), DnsOpcode::Query);
478 assert_eq!(rec.rcode(), DnsRcode::NoError);
479 assert_eq!(rec.query_count(), 0);
480 }
481
482 #[test]
483 fn create_and_add_query() {
484 let mut rec = DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError)
485 .expect("create should succeed");
486 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
487 .expect("query_add should succeed");
488 assert_eq!(rec.query_count(), 1);
489 let (name, qtype, qclass) = rec.query_get(0).expect("query_get should succeed");
490 assert_eq!(name, "example.com");
491 assert_eq!(qtype, DnsRecordType::A);
492 assert_eq!(qclass, DnsCls::IN);
493 }
494
495 #[test]
496 fn set_id() {
497 let mut rec = DnsRecord::new(0, DnsFlags::empty(), DnsOpcode::Query, DnsRcode::NoError)
498 .expect("create should succeed");
499 assert_eq!(rec.id(), 0);
500 rec.set_id(42);
501 assert_eq!(rec.id(), 42);
502 }
503
504 #[test]
505 fn query_set_name_and_type() {
506 let mut rec = DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError)
507 .expect("create should succeed");
508 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
509 .expect("query_add");
510 rec.query_set_name(0, "other.com").expect("set_name");
511 rec.query_set_type(0, DnsRecordType::AAAA)
512 .expect("set_type");
513 let (name, qtype, _) = rec.query_get(0).expect("query_get");
514 assert_eq!(name, "other.com");
515 assert_eq!(qtype, DnsRecordType::AAAA);
516 }
517
518 #[test]
519 fn rr_mut_and_rr_del() {
520 let mut rec =
521 DnsRecord::new(0, DnsFlags::QR, DnsOpcode::Query, DnsRcode::NoError).expect("create");
522 rec.query_add("example.com", DnsRecordType::MX, DnsCls::IN)
523 .expect("query_add");
524 let rr = rec
525 .rr_add(
526 DnsSection::Answer,
527 "example.com",
528 DnsRecordType::MX,
529 DnsCls::IN,
530 600,
531 )
532 .expect("rr_add");
533 rr.set_u16(DnsRrKey::MX_PREFERENCE, 10).expect("set_u16");
534 rr.set_str(DnsRrKey::MX_EXCHANGE, "mail.example.com")
535 .expect("set_str");
536
537 let rr = rec.rr_mut(DnsSection::Answer, 0).expect("rr_mut");
539 assert_eq!(rr.get_u16(DnsRrKey::MX_PREFERENCE), 10);
540 assert_eq!(rr.get_str(DnsRrKey::MX_EXCHANGE), Some("mail.example.com"));
541
542 rec.rr_del(DnsSection::Answer, 0).expect("rr_del");
544 assert_eq!(rec.rr_count(DnsSection::Answer), 0);
545 }
546
547 #[test]
548 fn rrs_mut_update_ttl() {
549 let mut rec =
550 DnsRecord::new(0, DnsFlags::QR, DnsOpcode::Query, DnsRcode::NoError).expect("create");
551 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
552 .expect("query_add");
553 for i in 0..3u8 {
554 let rr = rec
555 .rr_add(
556 DnsSection::Answer,
557 "example.com",
558 DnsRecordType::A,
559 DnsCls::IN,
560 300,
561 )
562 .expect("rr_add");
563 rr.set_addr(DnsRrKey::A_ADDR, Ipv4Addr::new(10, 0, 0, i))
564 .expect("set_addr");
565 }
566
567 for rr in rec.rrs_mut(DnsSection::Answer) {
569 let addr = rr.get_addr(DnsRrKey::A_ADDR).expect("get_addr");
570 let octets = addr.octets();
572 rr.set_addr(
573 DnsRrKey::A_ADDR,
574 Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3] + 100),
575 )
576 .expect("set_addr");
577 }
578
579 let addrs: Vec<_> = rec
581 .rrs(DnsSection::Answer)
582 .map(|rr| rr.get_addr(DnsRrKey::A_ADDR).unwrap())
583 .collect();
584 assert_eq!(
585 addrs,
586 vec![
587 Ipv4Addr::new(10, 0, 0, 100),
588 Ipv4Addr::new(10, 0, 0, 101),
589 Ipv4Addr::new(10, 0, 0, 102),
590 ]
591 );
592 }
593
594 #[test]
595 fn write_and_reparse() {
596 let mut rec =
597 DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
598 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
599 .expect("query_add");
600
601 let wire = rec.write().expect("write");
602 assert!(!wire.is_empty());
603
604 let rec2 = DnsRecord::parse(&wire, DnsParseFlags::empty()).expect("parse");
606 assert_eq!(rec2.query_count(), 1);
607 let (name, qtype, qclass) = rec2.query_get(0).expect("query_get");
608 assert_eq!(name, "example.com");
609 assert_eq!(qtype, DnsRecordType::A);
610 assert_eq!(qclass, DnsCls::IN);
611 }
612
613 #[test]
614 fn duplicate_record() {
615 let mut rec =
616 DnsRecord::new(42, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
617 rec.query_add("test.org", DnsRecordType::AAAA, DnsCls::IN)
618 .expect("query_add");
619
620 let dup = rec.try_clone().expect("try_clone");
621 assert_eq!(dup.id(), 42);
622 assert_eq!(dup.query_count(), 1);
623 let (name, qtype, _) = dup.query_get(0).expect("query_get");
624 assert_eq!(name, "test.org");
625 assert_eq!(qtype, DnsRecordType::AAAA);
626 }
627
628 #[test]
630 fn rr_out_of_range() {
631 let rec =
632 DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
633 assert!(rec.rr(DnsSection::Answer, 0).is_none());
634 assert!(rec.rr(DnsSection::Answer, 100).is_none());
635 assert!(rec.rr(DnsSection::Authority, 0).is_none());
636 assert!(rec.rr(DnsSection::Additional, 0).is_none());
637 }
638
639 #[test]
641 fn rr_mut_out_of_range() {
642 let mut rec =
643 DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
644 assert!(rec.rr_mut(DnsSection::Answer, 0).is_none());
645 assert!(rec.rr_mut(DnsSection::Answer, 100).is_none());
646 }
647
648 #[test]
650 fn rr_del_out_of_range() {
651 let mut rec =
652 DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
653 let result = rec.rr_del(DnsSection::Answer, 0);
654 assert!(result.is_err());
655 }
656
657 #[test]
659 fn multiple_queries() {
660 let mut rec =
661 DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
662 rec.query_add("a.example.com", DnsRecordType::A, DnsCls::IN)
663 .expect("add 0");
664 rec.query_add("b.example.com", DnsRecordType::AAAA, DnsCls::IN)
665 .expect("add 1");
666 rec.query_add("c.example.com", DnsRecordType::MX, DnsCls::IN)
667 .expect("add 2");
668 assert_eq!(rec.query_count(), 3);
669
670 let (n, t, _) = rec.query_get(0).expect("get 0");
671 assert_eq!(n, "a.example.com");
672 assert_eq!(t, DnsRecordType::A);
673
674 let (n, t, _) = rec.query_get(1).expect("get 1");
675 assert_eq!(n, "b.example.com");
676 assert_eq!(t, DnsRecordType::AAAA);
677
678 let (n, t, _) = rec.query_get(2).expect("get 2");
679 assert_eq!(n, "c.example.com");
680 assert_eq!(t, DnsRecordType::MX);
681 }
682
683 #[test]
685 fn multiple_rrs_same_section() {
686 let mut rec =
687 DnsRecord::new(0, DnsFlags::QR, DnsOpcode::Query, DnsRcode::NoError).expect("create");
688 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
689 .expect("query_add");
690 for i in 0..5 {
691 let rr = rec
692 .rr_add(
693 DnsSection::Answer,
694 "example.com",
695 DnsRecordType::A,
696 DnsCls::IN,
697 300,
698 )
699 .expect("rr_add");
700 rr.set_addr(DnsRrKey::A_ADDR, Ipv4Addr::new(10, 0, 0, i))
701 .expect("set_addr");
702 }
703 assert_eq!(rec.rr_count(DnsSection::Answer), 5);
704 for i in 0..5 {
705 let rr = rec.rr(DnsSection::Answer, i).expect("rr");
706 assert_eq!(
707 rr.get_addr(DnsRrKey::A_ADDR),
708 Some(Ipv4Addr::new(10, 0, 0, i as u8))
709 );
710 }
711 }
712
713 #[test]
715 fn authority_and_additional_sections() {
716 let mut rec =
717 DnsRecord::new(0, DnsFlags::QR, DnsOpcode::Query, DnsRcode::NoError).expect("create");
718 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
719 .expect("query_add");
720
721 let rr = rec
723 .rr_add(
724 DnsSection::Authority,
725 "example.com",
726 DnsRecordType::NS,
727 DnsCls::IN,
728 3600,
729 )
730 .expect("rr_add authority");
731 rr.set_str(DnsRrKey::NS_NSDNAME, "ns1.example.com")
732 .expect("set ns name");
733
734 let rr = rec
736 .rr_add(
737 DnsSection::Additional,
738 "ns1.example.com",
739 DnsRecordType::A,
740 DnsCls::IN,
741 3600,
742 )
743 .expect("rr_add additional");
744 rr.set_addr(DnsRrKey::A_ADDR, Ipv4Addr::new(192, 0, 2, 1))
745 .expect("set_addr");
746
747 assert_eq!(rec.rr_count(DnsSection::Answer), 0);
748 assert_eq!(rec.rr_count(DnsSection::Authority), 1);
749 assert_eq!(rec.rr_count(DnsSection::Additional), 1);
750
751 let ns = rec.rr(DnsSection::Authority, 0).expect("rr authority");
752 assert_eq!(ns.rr_type(), DnsRecordType::NS);
753 assert_eq!(ns.get_str(DnsRrKey::NS_NSDNAME), Some("ns1.example.com"));
754
755 let a = rec.rr(DnsSection::Additional, 0).expect("rr additional");
756 assert_eq!(a.rr_type(), DnsRecordType::A);
757 assert_eq!(
758 a.get_addr(DnsRrKey::A_ADDR),
759 Some(Ipv4Addr::new(192, 0, 2, 1))
760 );
761 }
762
763 #[test]
765 fn write_reparse_with_answer() {
766 let mut rec = DnsRecord::new(
767 100,
768 DnsFlags::QR | DnsFlags::RD | DnsFlags::RA,
769 DnsOpcode::Query,
770 DnsRcode::NoError,
771 )
772 .expect("create");
773 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
774 .expect("query_add");
775 let rr = rec
776 .rr_add(
777 DnsSection::Answer,
778 "example.com",
779 DnsRecordType::A,
780 DnsCls::IN,
781 300,
782 )
783 .expect("rr_add");
784 rr.set_addr(DnsRrKey::A_ADDR, Ipv4Addr::new(93, 184, 216, 34))
785 .expect("set_addr");
786
787 let wire = rec.write().expect("write");
788 let rec2 = DnsRecord::parse(&wire, DnsParseFlags::empty()).expect("reparse");
789 assert_eq!(rec2.id(), 100);
790 assert!(rec2.flags().contains(DnsFlags::QR));
791 assert!(rec2.flags().contains(DnsFlags::RD));
792 assert!(rec2.flags().contains(DnsFlags::RA));
793 assert_eq!(rec2.rr_count(DnsSection::Answer), 1);
794 let rr = rec2.rr(DnsSection::Answer, 0).expect("rr");
795 assert_eq!(
796 rr.get_addr(DnsRrKey::A_ADDR),
797 Some(Ipv4Addr::new(93, 184, 216, 34))
798 );
799 }
800
801 #[test]
803 fn soa_write_reparse() {
804 let mut rec = DnsRecord::new(
805 5,
806 DnsFlags::QR | DnsFlags::AA | DnsFlags::RD,
807 DnsOpcode::Query,
808 DnsRcode::NoError,
809 )
810 .expect("create");
811 rec.query_add("example.com", DnsRecordType::SOA, DnsCls::IN)
812 .expect("query_add");
813 let rr = rec
814 .rr_add(
815 DnsSection::Answer,
816 "example.com",
817 DnsRecordType::SOA,
818 DnsCls::IN,
819 86400,
820 )
821 .expect("rr_add");
822 rr.set_str(DnsRrKey::SOA_MNAME, "ns1.example.com")
823 .expect("mname");
824 rr.set_str(DnsRrKey::SOA_RNAME, "hostmaster.example.com")
825 .expect("rname");
826 rr.set_u32(DnsRrKey::SOA_SERIAL, 1).expect("serial");
827 rr.set_u32(DnsRrKey::SOA_REFRESH, 3600).expect("refresh");
828 rr.set_u32(DnsRrKey::SOA_RETRY, 900).expect("retry");
829 rr.set_u32(DnsRrKey::SOA_EXPIRE, 604800).expect("expire");
830 rr.set_u32(DnsRrKey::SOA_MINIMUM, 60).expect("minimum");
831
832 let wire = rec.write().expect("write");
833 let rec2 = DnsRecord::parse(&wire, DnsParseFlags::empty()).expect("reparse");
834 assert_eq!(rec2.id(), 5);
835 assert!(rec2.flags().contains(DnsFlags::AA));
836 let rr = rec2.rr(DnsSection::Answer, 0).expect("rr");
837 assert_eq!(rr.get_str(DnsRrKey::SOA_MNAME), Some("ns1.example.com"));
838 assert_eq!(
839 rr.get_str(DnsRrKey::SOA_RNAME),
840 Some("hostmaster.example.com")
841 );
842 assert_eq!(rr.get_u32(DnsRrKey::SOA_SERIAL), 1);
843 assert_eq!(rr.get_u32(DnsRrKey::SOA_EXPIRE), 604800);
844 }
845
846 #[test]
848 fn txt_abin_write_reparse() {
849 let mut rec =
850 DnsRecord::new(0, DnsFlags::QR, DnsOpcode::Query, DnsRcode::NoError).expect("create");
851 rec.query_add("example.com", DnsRecordType::TXT, DnsCls::IN)
852 .expect("query_add");
853 let rr = rec
854 .rr_add(
855 DnsSection::Answer,
856 "example.com",
857 DnsRecordType::TXT,
858 DnsCls::IN,
859 300,
860 )
861 .expect("rr_add");
862 rr.add_abin(DnsRrKey::TXT_DATA, b"v=spf1 include:example.com ~all")
863 .expect("add_abin");
864
865 let wire = rec.write().expect("write");
866 let rec2 = DnsRecord::parse(&wire, DnsParseFlags::empty()).expect("reparse");
867 let rr = rec2.rr(DnsSection::Answer, 0).expect("rr");
868 assert_eq!(rr.get_abin_count(DnsRrKey::TXT_DATA), 1);
869 assert_eq!(
870 rr.get_abin(DnsRrKey::TXT_DATA, 0).unwrap(),
871 b"v=spf1 include:example.com ~all"
872 );
873 }
874
875 #[test]
877 fn query_add_rejects_null_byte() {
878 let mut rec =
879 DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
880 let result = rec.query_add("ex\0ample.com", DnsRecordType::A, DnsCls::IN);
881 assert!(matches!(result, Err(Error::EBADSTR)));
882 }
883
884 #[test]
885 fn query_set_name_rejects_null_byte() {
886 let mut rec =
887 DnsRecord::new(0, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
888 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
889 .expect("query_add");
890 let result = rec.query_set_name(0, "ex\0ample.com");
891 assert!(matches!(result, Err(Error::EBADSTR)));
892 }
893
894 #[test]
895 fn rr_add_rejects_null_byte() {
896 let mut rec =
897 DnsRecord::new(0, DnsFlags::QR, DnsOpcode::Query, DnsRcode::NoError).expect("create");
898 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
899 .expect("query_add");
900 let result = rec.rr_add(
901 DnsSection::Answer,
902 "ex\0ample.com",
903 DnsRecordType::A,
904 DnsCls::IN,
905 300,
906 );
907 assert!(matches!(result, Err(Error::EBADSTR)));
908 }
909
910 #[test]
911 fn debug_dns_record() {
912 let rec =
913 DnsRecord::new(42, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
914 let debug = format!("{rec:?}");
915 assert!(debug.contains("DnsRecord"));
916 assert!(debug.contains("42"));
917 }
918
919 #[test]
920 fn clone_dns_record() {
921 let mut rec =
922 DnsRecord::new(7, DnsFlags::RD, DnsOpcode::Query, DnsRcode::NoError).expect("create");
923 rec.query_add("example.com", DnsRecordType::A, DnsCls::IN)
924 .expect("query_add");
925
926 let cloned = rec.try_clone().expect("try_clone");
927 assert_eq!(cloned.id(), 7);
928 assert_eq!(cloned.query_count(), 1);
929 let (name, qtype, _) = cloned.query_get(0).expect("query_get");
930 assert_eq!(name, "example.com");
931 assert_eq!(qtype, DnsRecordType::A);
932
933 rec.set_id(99);
935 assert_eq!(cloned.id(), 7);
936 }
937}