1# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
2
3# Copyright (C) 2001-2017 Nominum, Inc.
4#
5# Permission to use, copy, modify, and distribute this software and its
6# documentation for any purpose with or without fee is hereby granted,
7# provided that the above copyright notice and this permission notice
8# appear in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
16# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18"""DNS Result Codes."""
19
20import dns.enum
21import dns.exception
22
23class Rcode(dns.enum.IntEnum):
24    #: No error
25    NOERROR = 0
26    #: Format error
27    FORMERR = 1
28    #: Server failure
29    SERVFAIL = 2
30    #: Name does not exist ("Name Error" in RFC 1025 terminology).
31    NXDOMAIN = 3
32    #: Not implemented
33    NOTIMP = 4
34    #: Refused
35    REFUSED = 5
36    #: Name exists.
37    YXDOMAIN = 6
38    #: RRset exists.
39    YXRRSET = 7
40    #: RRset does not exist.
41    NXRRSET = 8
42    #: Not authoritative.
43    NOTAUTH = 9
44    #: Name not in zone.
45    NOTZONE = 10
46    #: DSO-TYPE Not Implemented
47    DSOTYPENI = 11
48    #: Bad EDNS version.
49    BADVERS = 16
50    #: TSIG Signature Failure
51    BADSIG = 16
52    #: Key not recognized.
53    BADKEY = 17
54    #: Signature out of time window.
55    BADTIME = 18
56    #: Bad TKEY Mode.
57    BADMODE = 19
58    #: Duplicate key name.
59    BADNAME = 20
60    #: Algorithm not supported.
61    BADALG = 21
62    #: Bad Truncation
63    BADTRUNC = 22
64    #: Bad/missing Server Cookie
65    BADCOOKIE = 23
66
67    @classmethod
68    def _maximum(cls):
69        return 4095
70
71    @classmethod
72    def _unknown_exception_class(cls):
73        return UnknownRcode
74
75globals().update(Rcode.__members__)
76
77class UnknownRcode(dns.exception.DNSException):
78    """A DNS rcode is unknown."""
79
80
81def from_text(text):
82    """Convert text into an rcode.
83
84    *text*, a ``str``, the textual rcode or an integer in textual form.
85
86    Raises ``dns.rcode.UnknownRcode`` if the rcode mnemonic is unknown.
87
88    Returns an ``int``.
89    """
90
91    return Rcode.from_text(text)
92
93
94def from_flags(flags, ednsflags):
95    """Return the rcode value encoded by flags and ednsflags.
96
97    *flags*, an ``int``, the DNS flags field.
98
99    *ednsflags*, an ``int``, the EDNS flags field.
100
101    Raises ``ValueError`` if rcode is < 0 or > 4095
102
103    Returns an ``int``.
104    """
105
106    value = (flags & 0x000f) | ((ednsflags >> 20) & 0xff0)
107    if value < 0 or value > 4095:
108        raise ValueError('rcode must be >= 0 and <= 4095')
109    return value
110
111
112def to_flags(value):
113    """Return a (flags, ednsflags) tuple which encodes the rcode.
114
115    *value*, an ``int``, the rcode.
116
117    Raises ``ValueError`` if rcode is < 0 or > 4095.
118
119    Returns an ``(int, int)`` tuple.
120    """
121
122    if value < 0 or value > 4095:
123        raise ValueError('rcode must be >= 0 and <= 4095')
124    v = value & 0xf
125    ev = (value & 0xff0) << 20
126    return (v, ev)
127
128
129def to_text(value, tsig=False):
130    """Convert rcode into text.
131
132    *value*, an ``int``, the rcode.
133
134    Raises ``ValueError`` if rcode is < 0 or > 4095.
135
136    Returns a ``str``.
137    """
138
139    if tsig and value == Rcode.BADVERS:
140        return 'BADSIG'
141    return Rcode.to_text(value)
142