dnssec_prover/
rr.rs

1//! Resource Records are the fundamental type in the DNS - individual records mapping a name to
2//! some data.
3//!
4//! This module holds structs and utilities for the Resource Records supported by this crate.
5
6use alloc::vec::Vec;
7use alloc::string::String;
8use alloc::borrow::ToOwned;
9use alloc::format;
10
11use core::cmp::Ordering;
12use core::fmt;
13use core::fmt::Write;
14use core::num::NonZeroU8;
15
16use crate::ser::*;
17
18/// A valid domain name.
19///
20/// It must end with a ".", be no longer than 255 bytes, consist of only printable ASCII
21/// characters and each label may be no longer than 63 bytes.
22#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
23pub struct Name(String);
24impl Name {
25	/// Gets the underlying human-readable domain name
26	pub fn as_str(&self) -> &str { &self.0 }
27	/// Gets the number of labels in this name
28	pub fn labels(&self) -> u8 {
29		if self.as_str() == "." {
30			0
31		} else {
32			self.as_str().chars().filter(|c| *c == '.').count() as u8
33		}
34	}
35	/// Gets a string containing the last `n` labels in this [`Name`] (which is also a valid name).
36	pub fn trailing_n_labels(&self, n: u8) -> Option<&str> {
37		let labels = self.labels();
38		if n > labels {
39			None
40		} else if n == labels {
41			Some(self.as_str())
42		} else if n == 0 {
43			Some(".")
44		} else {
45			self.as_str().splitn(labels as usize - n as usize + 1, '.').last()
46		}
47	}
48}
49impl core::ops::Deref for Name {
50	type Target = str;
51	fn deref(&self) -> &str { &self.0 }
52}
53impl fmt::Display for Name {
54	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
55		self.0.fmt(f)
56	}
57}
58impl TryFrom<String> for Name {
59	type Error = ();
60	fn try_from(s: String) -> Result<Name, ()> {
61		if s.is_empty() { return Err(()); }
62		if *s.as_bytes().last().unwrap_or(&0) != b"."[0] { return Err(()); }
63		if s.len() > 255 { return Err(()); }
64		if s.chars().any(|c| !c.is_ascii_graphic() || c == '"') { return Err(()); }
65		for label in s.split('.') {
66			if label.len() > 63 { return Err(()); }
67		}
68
69		Ok(Name(s.to_ascii_lowercase()))
70	}
71}
72impl TryFrom<&str> for Name {
73	type Error = ();
74	fn try_from(s: &str) -> Result<Name, ()> {
75		Self::try_from(s.to_owned())
76	}
77}
78
79#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
80/// A supported Resource Record
81///
82/// Note that we only currently support a handful of RR types as needed to generate and validate
83/// TXT or TLSA record proofs.
84pub enum RR {
85	/// An IPv4 resource record
86	A(A),
87	/// An IPv6 resource record
88	AAAA(AAAA),
89	/// A name server resource record
90	NS(NS),
91	/// A text resource record
92	Txt(Txt),
93	/// A TLS Certificate Association resource record
94	TLSA(TLSA),
95	/// A Canonical Name record
96	CName(CName),
97	/// A Delegation Name record
98	DName(DName),
99	/// A DNS (Public) Key resource record
100	DnsKey(DnsKey),
101	/// A Delegated Signer resource record
102	DS(DS),
103	/// A Resource Record Signature record
104	RRSig(RRSig),
105	/// A Next Secure Record record
106	NSec(NSec),
107	/// A Next Secure Record version 3 record
108	NSec3(NSec3),
109}
110impl RR {
111	/// Gets the name this record refers to.
112	pub fn name(&self) -> &Name {
113		match self {
114			RR::A(rr) => &rr.name,
115			RR::AAAA(rr) => &rr.name,
116			RR::NS(rr) => &rr.name,
117			RR::Txt(rr) => &rr.name,
118			RR::CName(rr) => &rr.name,
119			RR::DName(rr) => &rr.name,
120			RR::TLSA(rr) => &rr.name,
121			RR::DnsKey(rr) => &rr.name,
122			RR::DS(rr) => &rr.name,
123			RR::RRSig(rr) => &rr.name,
124			RR::NSec(rr) => &rr.name,
125			RR::NSec3(rr) => &rr.name,
126		}
127	}
128	/// Gets a JSON encoding of this record
129	pub fn json(&self) -> String {
130		match self {
131			RR::A(rr) => StaticRecord::json(rr),
132			RR::AAAA(rr) => StaticRecord::json(rr),
133			RR::NS(rr) => StaticRecord::json(rr),
134			RR::Txt(rr) => StaticRecord::json(rr),
135			RR::CName(rr) => StaticRecord::json(rr),
136			RR::DName(rr) => StaticRecord::json(rr),
137			RR::TLSA(rr) => StaticRecord::json(rr),
138			RR::DnsKey(rr) => StaticRecord::json(rr),
139			RR::DS(rr) => StaticRecord::json(rr),
140			RR::RRSig(rr) => StaticRecord::json(rr),
141			RR::NSec(rr) => StaticRecord::json(rr),
142			RR::NSec3(rr) => StaticRecord::json(rr),
143		}
144	}
145	fn ty(&self) -> u16 {
146		match self {
147			RR::A(_) => A::TYPE,
148			RR::AAAA(_) => AAAA::TYPE,
149			RR::NS(_) => NS::TYPE,
150			RR::Txt(_) => Txt::TYPE,
151			RR::CName(_) => CName::TYPE,
152			RR::DName(_) => DName::TYPE,
153			RR::TLSA(_) => TLSA::TYPE,
154			RR::DnsKey(_) => DnsKey::TYPE,
155			RR::DS(_) => DS::TYPE,
156			RR::RRSig(_) => RRSig::TYPE,
157			RR::NSec(_) => NSec::TYPE,
158			RR::NSec3(_) => NSec3::TYPE,
159		}
160	}
161	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
162		match self {
163			RR::A(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
164			RR::AAAA(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
165			RR::NS(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
166			RR::Txt(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
167			RR::CName(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
168			RR::DName(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
169			RR::TLSA(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
170			RR::DnsKey(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
171			RR::DS(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
172			RR::RRSig(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
173			RR::NSec(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
174			RR::NSec3(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
175		}
176	}
177	fn ty_to_rr_name(ty: u16) -> Option<&'static str> {
178		match ty {
179			A::TYPE => Some("A"),
180			AAAA::TYPE => Some("AAAA"),
181			NS::TYPE => Some("NS"),
182			Txt::TYPE => Some("TXT"),
183			CName::TYPE => Some("CNAME"),
184			DName::TYPE => Some("DNAME"),
185			TLSA::TYPE => Some("TLSA"),
186			DnsKey::TYPE => Some("DNSKEY"),
187			DS::TYPE => Some("DS"),
188			RRSig::TYPE => Some("RRSIG"),
189			NSec::TYPE => Some("NSEC"),
190			NSec3::TYPE => Some("NSEC3"),
191			_ => None,
192		}
193	}
194}
195impl From<A> for RR { fn from(a: A) -> RR { RR::A(a) } }
196impl From<AAAA> for RR { fn from(aaaa: AAAA) -> RR { RR::AAAA(aaaa) } }
197impl From<NS> for RR { fn from(ns: NS) -> RR { RR::NS(ns) } }
198impl From<Txt> for RR { fn from(txt: Txt) -> RR { RR::Txt(txt) } }
199impl From<CName> for RR { fn from(cname: CName) -> RR { RR::CName(cname) } }
200impl From<DName> for RR { fn from(cname: DName) -> RR { RR::DName(cname) } }
201impl From<TLSA> for RR { fn from(tlsa: TLSA) -> RR { RR::TLSA(tlsa) } }
202impl From<DnsKey> for RR { fn from(dnskey: DnsKey) -> RR { RR::DnsKey(dnskey) } }
203impl From<DS> for RR { fn from(ds: DS) -> RR { RR::DS(ds) } }
204impl From<RRSig> for RR { fn from(rrsig: RRSig) -> RR { RR::RRSig(rrsig) } }
205impl From<NSec> for RR { fn from(nsec: NSec) -> RR { RR::NSec(nsec) } }
206impl From<NSec3> for RR { fn from(nsec3: NSec3) -> RR { RR::NSec3(nsec3) } }
207
208pub(crate) trait StaticRecord : Ord + Sized {
209	// http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
210	const TYPE: u16;
211	fn name(&self) -> &Name;
212	fn json(&self) -> String;
213	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W);
214	fn read_from_data(name: Name, data: &[u8], wire_packet: &[u8]) -> Result<Self, ()>;
215}
216
217/// A record that can be written to a generic [`Writer`]
218pub(crate) trait WriteableRecord : Record {
219	fn serialize_u16_len_prefixed<W: Writer>(&self, out: &mut W);
220}
221impl<RR: StaticRecord> WriteableRecord for RR {
222	fn serialize_u16_len_prefixed<W: Writer>(&self, out: &mut W) {
223		RR::write_u16_len_prefixed_data(self, out)
224	}
225}
226impl WriteableRecord for RR {
227	fn serialize_u16_len_prefixed<W: Writer>(&self, out: &mut W) {
228		RR::write_u16_len_prefixed_data(self, out)
229	}
230}
231
232/// A trait describing a resource record (including the [`RR`] enum).
233pub trait Record : Ord {
234	/// The resource record type, as maintained by IANA.
235	///
236	/// Current assignments can be found at
237	/// <http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4>
238	fn ty(&self) -> u16;
239	/// The name this record is at.
240	fn name(&self) -> &Name;
241	/// Gets a JSON encoding of this record.
242	fn json(&self) -> String;
243	/// Writes the data of this record, prefixed by a u16 length, to the given `Vec`.
244	fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>);
245}
246impl<RR: StaticRecord> Record for RR {
247	fn ty(&self) -> u16 { RR::TYPE }
248	fn name(&self) -> &Name { RR::name(self) }
249	fn json(&self) -> String { RR::json(self) }
250	fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
251		RR::write_u16_len_prefixed_data(self, out)
252	}
253}
254impl Record for RR {
255	fn ty(&self) -> u16 { self.ty() }
256	fn name(&self) -> &Name { self.name() }
257	fn json(&self) -> String { self.json() }
258	fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
259		self.write_u16_len_prefixed_data(out)
260	}
261}
262
263#[derive(Debug, Clone, Hash, PartialEq, Eq)]
264struct TxtBytePart {
265	/// The bytes themselves.
266	///
267	/// Bytes at or beyond [`Self::len`] may be filled with garbage and should be ignored.
268	bytes: [u8; 255],
269	/// The number of bytes which are to be used.
270	len: NonZeroU8,
271}
272
273/// The bytes of a [`Txt`] record.
274///
275/// They are stored as a series of byte buffers so that we can reconstruct the exact encoding which
276/// was used for signatures, however they're really just a simple list of bytes, and the underlying
277/// encoding should be ignored.
278#[derive(Debug, Clone, Hash, PartialEq, Eq)]
279pub struct TxtBytes {
280	/// The series of byte buffers storing the bytes themselves.
281	chunks: Vec<TxtBytePart>,
282}
283
284impl TxtBytes {
285	/// Constructs a new [`TxtBytes`] from the given bytes
286	///
287	/// Fails if there are too many bytes to fit in a [`Txt`] record.
288	pub fn new(bytes: &[u8]) -> Result<TxtBytes, ()> {
289		if bytes.len() > 255*255 + 254 { return Err(()); }
290		let mut chunks = Vec::with_capacity((bytes.len() + 254) / 255);
291		let mut data_write = &bytes[..];
292		while !data_write.is_empty() {
293			let split_pos = core::cmp::min(255, data_write.len());
294			let mut part = TxtBytePart {
295				bytes: [0; 255],
296				len: (split_pos as u8).try_into().expect("Cannot be 0 as data_write is not empty"),
297			};
298			part.bytes[..split_pos].copy_from_slice(&data_write[..split_pos]);
299			chunks.push(part);
300			data_write = &data_write[split_pos..];
301		}
302		debug_assert_eq!(chunks.len(), (bytes.len() + 254) / 255);
303		Ok(TxtBytes { chunks })
304	}
305
306	/// Gets the total number of bytes represented in this record.
307	pub fn len(&self) -> usize {
308		let mut res = 0;
309		for chunk in self.chunks.iter() {
310			res += chunk.len.get() as usize;
311		}
312		res
313	}
314
315	/// The length of the bytes when serialized on the wire.
316	pub fn serialized_len(&self) -> u16 {
317		let mut len = 0u16;
318		for chunk in self.chunks.iter() {
319			len = len.checked_add(1 + chunk.len.get() as u16)
320				.expect("TxtBytes objects must fit in 2^16 - 1 bytes when serialized");
321		}
322		len
323	}
324
325	/// Gets the bytes as a flat `Vec` of `u8`s. This should be considered
326	pub fn as_vec(&self) -> Vec<u8> {
327		let mut res = Vec::with_capacity(self.len());
328		for chunk in self.chunks.iter() {
329			res.extend_from_slice(&chunk.bytes[..chunk.len.get() as usize]);
330		}
331		res
332	}
333
334	/// Gets an iterator over all the bytes in this [`TxtBytes`].
335	pub fn iter<'a>(&'a self) -> TxtBytesIter<'a> {
336		TxtBytesIter {
337			bytes: self,
338			next_part: 0,
339			next_byte: 0,
340		}
341	}
342}
343
344impl TryFrom<&str> for TxtBytes {
345	type Error = ();
346	fn try_from(s: &str) -> Result<TxtBytes, ()> {
347		TxtBytes::new(s.as_bytes())
348	}
349}
350
351impl TryFrom<&[u8]> for TxtBytes {
352	type Error = ();
353	fn try_from(b: &[u8]) -> Result<TxtBytes, ()> {
354		TxtBytes::new(b)
355	}
356}
357
358/// An iterator over the bytes in a [`TxtBytes`]
359pub struct TxtBytesIter<'a> {
360	bytes: &'a TxtBytes,
361	next_part: usize,
362	next_byte: u8,
363}
364
365impl<'a> Iterator for TxtBytesIter<'a> {
366	type Item = u8;
367	fn next(&mut self) -> Option<u8> {
368		self.bytes.chunks.get(self.next_part)
369			.and_then(|part| if self.next_byte >= part.len.get() {
370				None
371			} else {
372				let res = Some(part.bytes[self.next_byte as usize]);
373				if self.next_byte == part.len.get() - 1 {
374					self.next_byte = 0;
375					self.next_part += 1;
376				} else {
377					self.next_byte += 1;
378				}
379				res
380			})
381	}
382}
383
384#[derive(Debug, Clone, Hash, PartialEq, Eq)]
385/// A text resource record, containing arbitrary text data
386pub struct Txt {
387	/// The name this record is at.
388	pub name: Name,
389	/// The text record itself.
390	///
391	/// While this is generally UTF-8-valid, there is no specific requirement that it be, and thus
392	/// is an arbitrary series of bytes here.
393	pub data: TxtBytes,
394}
395/// The wire type for TXT records
396pub const TXT_TYPE: u16 = 16;
397impl Ord for Txt {
398	fn cmp(&self, o: &Txt) -> Ordering {
399		self.name.cmp(&o.name)
400			.then_with(|| {
401				// Compare in wire encoding form, i.e. compare checks in order
402				let mut o_chunks = o.data.chunks.iter();
403				for chunk in self.data.chunks.iter() {
404					if let Some(o_chunk) = o_chunks.next() {
405						let chunk_cmp = chunk.len.cmp(&o_chunk.len)
406							.then_with(||chunk.bytes[..chunk.len.get() as usize]
407								.cmp(&o_chunk.bytes[..o_chunk.len.get() as usize]));
408						if !chunk_cmp.is_eq() { return chunk_cmp; }
409					} else {
410						// self has more chunks than o
411						return Ordering::Greater;
412					}
413				}
414				if o_chunks.next().is_some() {
415					Ordering::Less
416				} else {
417					Ordering::Equal
418				}
419			})
420	}
421}
422impl PartialOrd for Txt {
423	fn partial_cmp(&self, o: &Txt) -> Option<Ordering> { Some(self.cmp(o)) }
424}
425impl StaticRecord for Txt {
426	const TYPE: u16 = TXT_TYPE;
427	fn name(&self) -> &Name { &self.name }
428	fn json(&self) -> String {
429		let mut res = format!("{{\"type\":\"txt\",\"name\":\"{}\",\"contents\":", self.name.0);
430		if self.data.iter().all(|b| b >= 0x20 && b <= 0x7e) {
431			res += "\"";
432			for b in self.data.iter() {
433				res.push(b as char);
434			}
435			res += "\"}";
436		} else {
437			res += "[";
438			let mut first_b = true;
439			for b in self.data.iter() {
440				if !first_b { res += ","; }
441				write!(&mut res, "{}", b).expect("Shouldn't fail to write to a String");
442				first_b = false;
443			}
444			res += "]}";
445		}
446		res
447	}
448	fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
449		let mut parts = TxtBytes {
450			chunks: Vec::with_capacity((data.len() + 255) / 256),
451		};
452		let mut serialized_len = 0;
453		while !data.is_empty() {
454			let len = read_u8(&mut data)?;
455			if data.len() < len as usize { return Err(()); }
456			if len == 0 { return Err(()); }
457			serialized_len += 1 + len as u32;
458			if serialized_len > u16::MAX as u32 {
459				return Err(());
460			}
461			let mut part = TxtBytePart {
462				bytes: [0; 255],
463				len: len.try_into().expect("We already checked 0 above"),
464			};
465			part.bytes[..len as usize].copy_from_slice(&data[..len as usize]);
466			data = &data[len as usize..];
467			parts.chunks.push(part);
468		}
469		debug_assert!(data.is_empty());
470		Ok(Txt { name, data: parts })
471	}
472	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
473		out.write(&self.data.serialized_len().to_be_bytes());
474		for chunk in self.data.chunks.iter() {
475			out.write(&[chunk.len.get()]);
476			out.write(&chunk.bytes[..chunk.len.get() as usize]);
477		}
478	}
479}
480
481#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
482/// A TLS Certificate Association resource record containing information about the TLS certificate
483/// which should be expected when communicating with the host at the given name.
484///
485/// See <https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities#TLSA_RR> for more
486/// info.
487pub struct TLSA {
488	/// The name this record is at.
489	pub name: Name,
490	/// The type of constraint on the TLS certificate(s) used which should be enforced by this
491	/// record.
492	pub cert_usage: u8,
493	/// Whether to match on the full certificate, or only the public key.
494	pub selector: u8,
495	/// The type of data included which is used to match the TLS certificate(s).
496	pub data_ty: u8,
497	/// The certificate data or hash of the certificate data itself.
498	pub data: Vec<u8>,
499}
500/// The wire type for TLSA records
501pub const TLSA_TYPE: u16 = 52;
502impl StaticRecord for TLSA {
503	const TYPE: u16 = TLSA_TYPE;
504	fn name(&self) -> &Name { &self.name }
505	fn json(&self) -> String {
506		let mut out = String::with_capacity(128+self.data.len()*2);
507		write!(&mut out,
508			"{{\"type\":\"tlsa\",\"name\":\"{}\",\"usage\":{},\"selector\":{},\"data_ty\":{},\"data\":\"",
509			self.name.0, self.cert_usage, self.selector, self.data_ty
510		).expect("Write to a String shouldn't fail");
511		for c in self.data.iter() {
512			write!(&mut out, "{:02X}", c)
513				.expect("Write to a String shouldn't fail");
514		}
515		out += "\"}";
516		out
517	}
518	fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
519		Ok(TLSA {
520			name, cert_usage: read_u8(&mut data)?, selector: read_u8(&mut data)?,
521			data_ty: read_u8(&mut data)?, data: data.to_vec(),
522		})
523	}
524	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
525		let len = 3 + self.data.len();
526		out.write(&(len as u16).to_be_bytes());
527		out.write(&[self.cert_usage, self.selector, self.data_ty]);
528		out.write(&self.data);
529	}
530}
531
532#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
533/// A Canonical Name resource record, referring all queries for this name to another name.
534pub struct CName {
535	/// The name this record is at.
536	pub name: Name,
537	/// The canonical name.
538	///
539	/// A resolver should use this name when looking up any further records for [`self.name`].
540	pub canonical_name: Name,
541}
542impl StaticRecord for CName {
543	const TYPE: u16 = 5;
544	fn name(&self) -> &Name { &self.name }
545	fn json(&self) -> String {
546		format!("{{\"type\":\"cname\",\"name\":\"{}\",\"canonical_name\":\"{}\"}}",
547			self.name.0, self.canonical_name.0)
548	}
549	fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
550		let res = CName { name, canonical_name: read_wire_packet_name(&mut data, wire_packet)? };
551		Ok(res)
552	}
553	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
554		let len: u16 = name_len(&self.canonical_name);
555		out.write(&len.to_be_bytes());
556		write_name(out, &self.canonical_name);
557	}
558}
559
560#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
561/// A Delegation Name resource record, referring all queries for subdomains of this name to another
562/// subtree of the DNS.
563pub struct DName {
564	/// The name this record is at.
565	pub name: Name,
566	/// The delegation name.
567	///
568	/// A resolver should use this domain name tree when looking up any further records for
569	/// subdomains of [`self.name`].
570	pub delegation_name: Name,
571}
572impl StaticRecord for DName {
573	const TYPE: u16 = 39;
574	fn name(&self) -> &Name { &self.name }
575	fn json(&self) -> String {
576		format!("{{\"type\":\"dname\",\"name\":\"{}\",\"delegation_name\":\"{}\"}}",
577			self.name.0, self.delegation_name.0)
578	}
579	fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
580		let res = DName { name, delegation_name: read_wire_packet_name(&mut data, wire_packet)? };
581		Ok(res)
582	}
583	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
584		let len: u16 = name_len(&self.delegation_name);
585		out.write(&len.to_be_bytes());
586		write_name(out, &self.delegation_name);
587	}
588}
589
590
591#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
592/// A public key resource record which can be used to validate [`RRSig`]s.
593pub struct DnsKey {
594	/// The name this record is at.
595	pub name: Name,
596	/// Flags which constrain the usage of this public key.
597	pub flags: u16,
598	/// The protocol this key is used for (protocol `3` is DNSSEC). 
599	pub protocol: u8,
600	/// The algorithm which this public key uses to sign data.
601	pub alg: u8,
602	/// The public key itself.
603	pub pubkey: Vec<u8>,
604}
605impl StaticRecord for DnsKey {
606	const TYPE: u16 = 48;
607	fn name(&self) -> &Name { &self.name }
608	fn json(&self) -> String {
609		let mut out = String::with_capacity(128+self.pubkey.len()*2);
610		write!(&mut out,
611			"{{\"type\":\"dnskey\",\"name\":\"{}\",\"flags\":{},\"protocol\":{},\"alg\":{},\"pubkey\":\"",
612			self.name.0, self.flags, self.protocol, self.alg
613		).expect("Write to a String shouldn't fail");
614		for c in self.pubkey.iter() {
615			write!(&mut out, "{:02X}", c)
616				.expect("Write to a String shouldn't fail");
617		}
618		out += "\"}";
619		out
620	}
621	fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
622		Ok(DnsKey {
623			name, flags: read_u16(&mut data)?, protocol: read_u8(&mut data)?,
624			alg: read_u8(&mut data)?, pubkey: data.to_vec(),
625		})
626	}
627	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
628		let len = 2 + 1 + 1 + self.pubkey.len();
629		out.write(&(len as u16).to_be_bytes());
630		out.write(&self.flags.to_be_bytes());
631		out.write(&self.protocol.to_be_bytes());
632		out.write(&self.alg.to_be_bytes());
633		out.write(&self.pubkey);
634	}
635}
636impl DnsKey {
637	/// A short (non-cryptographic) digest which can be used to refer to this [`DnsKey`].
638	pub fn key_tag(&self) -> u16 {
639		let mut res = u32::from(self.flags);
640		res += u32::from(self.protocol) << 8;
641		res += u32::from(self.alg);
642		for (idx, b) in self.pubkey.iter().enumerate() {
643			if idx % 2 == 0 {
644				res += u32::from(*b) << 8;
645			} else {
646				res += u32::from(*b);
647			}
648		}
649		res += (res >> 16) & 0xffff;
650		(res & 0xffff) as u16
651	}
652}
653
654#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
655/// A Delegation Signer resource record which indicates that some alternative [`DnsKey`] can sign
656/// for records in the zone which matches [`self.name`].
657pub struct DS {
658	/// The name this record is at.
659	///
660	/// This is also the zone that a [`DnsKey`] which matches the [`Self::digest`] can sign for.
661	pub name: Name,
662	/// A short tag which describes the matching [`DnsKey`].
663	///
664	/// This matches the [`DnsKey::key_tag`] for the [`DnsKey`] which is referred to by this
665	/// [`DS`].
666	pub key_tag: u16,
667	/// The algorithm which the [`DnsKey`] referred to by this [`DS`] uses.
668	///
669	/// This matches the [`DnsKey::alg`] field in the referred-to [`DnsKey`].
670	pub alg: u8,
671	/// The type of digest used to hash the referred-to [`DnsKey`].
672	pub digest_type: u8,
673	/// The digest itself.
674	pub digest: Vec<u8>,
675}
676impl StaticRecord for DS {
677	const TYPE: u16 = 43;
678	fn name(&self) -> &Name { &self.name }
679	fn json(&self) -> String {
680		let mut out = String::with_capacity(128+self.digest.len()*2);
681		write!(&mut out,
682			"{{\"type\":\"ds\",\"name\":\"{}\",\"key_tag\":{},\"alg\":{},\"digest_type\":{},\"digest\":\"",
683			self.name.0, self.key_tag, self.alg, self.digest_type
684		).expect("Write to a String shouldn't fail");
685		for c in self.digest.iter() {
686			write!(&mut out, "{:02X}", c)
687				.expect("Write to a String shouldn't fail");
688		}
689		out += "\"}";
690		out
691	}
692	fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
693		Ok(DS {
694			name, key_tag: read_u16(&mut data)?, alg: read_u8(&mut data)?,
695			digest_type: read_u8(&mut data)?, digest: data.to_vec(),
696		})
697	}
698	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
699		let len = 2 + 1 + 1 + self.digest.len();
700		out.write(&(len as u16).to_be_bytes());
701		out.write(&self.key_tag.to_be_bytes());
702		out.write(&self.alg.to_be_bytes());
703		out.write(&self.digest_type.to_be_bytes());
704		out.write(&self.digest);
705	}
706}
707
708#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
709/// A Resource Record (set) Signature resource record. This contains a signature over all the
710/// resources records of the given type at the given name.
711pub struct RRSig {
712	/// The name this record is at.
713	///
714	/// This is also the name of any records which this signature is covering (ignoring wildcards).
715	pub name: Name,
716	/// The resource record type which this [`RRSig`] is signing.
717	///
718	/// All resources records of this type at the same name as [`self.name`] must be signed by
719	/// this [`RRSig`].
720	pub ty: u16,
721	/// The algorithm which is being used to sign.
722	///
723	/// This must match the [`DnsKey::alg`] field in the [`DnsKey`] being used to sign.
724	pub alg: u8,
725	/// The number of labels in the name of the records that this signature is signing.
726	///
727	/// If this is less than the number of labels in [`self.name`], this signature is covering a
728	/// wildcard entry.
729	pub labels: u8,
730	/// The TTL of the records which this [`RRSig`] is signing.
731	pub orig_ttl: u32,
732	/// The expiration (as a UNIX timestamp) of this signature.
733	pub expiration: u32,
734	/// The time (as a UNIX timestamp) at which this signature becomes valid.
735	pub inception: u32,
736	/// A short tag which describes the matching [`DnsKey`].
737	///
738	/// This matches the [`DnsKey::key_tag`] for the [`DnsKey`] which created this signature.
739	pub key_tag: u16,
740	/// The [`DnsKey::name`] in the [`DnsKey`] which created this signature.
741	///
742	/// This must be a parent of [`self.name`].
743	///
744	/// [`DnsKey::name`]: Record::name
745	// We'd like to just link to the `DnsKey` member variable called `name`, but there doesn't
746	// appear to be a way to actually do that, so instead we have to link to the trait method.
747	pub key_name: Name,
748	/// The signature itself.
749	pub signature: Vec<u8>,
750}
751impl StaticRecord for RRSig {
752	const TYPE: u16 = 46;
753	fn name(&self) -> &Name { &self.name }
754	fn json(&self) -> String {
755		let mut out = String::with_capacity(256 + self.signature.len()*2);
756		write!(&mut out,
757			"{{\"type\":\"ds\",\"name\":\"{}\",\"signed_record_type\":{},\"alg\":{},\"signed_labels\":{},\"orig_ttl\":{},\"expiration\"{},\"inception\":{},\"key_tag\":{},\"key_name\":\"{}\",\"signature\":\"",
758			self.name.0, self.ty, self.alg, self.labels, self.orig_ttl, self.expiration, self.inception, self.key_tag, self.key_name.0
759		).expect("Write to a String shouldn't fail");
760		for c in self.signature.iter() {
761			write!(&mut out, "{:02X}", c)
762				.expect("Write to a String shouldn't fail");
763		}
764		out += "\"}";
765		out
766	}
767	fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
768		Ok(RRSig {
769			name, ty: read_u16(&mut data)?, alg: read_u8(&mut data)?,
770			labels: read_u8(&mut data)?, orig_ttl: read_u32(&mut data)?,
771			expiration: read_u32(&mut data)?, inception: read_u32(&mut data)?,
772			key_tag: read_u16(&mut data)?,
773			key_name: read_wire_packet_name(&mut data, wire_packet)?,
774			signature: data.to_vec(),
775		})
776	}
777	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
778		let len = 2 + 1 + 1 + 4*3 + 2 + name_len(&self.key_name) + self.signature.len() as u16;
779		out.write(&len.to_be_bytes());
780		out.write(&self.ty.to_be_bytes());
781		out.write(&self.alg.to_be_bytes());
782		out.write(&self.labels.to_be_bytes());
783		out.write(&self.orig_ttl.to_be_bytes());
784		out.write(&self.expiration.to_be_bytes());
785		out.write(&self.inception.to_be_bytes());
786		out.write(&self.key_tag.to_be_bytes());
787		write_name(out, &self.key_name);
788		out.write(&self.signature);
789	}
790}
791
792#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
793/// A mask used in [`NSec`] and [`NSec3`] records which indicates the resource record types which
794/// exist at the (hash of the) name described in [`Record::name`].
795pub struct NSecTypeMask([u8; 8192]);
796impl NSecTypeMask {
797	/// Constructs a new, empty, type mask.
798	pub fn new() -> Self { Self([0; 8192]) }
799	/// Builds a new type mask with the given types set
800	pub fn from_types(types: &[u16]) -> Self {
801		let mut flags = [0; 8192];
802		for t in types {
803			flags[*t as usize >> 3] |= 1 << (7 - (*t as usize % 8));
804		}
805		let res = Self(flags);
806		for t in types {
807			debug_assert!(res.contains_type(*t));
808		}
809		res
810	}
811	/// Checks if the given type (from [`Record::ty`]) is set, indicating a record of this type
812	/// exists.
813	pub fn contains_type(&self, ty: u16) -> bool {
814		let f = self.0[(ty >> 3) as usize];
815		// DNSSEC's bit fields are in wire order, so the high bit is type 0, etc.
816		f & (1 << (7 - (ty % 8))) != 0
817	}
818	fn write_json(&self, s: &mut String) {
819		*s += "[";
820		write!(s, "{:?}", self).expect("Writes to a string shouldn't fail");
821		*s += "]";
822	}
823}
824impl fmt::Debug for NSecTypeMask {
825	fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
826		let mut have_written = false;
827		for (idx, mask) in self.0.iter().enumerate() {
828			if *mask == 0 { continue; }
829			for b in 0..8 {
830				if *mask & (1 << b) != 0 {
831					let ty = ((idx as u16) << 3) | (7 - b);
832					match RR::ty_to_rr_name(ty) {
833						Some(name) => write!(f, "{}\"{}\"", if have_written { "," } else { "" }, name)?,
834						_ => write!(f, "{}{}", if have_written { "," } else { "" }, ty)?,
835					}
836					have_written = true;
837				}
838			}
839		}
840		Ok(())
841	}
842}
843
844#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
845/// A Next Secure Record resource record. This indicates a range of possible names for which there
846/// is no such record.
847pub struct NSec {
848	/// The name this record is at.
849	pub name: Name,
850	/// The next name which contains a record. There are no names between `name` and
851	/// [`Self::next_name`].
852	pub next_name: Name,
853	/// The set of record types which exist at `name`. Any other record types do not exist at
854	/// `name`.
855	pub types: NSecTypeMask,
856}
857impl StaticRecord for NSec {
858	const TYPE: u16 = 47;
859	fn name(&self) -> &Name { &self.name }
860	fn json(&self) -> String {
861		let mut out = String::with_capacity(256 + self.next_name.len());
862		write!(&mut out,
863			"{{\"type\":\"nsec\",\"name\":\"{}\",\"next_name\":\"{}\",\"types\":",
864			self.name.0, self.next_name.0,
865		).expect("Write to a String shouldn't fail");
866		self.types.write_json(&mut out);
867		out += "}";
868		out
869	}
870	fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
871		let res = NSec {
872			name, next_name: read_wire_packet_name(&mut data, wire_packet)?,
873			types: NSecTypeMask(read_nsec_types_bitmap(&mut data)?),
874		};
875		debug_assert!(data.is_empty());
876		Ok(res)
877	}
878	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
879		let len = name_len(&self.next_name) + nsec_types_bitmap_len(&self.types.0);
880		out.write(&len.to_be_bytes());
881		write_name(out, &self.next_name);
882		write_nsec_types_bitmap(out, &self.types.0);
883	}
884}
885
886#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
887/// A Next Secure Record resource record. This indicates a range of possible names for which there
888/// is no such record.
889pub struct NSec3 {
890	/// The name this record is at.
891	pub name: Name,
892	/// The hash algorithm used to hash the `name` and [`Self::next_name_hash`]. Currently only 1
893	/// (SHA-1) is defined.
894	pub hash_algo: u8,
895	/// Flags for this record. Currently only bit 0 (the "opt-out" bit) is defined.
896	pub flags: u8,
897	/// The number of hash iterations required.
898	///
899	/// As of RFC 9276 this MUST be set to 0, but sadly is often still set higher in the wild. A
900	/// hard cap is applied in validation.
901	pub hash_iterations: u16,
902	/// The salt included in the hash.
903	///
904	/// As of RFC 9276 this SHOULD be empty, but often isn't in the wild.
905	pub salt: Vec<u8>,
906	/// The hash of the next name which contains a record. There are no records who's name's hash
907	/// lies between `name` and [`Self::next_name_hash`].
908	pub next_name_hash: Vec<u8>,
909	/// The set of record types which exist at `name`. Any other record types do not exist at
910	/// `name`.
911	pub types: NSecTypeMask,
912}
913impl StaticRecord for NSec3 {
914	const TYPE: u16 = 50;
915	fn name(&self) -> &Name { &self.name }
916	fn json(&self) -> String {
917		let mut out = String::with_capacity(256);
918		write!(&mut out,
919			"{{\"type\":\"nsec3\",\"name\":\"{}\",\"hash_algo\":{},\"flags\":{},\"hash_iterations\":{},\"salt\":{:?},\"next_name_hash\":{:?},\"types\":",
920			self.name.0, self.hash_algo, self.flags, self.hash_iterations, &self.salt[..], &self.next_name_hash[..]
921		).expect("Write to a String shouldn't fail");
922		self.types.write_json(&mut out);
923		out += "}";
924		out
925	}
926	fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
927		let res = NSec3 {
928			name, hash_algo: read_u8(&mut data)?, flags: read_u8(&mut data)?,
929			hash_iterations: read_u16(&mut data)?, salt: read_u8_len_prefixed_bytes(&mut data)?,
930			next_name_hash: read_u8_len_prefixed_bytes(&mut data)?,
931			types: NSecTypeMask(read_nsec_types_bitmap(&mut data)?),
932		};
933		debug_assert!(data.is_empty());
934		Ok(res)
935	}
936	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
937		let len = 4 + 2 + self.salt.len() as u16 + self.next_name_hash.len() as u16 +
938			nsec_types_bitmap_len(&self.types.0);
939		out.write(&len.to_be_bytes());
940		out.write(&self.hash_algo.to_be_bytes());
941		out.write(&self.flags.to_be_bytes());
942		out.write(&self.hash_iterations.to_be_bytes());
943		out.write(&(self.salt.len() as u8).to_be_bytes());
944		out.write(&self.salt);
945		out.write(&(self.next_name_hash.len() as u8).to_be_bytes());
946		out.write(&self.next_name_hash);
947		write_nsec_types_bitmap(out, &self.types.0);
948	}
949}
950
951#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
952/// An IPv4 Address resource record
953pub struct A {
954	/// The name this record is at.
955	pub name: Name,
956	/// The bytes of the IPv4 address.
957	pub address: [u8; 4],
958}
959/// The wire type for A records
960pub const A_TYPE: u16 = 1;
961impl StaticRecord for A {
962	const TYPE: u16 = A_TYPE;
963	fn name(&self) -> &Name { &self.name }
964	fn json(&self) -> String {
965		format!("{{\"type\":\"a\",\"name\":\"{}\",\"address\":{:?}}}", self.name.0, self.address)
966	}
967	fn read_from_data(name: Name, data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
968		if data.len() != 4 { return Err(()); }
969		let mut address = [0; 4];
970		address.copy_from_slice(data);
971		Ok(A { name, address })
972	}
973	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
974		out.write(&4u16.to_be_bytes());
975		out.write(&self.address);
976	}
977}
978
979#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
980/// An IPv6 Address resource record
981pub struct AAAA {
982	/// The name this record is at.
983	pub name: Name,
984	/// The bytes of the IPv6 address.
985	pub address: [u8; 16],
986}
987/// The wire type for AAAA records
988pub const AAAA_TYPE: u16 = 28;
989impl StaticRecord for AAAA {
990	const TYPE: u16 = AAAA_TYPE;
991	fn name(&self) -> &Name { &self.name }
992	fn json(&self) -> String {
993		format!("{{\"type\":\"aaaa\",\"name\":\"{}\",\"address\":{:?}}}", self.name.0, self.address)
994	}
995	fn read_from_data(name: Name, data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
996		if data.len() != 16 { return Err(()); }
997		let mut address = [0; 16];
998		address.copy_from_slice(data);
999		Ok(AAAA { name, address })
1000	}
1001	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
1002		out.write(&16u16.to_be_bytes());
1003		out.write(&self.address);
1004	}
1005}
1006
1007#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
1008/// A Name Server resource record, which indicates the server responsible for handling queries for
1009/// a zone.
1010pub struct NS {
1011	/// The name this record is at.
1012	///
1013	/// This is also the zone which the server at [`Self::name_server`] is responsible for handling
1014	/// queries for.
1015	pub name: Name,
1016	/// The name of the server which is responsible for handling queries for the [`self.name`]
1017	/// zone.
1018	pub name_server: Name,
1019}
1020impl StaticRecord for NS {
1021	const TYPE: u16 = 2;
1022	fn name(&self) -> &Name { &self.name }
1023	fn json(&self) -> String {
1024		format!("{{\"type\":\"ns\",\"name\":\"{}\",\"ns\":\"{}\"}}", self.name.0, self.name_server.0)
1025	}
1026	fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
1027		let res = NS { name, name_server: read_wire_packet_name(&mut data, wire_packet)? };
1028		Ok(res)
1029	}
1030	fn write_u16_len_prefixed_data<W: Writer>(&self, out: &mut W) {
1031		out.write(&name_len(&self.name_server).to_be_bytes());
1032		write_name(out, &self.name_server);
1033	}
1034}