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