c464462e0d30a91b359721ed9826176d424d0b96
[dnssec-prover] / src / 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
6 use alloc::vec::Vec;
7 use alloc::string::String;
8 use alloc::borrow::ToOwned;
9 use alloc::format;
10
11 use core::cmp::{self, Ordering};
12 use core::fmt;
13 use core::fmt::Write;
14
15 use crate::ser::*;
16
17 /// A valid domain name.
18 ///
19 /// It must end with a ".", be no longer than 255 bytes, consist of only printable ASCII
20 /// characters and each label may be no longer than 63 bytes.
21 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
22 pub struct Name(String);
23 impl Name {
24         /// Gets the underlying human-readable domain name
25         pub fn as_str(&self) -> &str { &self.0 }
26         /// Gets the number of labels in this name
27         pub fn labels(&self) -> u8 {
28                 if self.as_str() == "." {
29                         0
30                 } else {
31                         self.as_str().chars().filter(|c| *c == '.').count() as u8
32                 }
33         }
34         /// Gets a string containing the last `n` labels in this [`Name`] (which is also a valid name).
35         pub fn trailing_n_labels(&self, n: u8) -> Option<&str> {
36                 let labels = self.labels();
37                 if n > labels {
38                         None
39                 } else if n == labels {
40                         Some(self.as_str())
41                 } else if n == 0 {
42                         Some(".")
43                 } else {
44                         self.as_str().splitn(labels as usize - n as usize + 1, ".").last()
45                 }
46         }
47 }
48 impl core::ops::Deref for Name {
49         type Target = str;
50         fn deref(&self) -> &str { &self.0 }
51 }
52 impl fmt::Display for Name {
53         fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
54                 self.0.fmt(f)
55         }
56 }
57 impl TryFrom<String> for Name {
58         type Error = ();
59         fn try_from(s: String) -> Result<Name, ()> {
60                 if s.is_empty() { return Err(()); }
61                 if *s.as_bytes().last().unwrap_or(&0) != b"."[0] { return Err(()); }
62                 if s.len() > 255 { return Err(()); }
63                 if s.chars().any(|c| !c.is_ascii_graphic() || c == '"') { return Err(()); }
64                 for label in s.split(".") {
65                         if label.len() > 63 { return Err(()); }
66                 }
67
68                 Ok(Name(s.to_ascii_lowercase()))
69         }
70 }
71 impl TryFrom<&str> for Name {
72         type Error = ();
73         fn try_from(s: &str) -> Result<Name, ()> {
74                 Self::try_from(s.to_owned())
75         }
76 }
77
78 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
79 /// A supported Resource Record
80 ///
81 /// Note that we only currently support a handful of RR types as needed to generate and validate
82 /// TXT or TLSA record proofs.
83 pub enum RR {
84         /// An IPv4 resource record
85         A(A),
86         /// An IPv6 resource record
87         AAAA(AAAA),
88         /// A name server resource record
89         NS(NS),
90         /// A text resource record
91         Txt(Txt),
92         /// A TLS Certificate Association resource record
93         TLSA(TLSA),
94         /// A Canonical Name record
95         CName(CName),
96         /// A Delegation Name record
97         DName(DName),
98         /// A DNS (Public) Key resource record
99         DnsKey(DnsKey),
100         /// A Delegated Signer resource record
101         DS(DS),
102         /// A Resource Record Signature record
103         RRSig(RRSig),
104 }
105 impl RR {
106         /// Gets the name this record refers to.
107         pub fn name(&self) -> &Name {
108                 match self {
109                         RR::A(rr) => &rr.name,
110                         RR::AAAA(rr) => &rr.name,
111                         RR::NS(rr) => &rr.name,
112                         RR::Txt(rr) => &rr.name,
113                         RR::CName(rr) => &rr.name,
114                         RR::DName(rr) => &rr.name,
115                         RR::TLSA(rr) => &rr.name,
116                         RR::DnsKey(rr) => &rr.name,
117                         RR::DS(rr) => &rr.name,
118                         RR::RRSig(rr) => &rr.name,
119                 }
120         }
121         /// Gets a JSON encoding of this record
122         pub fn json(&self) -> String {
123                 match self {
124                         RR::A(rr) => StaticRecord::json(rr),
125                         RR::AAAA(rr) => StaticRecord::json(rr),
126                         RR::NS(rr) => StaticRecord::json(rr),
127                         RR::Txt(rr) => StaticRecord::json(rr),
128                         RR::CName(rr) => StaticRecord::json(rr),
129                         RR::DName(rr) => StaticRecord::json(rr),
130                         RR::TLSA(rr) => StaticRecord::json(rr),
131                         RR::DnsKey(rr) => StaticRecord::json(rr),
132                         RR::DS(rr) => StaticRecord::json(rr),
133                         RR::RRSig(rr) => StaticRecord::json(rr),
134                 }
135         }
136         fn ty(&self) -> u16 {
137                 match self {
138                         RR::A(_) => A::TYPE,
139                         RR::AAAA(_) => AAAA::TYPE,
140                         RR::NS(_) => NS::TYPE,
141                         RR::Txt(_) => Txt::TYPE,
142                         RR::CName(_) => CName::TYPE,
143                         RR::DName(_) => DName::TYPE,
144                         RR::TLSA(_) => TLSA::TYPE,
145                         RR::DnsKey(_) => DnsKey::TYPE,
146                         RR::DS(_) => DS::TYPE,
147                         RR::RRSig(_) => RRSig::TYPE,
148                 }
149         }
150         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
151                 match self {
152                         RR::A(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
153                         RR::AAAA(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
154                         RR::NS(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
155                         RR::Txt(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
156                         RR::CName(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
157                         RR::DName(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
158                         RR::TLSA(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
159                         RR::DnsKey(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
160                         RR::DS(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
161                         RR::RRSig(rr) => StaticRecord::write_u16_len_prefixed_data(rr, out),
162                 }
163         }
164         fn ty_to_rr_name(ty: u16) -> Option<&'static str> {
165                 match ty {
166                         A::TYPE => Some("A"),
167                         AAAA::TYPE => Some("AAAA"),
168                         NS::TYPE => Some("NS"),
169                         Txt::TYPE => Some("TXT"),
170                         CName::TYPE => Some("CNAME"),
171                         DName::TYPE => Some("DNAME"),
172                         TLSA::TYPE => Some("TLSA"),
173                         DnsKey::TYPE => Some("DNSKEY"),
174                         DS::TYPE => Some("DS"),
175                         RRSig::TYPE => Some("RRSIG"),
176                         NSec::TYPE => Some("NSEC"),
177                         NSec3::TYPE => Some("NSEC3"),
178                         _ => None,
179                 }
180         }
181 }
182 impl From<A> for RR { fn from(a: A) -> RR { RR::A(a) } }
183 impl From<AAAA> for RR { fn from(aaaa: AAAA) -> RR { RR::AAAA(aaaa) } }
184 impl From<NS> for RR { fn from(ns: NS) -> RR { RR::NS(ns) } }
185 impl From<Txt> for RR { fn from(txt: Txt) -> RR { RR::Txt(txt) } }
186 impl From<CName> for RR { fn from(cname: CName) -> RR { RR::CName(cname) } }
187 impl From<DName> for RR { fn from(cname: DName) -> RR { RR::DName(cname) } }
188 impl From<TLSA> for RR { fn from(tlsa: TLSA) -> RR { RR::TLSA(tlsa) } }
189 impl From<DnsKey> for RR { fn from(dnskey: DnsKey) -> RR { RR::DnsKey(dnskey) } }
190 impl From<DS> for RR { fn from(ds: DS) -> RR { RR::DS(ds) } }
191 impl From<RRSig> for RR { fn from(rrsig: RRSig) -> RR { RR::RRSig(rrsig) } }
192
193 pub(crate) trait StaticRecord : Ord + Sized {
194         // http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4
195         const TYPE: u16;
196         fn name(&self) -> &Name;
197         fn json(&self) -> String;
198         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>);
199         fn read_from_data(name: Name, data: &[u8], wire_packet: &[u8]) -> Result<Self, ()>;
200 }
201 /// A trait describing a resource record (including the [`RR`] enum).
202 pub trait Record : Ord {
203         /// The resource record type, as maintained by IANA.
204         ///
205         /// Current assignments can be found at
206         /// <http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4>
207         fn ty(&self) -> u16;
208         /// The name this record is at.
209         fn name(&self) -> &Name;
210         /// Gets a JSON encoding of this record.
211         fn json(&self) -> String;
212         /// Writes the data of this record, prefixed by a u16 length, to the given `Vec`.
213         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>);
214 }
215 impl<RR: StaticRecord> Record for RR {
216         fn ty(&self) -> u16 { RR::TYPE }
217         fn name(&self) -> &Name { RR::name(self) }
218         fn json(&self) -> String { RR::json(self) }
219         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
220                 RR::write_u16_len_prefixed_data(self, out)
221         }
222 }
223 impl Record for RR {
224         fn ty(&self) -> u16 { self.ty() }
225         fn name(&self) -> &Name { self.name() }
226         fn json(&self) -> String { self.json() }
227         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
228                 self.write_u16_len_prefixed_data(out)
229         }
230 }
231
232 #[derive(Debug, Clone, PartialEq, Eq, Ord)]
233 /// A text resource record, containing arbitrary text data
234 pub struct Txt {
235         /// The name this record is at.
236         pub name: Name,
237         /// The text record itself.
238         ///
239         /// While this is generally UTF-8-valid, there is no specific requirement that it be, and thus
240         /// is an arbitrary series of bytes here.
241         pub data: Vec<u8>,
242 }
243 /// The wire type for TXT records
244 pub const TXT_TYPE: u16 = 16;
245 impl PartialOrd for Txt {
246         fn partial_cmp(&self, o: &Txt) -> Option<Ordering> {
247                 Some(self.name.cmp(&o.name)
248                         .then_with(|| {
249                                 // Compare in wire encoding form, i.e. compare in 255-byte chunks
250                                 for i in 1..(self.data.len() / 255) + 2 {
251                                         let start = (i - 1)*255;
252                                         let self_len = cmp::min(i * 255, self.data.len());
253                                         let o_len = cmp::min(i * 255, o.data.len());
254                                         let slice_cmp = self_len.cmp(&o_len)
255                                                 .then_with(|| self.data[start..self_len].cmp(&o.data[start..o_len]));
256                                         if !slice_cmp.is_eq() { return slice_cmp; }
257                                 }
258                                 Ordering::Equal
259                         }))
260         }
261 }
262 impl StaticRecord for Txt {
263         const TYPE: u16 = TXT_TYPE;
264         fn name(&self) -> &Name { &self.name }
265         fn json(&self) -> String {
266                 if let Ok(s) = core::str::from_utf8(&self.data) {
267                         if s.chars().all(|c| !c.is_control() && c != '"' && c != '\\') {
268                                 return format!("{{\"type\":\"txt\",\"name\":\"{}\",\"contents\":\"{}\"}}", self.name.0, s);
269                         }
270                 }
271                 format!("{{\"type\":\"txt\",\"name\":\"{}\",\"contents\":{:?}}}", self.name.0, &self.data[..])
272         }
273         fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
274                 let mut parsed_data = Vec::with_capacity(data.len().saturating_sub(1));
275                 while !data.is_empty() {
276                         let len = read_u8(&mut data)? as usize;
277                         if data.len() < len { return Err(()); }
278                         parsed_data.extend_from_slice(&data[..len]);
279                         data = &data[len..];
280                 }
281                 debug_assert!(data.is_empty());
282                 Ok(Txt { name, data: parsed_data })
283         }
284         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
285                 let len = (self.data.len() + (self.data.len() + 254) / 255) as u16;
286                 out.extend_from_slice(&len.to_be_bytes());
287
288                 let mut data_write = &self.data[..];
289                 out.extend_from_slice(&[data_write.len().try_into().unwrap_or(255)]);
290                 while !data_write.is_empty() {
291                         let split_pos = core::cmp::min(255, data_write.len());
292                         out.extend_from_slice(&data_write[..split_pos]);
293                         data_write = &data_write[split_pos..];
294                         if !data_write.is_empty() {
295                                 out.extend_from_slice(&[data_write.len().try_into().unwrap_or(255)]);
296                         }
297                 }
298         }
299 }
300
301 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
302 /// A TLS Certificate Association resource record containing information about the TLS certificate
303 /// which should be expected when communicating with the host at the given name.
304 ///
305 /// See <https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities#TLSA_RR> for more
306 /// info.
307 pub struct TLSA {
308         /// The name this record is at.
309         pub name: Name,
310         /// The type of constraint on the TLS certificate(s) used which should be enforced by this
311         /// record.
312         pub cert_usage: u8,
313         /// Whether to match on the full certificate, or only the public key.
314         pub selector: u8,
315         /// The type of data included which is used to match the TLS certificate(s).
316         pub data_ty: u8,
317         /// The certificate data or hash of the certificate data itself.
318         pub data: Vec<u8>,
319 }
320 /// The wire type for TLSA records
321 pub const TLSA_TYPE: u16 = 52;
322 impl StaticRecord for TLSA {
323         const TYPE: u16 = TLSA_TYPE;
324         fn name(&self) -> &Name { &self.name }
325         fn json(&self) -> String {
326                 let mut out = String::with_capacity(128+self.data.len()*2);
327                 write!(&mut out,
328                         "{{\"type\":\"tlsa\",\"name\":\"{}\",\"usage\":{},\"selector\":{},\"data_ty\":{},\"data\":\"",
329                         self.name.0, self.cert_usage, self.selector, self.data_ty
330                 ).expect("Write to a String shouldn't fail");
331                 for c in self.data.iter() {
332                         write!(&mut out, "{:02X}", c)
333                                 .expect("Write to a String shouldn't fail");
334                 }
335                 out += "\"}";
336                 out
337         }
338         fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
339                 Ok(TLSA {
340                         name, cert_usage: read_u8(&mut data)?, selector: read_u8(&mut data)?,
341                         data_ty: read_u8(&mut data)?, data: data.to_vec(),
342                 })
343         }
344         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
345                 let len = 3 + self.data.len();
346                 out.extend_from_slice(&(len as u16).to_be_bytes());
347                 out.extend_from_slice(&[self.cert_usage, self.selector, self.data_ty]);
348                 out.extend_from_slice(&self.data);
349         }
350 }
351
352 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
353 /// A Canonical Name resource record, referring all queries for this name to another name.
354 pub struct CName {
355         /// The name this record is at.
356         pub name: Name,
357         /// The canonical name.
358         ///
359         /// A resolver should use this name when looking up any further records for [`self.name`].
360         pub canonical_name: Name,
361 }
362 impl StaticRecord for CName {
363         const TYPE: u16 = 5;
364         fn name(&self) -> &Name { &self.name }
365         fn json(&self) -> String {
366                 format!("{{\"type\":\"cname\",\"name\":\"{}\",\"canonical_name\":\"{}\"}}",
367                         self.name.0, self.canonical_name.0)
368         }
369         fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
370                 let res = CName { name, canonical_name: read_wire_packet_name(&mut data, wire_packet)? };
371                 debug_assert!(data.is_empty());
372                 Ok(res)
373         }
374         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
375                 let len: u16 = name_len(&self.canonical_name);
376                 out.extend_from_slice(&len.to_be_bytes());
377                 write_name(out, &self.canonical_name);
378         }
379 }
380
381 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
382 /// A Delegation Name resource record, referring all queries for subdomains of this name to another
383 /// subtree of the DNS.
384 pub struct DName {
385         /// The name this record is at.
386         pub name: Name,
387         /// The delegation name.
388         ///
389         /// A resolver should use this domain name tree when looking up any further records for
390         /// subdomains of [`self.name`].
391         pub delegation_name: Name,
392 }
393 impl StaticRecord for DName {
394         const TYPE: u16 = 39;
395         fn name(&self) -> &Name { &self.name }
396         fn json(&self) -> String {
397                 format!("{{\"type\":\"dname\",\"name\":\"{}\",\"delegation_name\":\"{}\"}}",
398                         self.name.0, self.delegation_name.0)
399         }
400         fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
401                 let res = DName { name, delegation_name: read_wire_packet_name(&mut data, wire_packet)? };
402                 debug_assert!(data.is_empty());
403                 Ok(res)
404         }
405         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
406                 let len: u16 = name_len(&self.delegation_name);
407                 out.extend_from_slice(&len.to_be_bytes());
408                 write_name(out, &self.delegation_name);
409         }
410 }
411
412
413 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
414 /// A public key resource record which can be used to validate [`RRSig`]s.
415 pub struct DnsKey {
416         /// The name this record is at.
417         pub name: Name,
418         /// Flags which constrain the usage of this public key.
419         pub flags: u16,
420         /// The protocol this key is used for (protocol `3` is DNSSEC). 
421         pub protocol: u8,
422         /// The algorithm which this public key uses to sign data.
423         pub alg: u8,
424         /// The public key itself.
425         pub pubkey: Vec<u8>,
426 }
427 impl StaticRecord for DnsKey {
428         const TYPE: u16 = 48;
429         fn name(&self) -> &Name { &self.name }
430         fn json(&self) -> String {
431                 let mut out = String::with_capacity(128+self.pubkey.len()*2);
432                 write!(&mut out,
433                         "{{\"type\":\"dnskey\",\"name\":\"{}\",\"flags\":{},\"protocol\":{},\"alg\":{},\"pubkey\":\"",
434                         self.name.0, self.flags, self.protocol, self.alg
435                 ).expect("Write to a String shouldn't fail");
436                 for c in self.pubkey.iter() {
437                         write!(&mut out, "{:02X}", c)
438                                 .expect("Write to a String shouldn't fail");
439                 }
440                 out += "\"}";
441                 out
442         }
443         fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
444                 Ok(DnsKey {
445                         name, flags: read_u16(&mut data)?, protocol: read_u8(&mut data)?,
446                         alg: read_u8(&mut data)?, pubkey: data.to_vec(),
447                 })
448         }
449         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
450                 let len = 2 + 1 + 1 + self.pubkey.len();
451                 out.extend_from_slice(&(len as u16).to_be_bytes());
452                 out.extend_from_slice(&self.flags.to_be_bytes());
453                 out.extend_from_slice(&self.protocol.to_be_bytes());
454                 out.extend_from_slice(&self.alg.to_be_bytes());
455                 out.extend_from_slice(&self.pubkey);
456         }
457 }
458 impl DnsKey {
459         /// A short (non-cryptographic) digest which can be used to refer to this [`DnsKey`].
460         pub fn key_tag(&self) -> u16 {
461                 let mut res = u32::from(self.flags);
462                 res += u32::from(self.protocol) << 8;
463                 res += u32::from(self.alg);
464                 for (idx, b) in self.pubkey.iter().enumerate() {
465                         if idx % 2 == 0 {
466                                 res += u32::from(*b) << 8;
467                         } else {
468                                 res += u32::from(*b);
469                         }
470                 }
471                 res += (res >> 16) & 0xffff;
472                 (res & 0xffff) as u16
473         }
474 }
475
476 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
477 /// A Delegation Signer resource record which indicates that some alternative [`DnsKey`] can sign
478 /// for records in the zone which matches [`self.name`].
479 pub struct DS {
480         /// The name this record is at.
481         ///
482         /// This is also the zone that a [`DnsKey`] which matches the [`Self::digest`] can sign for.
483         pub name: Name,
484         /// A short tag which describes the matching [`DnsKey`].
485         ///
486         /// This matches the [`DnsKey::key_tag`] for the [`DnsKey`] which is referred to by this
487         /// [`DS`].
488         pub key_tag: u16,
489         /// The algorithm which the [`DnsKey`] referred to by this [`DS`] uses.
490         ///
491         /// This matches the [`DnsKey::alg`] field in the referred-to [`DnsKey`].
492         pub alg: u8,
493         /// The type of digest used to hash the referred-to [`DnsKey`].
494         pub digest_type: u8,
495         /// The digest itself.
496         pub digest: Vec<u8>,
497 }
498 impl StaticRecord for DS {
499         const TYPE: u16 = 43;
500         fn name(&self) -> &Name { &self.name }
501         fn json(&self) -> String {
502                 let mut out = String::with_capacity(128+self.digest.len()*2);
503                 write!(&mut out,
504                         "{{\"type\":\"ds\",\"name\":\"{}\",\"key_tag\":{},\"alg\":{},\"digest_type\":{},\"digest\":\"",
505                         self.name.0, self.key_tag, self.alg, self.digest_type
506                 ).expect("Write to a String shouldn't fail");
507                 for c in self.digest.iter() {
508                         write!(&mut out, "{:02X}", c)
509                                 .expect("Write to a String shouldn't fail");
510                 }
511                 out += "\"}";
512                 out
513         }
514         fn read_from_data(name: Name, mut data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
515                 Ok(DS {
516                         name, key_tag: read_u16(&mut data)?, alg: read_u8(&mut data)?,
517                         digest_type: read_u8(&mut data)?, digest: data.to_vec(),
518                 })
519         }
520         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
521                 let len = 2 + 1 + 1 + self.digest.len();
522                 out.extend_from_slice(&(len as u16).to_be_bytes());
523                 out.extend_from_slice(&self.key_tag.to_be_bytes());
524                 out.extend_from_slice(&self.alg.to_be_bytes());
525                 out.extend_from_slice(&self.digest_type.to_be_bytes());
526                 out.extend_from_slice(&self.digest);
527         }
528 }
529
530 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
531 /// A Resource Record (set) Signature resource record. This contains a signature over all the
532 /// resources records of the given type at the given name.
533 pub struct RRSig {
534         /// The name this record is at.
535         ///
536         /// This is also the name of any records which this signature is covering (ignoring wildcards).
537         pub name: Name,
538         /// The resource record type which this [`RRSig`] is signing.
539         ///
540         /// All resources records of this type at the same name as [`self.name`] must be signed by
541         /// this [`RRSig`].
542         pub ty: u16,
543         /// The algorithm which is being used to sign.
544         ///
545         /// This must match the [`DnsKey::alg`] field in the [`DnsKey`] being used to sign.
546         pub alg: u8,
547         /// The number of labels in the name of the records that this signature is signing.
548         ///
549         /// If this is less than the number of labels in [`self.name`], this signature is covering a
550         /// wildcard entry.
551         pub labels: u8,
552         /// The TTL of the records which this [`RRSig`] is signing.
553         pub orig_ttl: u32,
554         /// The expiration (as a UNIX timestamp) of this signature.
555         pub expiration: u32,
556         /// The time (as a UNIX timestamp) at which this signature becomes valid.
557         pub inception: u32,
558         /// A short tag which describes the matching [`DnsKey`].
559         ///
560         /// This matches the [`DnsKey::key_tag`] for the [`DnsKey`] which created this signature.
561         pub key_tag: u16,
562         /// The [`DnsKey::name`] in the [`DnsKey`] which created this signature.
563         ///
564         /// This must be a parent of [`self.name`].
565         ///
566         /// [`DnsKey::name`]: Record::name
567         // We'd like to just link to the `DnsKey` member variable called `name`, but there doesn't
568         // appear to be a way to actually do that, so instead we have to link to the trait method.
569         pub key_name: Name,
570         /// The signature itself.
571         pub signature: Vec<u8>,
572 }
573 impl StaticRecord for RRSig {
574         const TYPE: u16 = 46;
575         fn name(&self) -> &Name { &self.name }
576         fn json(&self) -> String {
577                 let mut out = String::with_capacity(256 + self.signature.len()*2);
578                 write!(&mut out,
579                         "{{\"type\":\"ds\",\"name\":\"{}\",\"signed_record_type\":{},\"alg\":{},\"signed_labels\":{},\"orig_ttl\":{},\"expiration\"{},\"inception\":{},\"key_tag\":{},\"key_name\":\"{}\",\"signature\":\"",
580                         self.name.0, self.ty, self.alg, self.labels, self.orig_ttl, self.expiration, self.inception, self.key_tag, self.key_name.0
581                 ).expect("Write to a String shouldn't fail");
582                 for c in self.signature.iter() {
583                         write!(&mut out, "{:02X}", c)
584                                 .expect("Write to a String shouldn't fail");
585                 }
586                 out += "\"}";
587                 out
588         }
589         fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
590                 Ok(RRSig {
591                         name, ty: read_u16(&mut data)?, alg: read_u8(&mut data)?,
592                         labels: read_u8(&mut data)?, orig_ttl: read_u32(&mut data)?,
593                         expiration: read_u32(&mut data)?, inception: read_u32(&mut data)?,
594                         key_tag: read_u16(&mut data)?,
595                         key_name: read_wire_packet_name(&mut data, wire_packet)?,
596                         signature: data.to_vec(),
597                 })
598         }
599         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
600                 let len = 2 + 1 + 1 + 4*3 + 2 + name_len(&self.key_name) + self.signature.len() as u16;
601                 out.extend_from_slice(&len.to_be_bytes());
602                 out.extend_from_slice(&self.ty.to_be_bytes());
603                 out.extend_from_slice(&self.alg.to_be_bytes());
604                 out.extend_from_slice(&self.labels.to_be_bytes());
605                 out.extend_from_slice(&self.orig_ttl.to_be_bytes());
606                 out.extend_from_slice(&self.expiration.to_be_bytes());
607                 out.extend_from_slice(&self.inception.to_be_bytes());
608                 out.extend_from_slice(&self.key_tag.to_be_bytes());
609                 write_name(out, &self.key_name);
610                 out.extend_from_slice(&self.signature);
611         }
612 }
613
614 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
615 /// An IPv4 Address resource record
616 pub struct A {
617         /// The name this record is at.
618         pub name: Name,
619         /// The bytes of the IPv4 address.
620         pub address: [u8; 4],
621 }
622 /// The wire type for A records
623 pub const A_TYPE: u16 = 1;
624 impl StaticRecord for A {
625         const TYPE: u16 = A_TYPE;
626         fn name(&self) -> &Name { &self.name }
627         fn json(&self) -> String {
628                 format!("{{\"type\":\"a\",\"name\":\"{}\",\"address\":{:?}}}", self.name.0, self.address)
629         }
630         fn read_from_data(name: Name, data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
631                 if data.len() != 4 { return Err(()); }
632                 let mut address = [0; 4];
633                 address.copy_from_slice(&data);
634                 Ok(A { name, address })
635         }
636         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
637                 out.extend_from_slice(&4u16.to_be_bytes());
638                 out.extend_from_slice(&self.address);
639         }
640 }
641
642 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
643 /// An IPv6 Address resource record
644 pub struct AAAA {
645         /// The name this record is at.
646         pub name: Name,
647         /// The bytes of the IPv6 address.
648         pub address: [u8; 16],
649 }
650 /// The wire type for AAAA records
651 pub const AAAA_TYPE: u16 = 28;
652 impl StaticRecord for AAAA {
653         const TYPE: u16 = AAAA_TYPE;
654         fn name(&self) -> &Name { &self.name }
655         fn json(&self) -> String {
656                 format!("{{\"type\":\"aaaa\",\"name\":\"{}\",\"address\":{:?}}}", self.name.0, self.address)
657         }
658         fn read_from_data(name: Name, data: &[u8], _wire_packet: &[u8]) -> Result<Self, ()> {
659                 if data.len() != 16 { return Err(()); }
660                 let mut address = [0; 16];
661                 address.copy_from_slice(&data);
662                 Ok(AAAA { name, address })
663         }
664         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
665                 out.extend_from_slice(&16u16.to_be_bytes());
666                 out.extend_from_slice(&self.address);
667         }
668 }
669
670 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
671 /// A Name Server resource record, which indicates the server responsible for handling queries for
672 /// a zone.
673 pub struct NS {
674         /// The name this record is at.
675         ///
676         /// This is also the zone which the server at [`Self::name_server`] is responsible for handling
677         /// queries for.
678         pub name: Name,
679         /// The name of the server which is responsible for handling queries for the [`self.name`]
680         /// zone.
681         pub name_server: Name,
682 }
683 impl StaticRecord for NS {
684         const TYPE: u16 = 2;
685         fn name(&self) -> &Name { &self.name }
686         fn json(&self) -> String {
687                 format!("{{\"type\":\"ns\",\"name\":\"{}\",\"ns\":\"{}\"}}", self.name.0, self.name_server.0)
688         }
689         fn read_from_data(name: Name, mut data: &[u8], wire_packet: &[u8]) -> Result<Self, ()> {
690                 let res = NS { name, name_server: read_wire_packet_name(&mut data, wire_packet)? };
691                 debug_assert!(data.is_empty());
692                 Ok(res)
693         }
694         fn write_u16_len_prefixed_data(&self, out: &mut Vec<u8>) {
695                 out.extend_from_slice(&name_len(&self.name_server).to_be_bytes());
696                 write_name(out, &self.name_server);
697         }
698 }