domain/base/iana/rcode.rs
1//! DNS response codes and extended response codes.
2//!
3//! The original DNS specification in [RFC 1035] specified four bits of the
4//! message header as response code. The type [`Rcode`] defined herein
5//! represents these codes. Later, [RFC 2671][] (now [RFC 6891]) added eight
6//! bits to the response code to be transmitted as part of the OPT
7//! pseudo-resource record. To make matters even worse, the TSIG and TKEY
8//! records defined by [RFC 2845] and [RFC 2930] use a 16 bit error code.
9//! All of these codes share the same definition space. Even so, we have
10//! separate types for each of these.
11//!
12//! [RFC 1035]: https://tools.ietf.org/html/rfc1035
13//! [RFC 2671]: https://tools.ietf.org/html/rfc2671
14//! [RFC 2845]: https://tools.ietf.org/html/rfc2845
15//! [RFC 2930]: https://tools.ietf.org/html/rfc2930
16//! [RFC 6891]: https://tools.ietf.org/html/rfc6891
17
18// Note: Rcode and OptRcode don’t use the macros since they don’t use all the
19// bits of the wrapped integer.
20
21use core::fmt;
22use core::str::FromStr;
23
24//------------ Rcode ---------------------------------------------------------
25
26/// DNS Response Codes.
27///
28/// The response code of a response indicates what happend on the server
29/// when trying to answer the query. The code is a 4 bit value and part of
30/// the header of a DNS message.
31///
32/// This response was defined as part of [RFC 1035]. Later, [RFC 2671]
33/// defined an extended response code of 12 bits using the lower four bits
34/// from the header and eight additional bits stored in the OPT
35/// pseudo-record. The type [OptRcode] represents this extended response
36/// code. A third response code, now 16 bit wide, was defined for the
37/// transaction authentication mechansim (TSIG) in [RFC 2845] and is
38/// represented by [TsigRcode].
39///
40/// All three codes share the same name space. Their values are defined in
41/// one registry, [IANA DNS RCODEs]. This type is complete as of 2019-01-28.
42///
43/// [IANA DNS RCODEs]: http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
44/// [RFC 1035]: https://tools.ietf.org/html/rfc1035
45/// [RFC 2671]: https://tools.ietf.org/html/rfc2671
46#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
47pub struct Rcode(u8);
48
49impl Rcode {
50 /// No error condition.
51 ///
52 /// (Otherwise known as success.)
53 ///
54 /// Defined in [RFC 1035].
55 ///
56 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
57 pub const NOERROR: Self = Self(0);
58
59 /// Format error.
60 ///
61 /// The name server was unable to interpret the query.
62 ///
63 /// Defined in [RFC 1035].
64 ///
65 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
66 pub const FORMERR: Self = Self(1);
67
68 /// Server failure.
69 ///
70 /// The name server was unable to process this query due to a problem
71 /// with the name server.
72 ///
73 /// Defined in [RFC 1035].
74 ///
75 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
76 pub const SERVFAIL: Self = Self(2);
77
78 /// Name error.
79 ///
80 /// The domain name given in the query does not exist at the name server.
81 ///
82 /// Defined in [RFC 1035].
83 ///
84 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
85 pub const NXDOMAIN: Self = Self(3);
86
87 /// Not implemented.
88 ///
89 /// The name server does not support the requested kind of query.
90 ///
91 /// Defined in [RFC 1035].
92 ///
93 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
94 pub const NOTIMP: Self = Self(4);
95
96 /// Query refused.
97 ///
98 /// The name server refused to perform the operation requested by the
99 /// query for policy reasons.
100 ///
101 /// Defined in [RFC 1035].
102 ///
103 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
104 pub const REFUSED: Self = Self(5);
105
106 /// Name exists when it should not.
107 ///
108 /// Returned for an UPDATE query when a domain requested to not exist
109 /// does in fact exist.
110 ///
111 /// Returned when resolving a DNAME redirection when the resulting name
112 /// exceeds the length of 255 octets.
113 ///
114 /// Defined in [RFC 2136] for the UPDATE query and [RFC 6672] for DNAME
115 /// redirection.
116 ///
117 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
118 /// [RFC 6672]: https://tools.ietf.org/html/rfc6672
119 pub const YXDOMAIN: Self = Self(6);
120
121 /// RR set exists when it should not.
122 ///
123 /// Returned for an UPDATE query when an RRset requested to not exist
124 /// does in fact exist.
125 ///
126 /// Defined in [RFC 2136].
127 ///
128 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
129 pub const YXRRSET: Self = Self(7);
130
131 /// RR set that should exist does not.
132 ///
133 /// Returned for an UPDATE query when an RRset requested to exist
134 /// does not.
135 ///
136 /// Defined in [RFC 2136].
137 ///
138 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
139 pub const NXRRSET: Self = Self(8);
140
141 /// Server not authoritative for zone or client not authorized.
142 ///
143 /// Returned for an UPDATE query when the server is not an authoritative
144 /// name server for the requested domain.
145 ///
146 /// Returned for queries using TSIG when authorisation failed.
147 ///
148 /// Defined in [RFC 2136] for UPDATE and [RFC 2845] for TSIG.
149 ///
150 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
151 /// [RFC 2845]: https://tools.ietf.org/html/rfc2845
152 pub const NOTAUTH: Self = Self(9);
153
154 /// Name not contained in zone.
155 ///
156 /// A name used in the prerequisite or update section is not within the
157 /// zone given in the zone section.
158 ///
159 /// Defined in [RFC 2136].
160 ///
161 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
162 pub const NOTZONE: Self = Self(10);
163}
164
165impl Rcode {
166 /// Creates an rcode from an integer, returning `None` if invalid.
167 ///
168 /// The rcode is valid if the upper four bits of `value` are all zero.
169 #[must_use]
170 pub const fn checked_from_int(value: u8) -> Option<Self> {
171 if value & 0xF0 != 0 {
172 None
173 } else {
174 Some(Rcode(value))
175 }
176 }
177
178 /// Creates an rcode from an integer, only considering the lower four bits.
179 ///
180 /// This function will ignore the upper four bit of `value`.
181 #[must_use]
182 pub const fn masked_from_int(value: u8) -> Self {
183 Rcode(value & 0x0F)
184 }
185
186 /// Returns the integer value for this rcode.
187 ///
188 /// Only the lower 4 bits of the returned octet are used by the rcode. The
189 /// upper four bits are always zero.
190 #[must_use]
191 pub const fn to_int(self) -> u8 {
192 self.0
193 }
194
195 /// Returns the mnemonic for this value if there is one.
196 #[must_use]
197 pub const fn to_mnemonic(self) -> Option<&'static [u8]> {
198 match self {
199 Rcode::NOERROR => Some(b"NOERROR"),
200 Rcode::FORMERR => Some(b"FORMERR"),
201 Rcode::SERVFAIL => Some(b"SERVFAIL"),
202 Rcode::NXDOMAIN => Some(b"NXDOMAIN"),
203 Rcode::NOTIMP => Some(b"NOTIMP"),
204 Rcode::REFUSED => Some(b"REFUSED"),
205 Rcode::YXDOMAIN => Some(b"YXDOMAIN"),
206 Rcode::YXRRSET => Some(b"YXRRSET"),
207 Rcode::NXRRSET => Some(b"NXRRSET"),
208 Rcode::NOTAUTH => Some(b"NOTAUTH"),
209 Rcode::NOTZONE => Some(b"NOTZONE"),
210 _ => None,
211 }
212 }
213}
214
215//--- FromStr
216
217impl FromStr for Rcode {
218 type Err = ();
219
220 fn from_str(s: &str) -> Result<Self, Self::Err> {
221 match s {
222 "NOERROR" => Ok(Rcode::NOERROR),
223 "FORMERR" => Ok(Rcode::FORMERR),
224 "SERVFAIL" => Ok(Rcode::SERVFAIL),
225 "NXDOMAIN" => Ok(Rcode::NXDOMAIN),
226 "NOTIMP" => Ok(Rcode::NOTIMP),
227 "REFUSED" => Ok(Rcode::REFUSED),
228 "YXDOMAIN" => Ok(Rcode::YXDOMAIN),
229 "YXRRSET" => Ok(Rcode::YXRRSET),
230 "NXRRSET" => Ok(Rcode::NXRRSET),
231 "NOTAUTH" => Ok(Rcode::NOTAUTH),
232 "NOTZONE" => Ok(Rcode::NOTZONE),
233 _ => Err(()),
234 }
235 }
236}
237
238//--- TryFrom and From
239
240impl TryFrom<u8> for Rcode {
241 type Error = InvalidRcode;
242
243 fn try_from(value: u8) -> Result<Self, Self::Error> {
244 Rcode::checked_from_int(value).ok_or(InvalidRcode(()))
245 }
246}
247
248impl From<Rcode> for u8 {
249 fn from(value: Rcode) -> u8 {
250 value.to_int()
251 }
252}
253
254//--- Display and Debug
255
256impl fmt::Display for Rcode {
257 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
258 match self
259 .to_mnemonic()
260 .and_then(|bytes| core::str::from_utf8(bytes).ok())
261 {
262 Some(mnemonic) => f.write_str(mnemonic),
263 None => self.0.fmt(f),
264 }
265 }
266}
267
268impl fmt::Debug for Rcode {
269 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
270 match self
271 .to_mnemonic()
272 .and_then(|bytes| core::str::from_utf8(bytes).ok())
273 {
274 Some(mnemonic) => write!(f, "Rcode::{}", mnemonic),
275 None => f.debug_tuple("Rcode").field(&self.0).finish(),
276 }
277 }
278}
279
280//--- Serialize and Deserialize
281
282#[cfg(feature = "serde")]
283impl serde::Serialize for Rcode {
284 fn serialize<S: serde::Serializer>(
285 &self,
286 serializer: S,
287 ) -> Result<S::Ok, S::Error> {
288 self.to_int().serialize(serializer)
289 }
290}
291
292#[cfg(feature = "serde")]
293impl<'de> serde::Deserialize<'de> for Rcode {
294 fn deserialize<D: serde::Deserializer<'de>>(
295 deserializer: D,
296 ) -> Result<Self, D::Error> {
297 u8::deserialize(deserializer).and_then(|code| {
298 Rcode::try_from(code).map_err(serde::de::Error::custom)
299 })
300 }
301}
302
303//------------ OptRcode -----------------------------------------------------
304
305/// Extended DNS Response Codes for OPT records.
306///
307/// Originally, the response code embedded in the header of each DNS
308/// message was four bits long. This code, defined in [RFC 1035], is
309/// represented by the [Rcode] type. The extension mechanism for DNS
310/// initially defined in [RFC 2671] and updated by [RFC 6891] added eight
311/// more bits to be stored in the OPT pseudo-resource record. This type
312/// represents the complete 12 bit extended response code.
313///
314/// There is a third, 16 bit wide response code for transaction
315/// authentication (TSIG) defined in [RFC 2845] and represented by the
316/// [`TsigRcode`] type. The code mostly shares the same name space except
317/// for an unfortunate collision in between the BADVERS and BADSIG values.
318/// Because of this, we decided to have separate types.
319///
320/// The values for all three response code types are defined in
321/// the [IANA DNS RCODEs] registry. This type is complete as of 2019-01-28.
322///
323/// The 12-bit extended RCODE defined by [RFC 6891] stores the lowest 4-bits
324/// of the extended RCODE in the main DNS header RCODE field and stores the
325/// remaining 8-bits (right shifted by 4-bits) in the OPT record header RCODE
326/// field, like so:
327///
328/// ```text
329/// NoError: 0 = 0b0000_0000_0000
330/// ^^^^ Stored in DNS header RCODE field
331/// ^^^^_^^^^ Stored in OPT header RCODE field
332///
333/// FormErr: 1 = 0b0000_0000_0001
334/// ^^^^ Stored in DNS header RCODE field
335/// ^^^^_^^^^ Stored in OPT header RCODE field
336///
337/// BadVers: 16 = 0b0000_0001_0000
338/// ^^^^ Stored in DNS header RCODE field
339/// ^^^^_^^^^ Stored in OPT header RCODE field
340///
341/// BadCookie: 23 = 0b0000_0001_0111
342/// ^^^^ Stored in DNS header RCODE field
343/// ^^^^_^^^^ Stored in OPT header RCODE field
344/// ```
345///
346/// This type offers several functions to ease working with the separate parts
347/// and the combined value of an extended RCODE:
348///
349/// - [`OptRcode::rcode`]: the RFC 1035 header RCODE part.
350/// - [`OptRcode::ext`]`: the RFC 6891 ENDS OPT extended RCODE part.
351/// - [`OptRcode::to_parts`]`: to access both parts at once.
352/// - [`OptRcode::to_int`]`: the IANA number for the RCODE combining both
353/// parts.
354///
355/// [IANA DNS RCODEs]: http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
356/// [RFC 2671]: https://tools.ietf.org/html/rfc2671
357/// [RFC 2845]: https://tools.ietf.org/html/rfc2845
358/// [RFC 2930]: https://tools.ietf.org/html/rfc2930
359/// [RFC 6891]: https://tools.ietf.org/html/rfc6891
360#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
361pub struct OptRcode(u16);
362
363impl OptRcode {
364 /// No error condition.
365 ///
366 /// (Otherwise known as success.)
367 ///
368 /// Defined in [RFC 1035].
369 ///
370 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
371 pub const NOERROR: Self = Self::from_rcode(Rcode::NOERROR);
372
373 /// Format error.
374 ///
375 /// The name server was unable to interpret the query.
376 ///
377 /// Defined in [RFC 1035].
378 ///
379 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
380 pub const FORMERR: Self = Self::from_rcode(Rcode::FORMERR);
381
382 /// Server failure.
383 ///
384 /// The name server was unable to process this query due to a problem
385 /// with the name server.
386 ///
387 /// Defined in [RFC 1035].
388 ///
389 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
390 pub const SERVFAIL: Self = Self::from_rcode(Rcode::SERVFAIL);
391
392 /// Name error.
393 ///
394 /// The domain name given in the query does not exist at the name server.
395 ///
396 /// Defined in [RFC 1035].
397 ///
398 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
399 pub const NXDOMAIN: Self = Self::from_rcode(Rcode::NXDOMAIN);
400
401 /// Not implemented.
402 ///
403 /// The name server does not support the requested kind of query.
404 ///
405 /// Defined in [RFC 1035].
406 ///
407 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
408 pub const NOTIMP: Self = Self::from_rcode(Rcode::NOTIMP);
409
410 /// Query refused.
411 ///
412 /// The name server refused to perform the operation requested by the
413 /// query for policy reasons.
414 ///
415 /// Defined in [RFC 1035].
416 ///
417 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
418 pub const REFUSED: Self = Self::from_rcode(Rcode::REFUSED);
419
420 /// Name exists when it should not.
421 ///
422 /// Returned for an UPDATE query when a domain requested to not exist
423 /// does in fact exist.
424 ///
425 /// Returned when resolving a DNAME redirection when the resulting name
426 /// exceeds the length of 255 octets.
427 ///
428 /// Defined in [RFC 2136] for the UPDATE query and [RFC 6672] for DNAME
429 /// redirection.
430 ///
431 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
432 /// [RFC 6672]: https://tools.ietf.org/html/rfc6672
433 pub const YXDOMAIN: Self = Self::from_rcode(Rcode::YXDOMAIN);
434
435 /// RR set exists when it should not.
436 ///
437 /// Returned for an UPDATE query when an RRset requested to not exist
438 /// does in fact exist.
439 ///
440 /// Defined in [RFC 2136].
441 ///
442 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
443 pub const YXRRSET: Self = Self::from_rcode(Rcode::YXRRSET);
444
445 /// RR set that should exist does not.
446 ///
447 /// Returned for an UPDATE query when an RRset requested to exist
448 /// does not.
449 ///
450 /// Defined in [RFC 2136].
451 ///
452 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
453 pub const NXRRSET: Self = Self::from_rcode(Rcode::NXRRSET);
454
455 /// Server not authoritative for zone or client not authorized.
456 ///
457 /// Returned for an UPDATE query when the server is not an authoritative
458 /// name server for the requested domain.
459 ///
460 /// Returned for queries using TSIG when authorisation failed.
461 ///
462 /// Defined in [RFC 2136] for UPDATE and [RFC 2845] for TSIG.
463 ///
464 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
465 /// [RFC 2845]: https://tools.ietf.org/html/rfc2845
466 pub const NOTAUTH: Self = Self::from_rcode(Rcode::NOTAUTH);
467
468 /// Name not contained in zone.
469 ///
470 /// A name used in the prerequisite or update section is not within the
471 /// zone given in the zone section.
472 ///
473 /// Defined in [RFC 2136].
474 ///
475 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
476 pub const NOTZONE: Self = Self::from_rcode(Rcode::NOTZONE);
477
478 /// Bad OPT version.
479 ///
480 /// A name server does not implement the EDNS version requested in the
481 /// OPT record.
482 ///
483 /// Defined in [RFC 6891].
484 ///
485 /// [RFC 6891]: https://tools.ietf.org/html/rfc6891
486 pub const BADVERS: Self = Self(16);
487
488 // XXX We will not define the values from the TSIG and TKEY RFCs,
489 // unless they are used in OPT records, too?
490 /// Bad or missing server cookie.
491 ///
492 /// The request contained a COOKIE option either without a server cookie
493 /// or with a server cookie that did not validate.
494 ///
495 /// Defined in [RFC 7873].
496 ///
497 /// [RFC 7873]: https://tools.ietf.org/html/rfc7873
498 pub const BADCOOKIE: Self = Self(23);
499}
500
501impl OptRcode {
502 /// Creates an rcode from an integer, returning `None` if invalid.
503 ///
504 /// The rcode is valid if the upper four bits of `value` are all zero.
505 #[must_use]
506 pub const fn checked_from_int(value: u16) -> Option<OptRcode> {
507 if value & 0x0FFF != 0 {
508 None
509 } else {
510 Some(Self(value))
511 }
512 }
513
514 /// Creates an rcode from an integer, only considering the lower four bits.
515 ///
516 /// This function will ignore the upper four bit of `value`.
517 #[must_use]
518 pub const fn masked_from_int(value: u16) -> OptRcode {
519 Self(value & 0x0FFF)
520 }
521
522 /// Creates an OPT rcode from a plain rcode.
523 #[must_use]
524 pub const fn from_rcode(rcode: Rcode) -> Self {
525 Self(rcode.0 as u16)
526 }
527
528 /// Returns the integer value for this rcode.
529 ///
530 /// Only the lower 12 bits of the returned octet are used by the rcode.
531 /// The upper four bits are always zero.
532 #[must_use]
533 pub const fn to_int(self) -> u16 {
534 self.0
535 }
536
537 /// Creates an extended rcode value from its parts.
538 #[must_use]
539 pub fn from_parts(rcode: Rcode, ext: u8) -> OptRcode {
540 OptRcode((u16::from(ext) << 4) | u16::from(rcode.to_int()))
541 }
542
543 /// Returns the two parts of an extended rcode value.
544 #[must_use]
545 pub fn to_parts(self) -> (Rcode, u8) {
546 (Rcode::masked_from_int(self.0 as u8), (self.0 >> 4) as u8)
547 }
548
549 /// Returns the rcode part of the extended rcode.
550 #[must_use]
551 pub fn rcode(self) -> Rcode {
552 self.to_parts().0
553 }
554
555 /// Returns the extended octet of the extended rcode.
556 #[must_use]
557 pub fn ext(self) -> u8 {
558 self.to_parts().1
559 }
560
561 /// Returns true if the RCODE is extended, false otherwise.
562 #[must_use]
563 pub fn is_ext(&self) -> bool {
564 // https://datatracker.ietf.org/doc/html/rfc6891#section-6.1.3
565 // 6.1.3. OPT Record TTL Field Use
566 // ...
567 // "EXTENDED-RCODE
568 // Forms the upper 8 bits of extended 12-bit RCODE (together
569 // with the 4 bits defined in [RFC1035]. Note that
570 // EXTENDED-RCODE value 0 indicates that an unextended RCODE is
571 // in use (values 0 through 15)."
572 self.0 >> 4 != 0
573 }
574
575 /// Returns the mnemonic for this value if there is one.
576 #[must_use]
577 pub const fn to_mnemonic(self) -> Option<&'static [u8]> {
578 match self {
579 OptRcode::NOERROR => Some(b"NOERROR"),
580 OptRcode::FORMERR => Some(b"FORMERR"),
581 OptRcode::SERVFAIL => Some(b"SERVFAIL"),
582 OptRcode::NXDOMAIN => Some(b"NXDOMAIN"),
583 OptRcode::NOTIMP => Some(b"NOTIMP"),
584 OptRcode::REFUSED => Some(b"REFUSED"),
585 OptRcode::YXDOMAIN => Some(b"YXDOMAIN"),
586 OptRcode::YXRRSET => Some(b"YXRRSET"),
587 OptRcode::NXRRSET => Some(b"NXRRSET"),
588 OptRcode::NOTAUTH => Some(b"NOTAUTH"),
589 OptRcode::NOTZONE => Some(b"NOTZONE"),
590 OptRcode::BADVERS => Some(b"BADVERS"),
591 OptRcode::BADCOOKIE => Some(b"BADCOOKIE"),
592 _ => None,
593 }
594 }
595}
596
597//--- FromStr
598
599impl FromStr for OptRcode {
600 type Err = ();
601
602 fn from_str(s: &str) -> Result<Self, Self::Err> {
603 match s {
604 "NOERROR" => Ok(OptRcode::NOERROR),
605 "FORMERR" => Ok(OptRcode::FORMERR),
606 "SERVFAIL" => Ok(OptRcode::SERVFAIL),
607 "NXDOMAIN" => Ok(OptRcode::NXDOMAIN),
608 "NOTIMP" => Ok(OptRcode::NOTIMP),
609 "REFUSED" => Ok(OptRcode::REFUSED),
610 "YXDOMAIN" => Ok(OptRcode::YXDOMAIN),
611 "YXRRSET" => Ok(OptRcode::YXRRSET),
612 "NXRRSET" => Ok(OptRcode::NXRRSET),
613 "NOTAUTH" => Ok(OptRcode::NOTAUTH),
614 "NOTZONE" => Ok(OptRcode::NOTZONE),
615 "BADVERS" => Ok(OptRcode::BADVERS),
616 "BADCOOKIE" => Ok(OptRcode::BADCOOKIE),
617 _ => Err(()),
618 }
619 }
620}
621
622//--- TryFrom and From
623
624impl TryFrom<u16> for OptRcode {
625 type Error = InvalidRcode;
626
627 fn try_from(value: u16) -> Result<Self, Self::Error> {
628 OptRcode::checked_from_int(value).ok_or(InvalidRcode(()))
629 }
630}
631
632impl From<OptRcode> for u16 {
633 fn from(value: OptRcode) -> u16 {
634 value.to_int()
635 }
636}
637
638impl From<Rcode> for OptRcode {
639 fn from(value: Rcode) -> OptRcode {
640 OptRcode::from_rcode(value)
641 }
642}
643
644//--- Display and Debug
645
646impl fmt::Display for OptRcode {
647 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
648 match self
649 .to_mnemonic()
650 .and_then(|bytes| core::str::from_utf8(bytes).ok())
651 {
652 Some(mnemonic) => f.write_str(mnemonic),
653 None => self.0.fmt(f),
654 }
655 }
656}
657
658impl fmt::Debug for OptRcode {
659 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
660 match self
661 .to_mnemonic()
662 .and_then(|bytes| core::str::from_utf8(bytes).ok())
663 {
664 Some(mnemonic) => write!(f, "Rcode::{}", mnemonic),
665 None => f.debug_tuple("Rcode").field(&self.0).finish(),
666 }
667 }
668}
669
670//------------ TsigRcode ----------------------------------------------------
671
672int_enum! {
673 /// Response codes for transaction authentication (TSIG).
674 ///
675 /// TSIG and TKEY resource records contain a 16 bit wide error field whose
676 /// values are an extension of the standard DNS [`Rcode`]. While it was
677 /// intended to also share the same space with the extended response codes
678 /// used by EDNS (see [`OptRcode`]), both used the value 16. To allow
679 /// distinguish between the two uses of this value, we have two separate
680 /// types.
681 ///
682 /// The values for all three response code types are defined in
683 /// the [IANA DNS RCODEs] registry. This type is complete as of 2019-01-28.
684 ///
685 /// [`Rcode`]: enum.Rcode.html
686 /// [`OptRcode`]: enum.OptRcode.html
687 /// [IANA DNS RCODEs]: http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6
688 =>
689 TsigRcode, u16;
690
691 /// No error condition.
692 ///
693 /// (Otherwise known as success.)
694 ///
695 /// Defined in [RFC 1035].
696 ///
697 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
698 (NOERROR => 0, "NOERROR")
699
700 /// Format error.
701 ///
702 /// The name server was unable to interpret the query.
703 ///
704 /// Defined in [RFC 1035].
705 ///
706 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
707 (FORMERR => 1, "FORMERR")
708
709 /// Server failure.
710 ///
711 /// The name server was unable to process this query due to a problem
712 /// with the name server.
713 ///
714 /// Defined in [RFC 1035].
715 ///
716 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
717 (SERVFAIL => 2, "SERVFAIL")
718
719 /// Name error.
720 ///
721 /// The domain name given in the query does not exist at the name server.
722 ///
723 /// Defined in [RFC 1035].
724 ///
725 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
726 (NXDOMAIN => 3, "NXDOMAIN")
727
728 /// Not implemented.
729 ///
730 /// The name server does not support the requested kind of query.
731 ///
732 /// Defined in [RFC 1035].
733 ///
734 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
735 (NOTIMP => 4, "NOTIMPL")
736
737 /// Query refused.
738 ///
739 /// The name server refused to perform the operation requested by the
740 /// query for policy reasons.
741 ///
742 /// Defined in [RFC 1035].
743 ///
744 /// [RFC 1035]: https://tools.ietf.org/html/rfc1035
745 (REFUSED => 5, "REFUSED")
746
747 /// Name exists when it should not.
748 ///
749 /// Returned for an UPDATE query when a domain requested to not exist
750 /// does in fact exist.
751 ///
752 /// Returned when resolving a DNAME redirection when the resulting name
753 /// exceeds the length of 255 octets.
754 ///
755 /// Defined in [RFC 2136] for the UPDATE query and [RFC 6672] for DNAME
756 /// redirection.
757 ///
758 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
759 /// [RFC 6672]: https://tools.ietf.org/html/rfc6672
760 (YXDOMAIN => 6, "YXDOMAIN")
761
762 /// RR set exists when it should not.
763 ///
764 /// Returned for an UPDATE query when an RRset requested to not exist
765 /// does in fact exist.
766 ///
767 /// Defined in [RFC 2136].
768 ///
769 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
770 (YXRRSET => 7, "YXRRSET")
771
772 /// RR set that should exist does not.
773 ///
774 /// Returned for an UPDATE query when an RRset requested to exist
775 /// does not.
776 ///
777 /// Defined in [RFC 2136].
778 ///
779 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
780 (NXRRSET => 8, "NXRRSET")
781
782 /// Server not authoritative for zone or client not authorized.
783 ///
784 /// Returned for an UPDATE query when the server is not an authoritative
785 /// name server for the requested domain.
786 ///
787 /// Returned for queries using TSIG when authorisation failed.
788 ///
789 /// Defined in [RFC 2136] for UPDATE and [RFC 2845] for TSIG.
790 ///
791 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
792 /// [RFC 2845]: https://tools.ietf.org/html/rfc2845
793 (NOTAUTH => 9, "NOTAUTH")
794
795 /// Name not contained in zone.
796 ///
797 /// A name used in the prerequisite or update section is not within the
798 /// zone given in the zone section.
799 ///
800 /// Defined in [RFC 2136].
801 ///
802 /// [RFC 2136]: https://tools.ietf.org/html/rfc2136
803 (NOTZONE => 10, "NOTZONE")
804
805 /// TSIG signature failure.
806 ///
807 /// The TSIG signature fails to verify.
808 ///
809 /// Defined in [RFC 2845].
810 ///
811 /// [RFC 2845]: https://tools.ietf.org/html/rfc2845
812 (BADSIG => 16, "BADSIG")
813
814 /// Key not recognized.
815 ///
816 /// The server did not recognize the key used for generating the
817 /// signature.
818 ///
819 /// Defined in [RFC 2845].
820 ///
821 /// [RFC 2845]: https://tools.ietf.org/html/rfc2845
822 (BADKEY => 17, "BADKEY")
823
824 /// Signature out of time window.
825 ///
826 /// The server time was outside the time interval specified by the
827 /// request.
828 ///
829 /// Defined in [RFC 2845].
830 ///
831 /// [RFC 2845]: https://tools.ietf.org/html/rfc2845
832 (BADTIME => 18, "BADTIME")
833
834 /// Bad TKEY mode.
835 ///
836 /// The mode field in a TKEY resource record contained a mode not
837 /// supported by the server.
838 ///
839 /// Defined in [RFC 2930].
840 ///
841 /// [RFC 2930]: https://tools.ietf.org/html/rfc2930
842 (BADMODE => 19, "BADMODE")
843
844 /// Duplicate key name.
845 ///
846 /// In TKEY records, when establishing a new key, the name used already
847 /// exists at the server or when deleting a key, a key of this name does
848 /// not exist.
849 ///
850 /// Defined in [RFC 2930].
851 ///
852 /// [RFC 2930]: https://tools.ietf.org/html/rfc2930
853 (BADNAME => 20, "BADNAME")
854
855 /// Algorithm not supported.
856 ///
857 /// The value is defined in [RFC 2930] but never actually explained.
858 /// Presumably, it will be returned when the algorithm field of a TKEY
859 /// record contains a value not supported by the server.
860 ///
861 /// [RFC 2930]: https://tools.ietf.org/html/rfc2930
862 (BADALG => 21, "BADALG")
863
864 /// Bad truncation.
865 ///
866 /// A TSIG record was received with a MAC too short for the local
867 /// policy in force.
868 ///
869 /// Defined in [RFC 4635].
870 ///
871 /// [RFC 4635]: https://tools.ietf.org/html/rfc4635
872 (BADTRUNC => 22, "BADTRUNC")
873
874 /// Bad or missing server cookie.
875 ///
876 /// The request contained a COOKIE option either without a server cookie
877 /// or with a server cookie that did not validate.
878 ///
879 /// Defined in [RFC 7873].
880 ///
881 /// [RFC 7873]: https://tools.ietf.org/html/rfc7873
882 (BADCOOKIE => 23, "BADCOOKIE")
883}
884
885//--- From
886
887impl From<Rcode> for TsigRcode {
888 fn from(value: Rcode) -> TsigRcode {
889 TsigRcode::from_int(u16::from(value.to_int()))
890 }
891}
892
893impl From<OptRcode> for TsigRcode {
894 fn from(value: OptRcode) -> TsigRcode {
895 TsigRcode::from_int(value.to_int())
896 }
897}
898
899int_enum_str_with_decimal!(TsigRcode, u16, "unknown TSIG error");
900int_enum_zonefile_fmt_with_decimal!(TsigRcode);
901
902//============ Error Types ===================================================
903
904/// An integer couldn’t be converted into an rcode.
905#[derive(Clone, Copy, Debug)]
906pub struct InvalidRcode(());
907
908impl fmt::Display for InvalidRcode {
909 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
910 f.write_str("invalid rcode value")
911 }
912}
913
914#[cfg(feature = "std")]
915impl std::error::Error for InvalidRcode {}
916
917//============ Tests =========================================================
918
919#[cfg(test)]
920mod test {
921 use super::*;
922
923 #[test]
924 fn optrcode_parts() {
925 // Define a macro to test the various functions involved in working
926 // with RFC 6891 extended RCODEs. Given an OPT RCODE enum variant,
927 // check if the functions produce the expected high bit, low bit and
928 // combined values.
929 macro_rules! assert_opt_rcode_parts_eq {
930 ($name:expr, $high_bits:expr, $low_bits:expr) => {
931 let u12 = (($high_bits as u16) << 4) | ($low_bits as u16);
932 assert_eq!($name.rcode().to_int(), $low_bits);
933 assert_eq!($name.ext(), $high_bits);
934 assert_eq!($name.to_parts().0.to_int(), $low_bits);
935 assert_eq!($name.to_parts().1, $high_bits);
936 assert_eq!($name.to_int(), u12);
937 };
938 }
939
940 // Test RFC 6891 OptRcode enum variants that domain defines, plus any
941 // boundary cases not included in that set:
942 assert_opt_rcode_parts_eq!(OptRcode::NOERROR, 0b000_0000, 0b0000);
943 assert_opt_rcode_parts_eq!(OptRcode::FORMERR, 0b000_0000, 0b0001);
944 assert_opt_rcode_parts_eq!(OptRcode::SERVFAIL, 0b000_0000, 0b0010);
945 assert_opt_rcode_parts_eq!(OptRcode::NXDOMAIN, 0b000_0000, 0b0011);
946 assert_opt_rcode_parts_eq!(OptRcode::NOTIMP, 0b000_0000, 0b0100);
947 assert_opt_rcode_parts_eq!(OptRcode::REFUSED, 0b000_0000, 0b0101);
948 assert_opt_rcode_parts_eq!(OptRcode::YXDOMAIN, 0b000_0000, 0b0110);
949 assert_opt_rcode_parts_eq!(OptRcode::YXRRSET, 0b000_0000, 0b0111);
950 assert_opt_rcode_parts_eq!(OptRcode::NXRRSET, 0b000_0000, 0b1000);
951 assert_opt_rcode_parts_eq!(OptRcode::NOTAUTH, 0b000_0000, 0b1001);
952 assert_opt_rcode_parts_eq!(OptRcode::NOTZONE, 0b000_0000, 0b1010);
953 assert_opt_rcode_parts_eq!(OptRcode(15), 0b0000_0000, 0b1111);
954 assert_opt_rcode_parts_eq!(OptRcode::BADVERS, 0b0000_0001, 0b0000);
955 assert_opt_rcode_parts_eq!(OptRcode(17), 0b0000_0001, 0b0001);
956 assert_opt_rcode_parts_eq!(OptRcode::BADCOOKIE, 0b000_0001, 0b0111);
957 assert_opt_rcode_parts_eq!(OptRcode(4094), 0b1111_1111, 0b1110);
958 assert_opt_rcode_parts_eq!(OptRcode(4095), 0b1111_1111, 0b1111);
959 }
960
961 #[test]
962 fn rcode_fromstr() {
963 assert_eq!(Ok(Rcode::NOERROR), "NOERROR".parse());
964 assert_eq!(Ok(Rcode::FORMERR), "FORMERR".parse());
965 assert_eq!(Ok(Rcode::SERVFAIL), "SERVFAIL".parse());
966 assert_eq!(Ok(Rcode::NXDOMAIN), "NXDOMAIN".parse());
967 assert_eq!(Ok(Rcode::NOTIMP), "NOTIMP".parse());
968 assert_eq!(Ok(Rcode::REFUSED), "REFUSED".parse());
969 assert_eq!(Ok(Rcode::YXDOMAIN), "YXDOMAIN".parse());
970 assert_eq!(Ok(Rcode::YXRRSET), "YXRRSET".parse());
971 assert_eq!(Ok(Rcode::NXRRSET), "NXRRSET".parse());
972 assert_eq!(Ok(Rcode::NOTAUTH), "NOTAUTH".parse());
973 assert_eq!(Ok(Rcode::NOTZONE), "NOTZONE".parse());
974 assert!("#$%!@".parse::<Rcode>().is_err());
975 }
976
977 #[test]
978 fn optrcode_fromstr() {
979 assert_eq!(Ok(OptRcode::NOERROR), "NOERROR".parse());
980 assert_eq!(Ok(OptRcode::FORMERR), "FORMERR".parse());
981 assert_eq!(Ok(OptRcode::SERVFAIL), "SERVFAIL".parse());
982 assert_eq!(Ok(OptRcode::NXDOMAIN), "NXDOMAIN".parse());
983 assert_eq!(Ok(OptRcode::NOTIMP), "NOTIMP".parse());
984 assert_eq!(Ok(OptRcode::REFUSED), "REFUSED".parse());
985 assert_eq!(Ok(OptRcode::YXDOMAIN), "YXDOMAIN".parse());
986 assert_eq!(Ok(OptRcode::YXRRSET), "YXRRSET".parse());
987 assert_eq!(Ok(OptRcode::NXRRSET), "NXRRSET".parse());
988 assert_eq!(Ok(OptRcode::NOTAUTH), "NOTAUTH".parse());
989 assert_eq!(Ok(OptRcode::NOTZONE), "NOTZONE".parse());
990 assert_eq!(Ok(OptRcode::BADVERS), "BADVERS".parse());
991 assert_eq!(Ok(OptRcode::BADCOOKIE), "BADCOOKIE".parse());
992 assert!("#$%!@".parse::<Rcode>().is_err());
993 }
994
995 #[test]
996 fn optrcode_isext() {
997 assert!(!OptRcode::NOERROR.is_ext());
998 assert!(!OptRcode::FORMERR.is_ext());
999 assert!(!OptRcode::SERVFAIL.is_ext());
1000 assert!(!OptRcode::NXDOMAIN.is_ext());
1001 assert!(!OptRcode::NOTIMP.is_ext());
1002 assert!(!OptRcode::REFUSED.is_ext());
1003 assert!(!OptRcode::YXDOMAIN.is_ext());
1004 assert!(!OptRcode::YXRRSET.is_ext());
1005 assert!(!OptRcode::NXRRSET.is_ext());
1006 assert!(!OptRcode::NOTAUTH.is_ext());
1007 assert!(!OptRcode::NOTZONE.is_ext());
1008 assert!(OptRcode::BADVERS.is_ext());
1009 assert!(OptRcode::BADCOOKIE.is_ext());
1010 }
1011}