1# Copyright (C) 2001-2007, 2009, 2010 Nominum, Inc. 2# 3# Permission to use, copy, modify, and distribute this software and its 4# documentation for any purpose with or without fee is hereby granted, 5# provided that the above copyright notice and this permission notice 6# appear in all copies. 7# 8# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 9# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 11# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 14# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 16"""DNS Rdata Types. 17 18@var _by_text: The rdata type textual name to value mapping 19@type _by_text: dict 20@var _by_value: The rdata type value to textual name mapping 21@type _by_value: dict 22@var _metatypes: If an rdatatype is a metatype, there will be a mapping 23whose key is the rdatatype value and whose value is True in this dictionary. 24@type _metatypes: dict 25@var _singletons: If an rdatatype is a singleton, there will be a mapping 26whose key is the rdatatype value and whose value is True in this dictionary. 27@type _singletons: dict""" 28 29import re 30 31import dns.exception 32 33NONE = 0 34A = 1 35NS = 2 36MD = 3 37MF = 4 38CNAME = 5 39SOA = 6 40MB = 7 41MG = 8 42MR = 9 43NULL = 10 44WKS = 11 45PTR = 12 46HINFO = 13 47MINFO = 14 48MX = 15 49TXT = 16 50RP = 17 51AFSDB = 18 52X25 = 19 53ISDN = 20 54RT = 21 55NSAP = 22 56NSAP_PTR = 23 57SIG = 24 58KEY = 25 59PX = 26 60GPOS = 27 61AAAA = 28 62LOC = 29 63NXT = 30 64SRV = 33 65NAPTR = 35 66KX = 36 67CERT = 37 68A6 = 38 69DNAME = 39 70OPT = 41 71APL = 42 72DS = 43 73SSHFP = 44 74IPSECKEY = 45 75RRSIG = 46 76NSEC = 47 77DNSKEY = 48 78DHCID = 49 79NSEC3 = 50 80NSEC3PARAM = 51 81HIP = 55 82SPF = 99 83UNSPEC = 103 84TKEY = 249 85TSIG = 250 86IXFR = 251 87AXFR = 252 88MAILB = 253 89MAILA = 254 90ANY = 255 91TA = 32768 92DLV = 32769 93 94_by_text = { 95 'NONE' : NONE, 96 'A' : A, 97 'NS' : NS, 98 'MD' : MD, 99 'MF' : MF, 100 'CNAME' : CNAME, 101 'SOA' : SOA, 102 'MB' : MB, 103 'MG' : MG, 104 'MR' : MR, 105 'NULL' : NULL, 106 'WKS' : WKS, 107 'PTR' : PTR, 108 'HINFO' : HINFO, 109 'MINFO' : MINFO, 110 'MX' : MX, 111 'TXT' : TXT, 112 'RP' : RP, 113 'AFSDB' : AFSDB, 114 'X25' : X25, 115 'ISDN' : ISDN, 116 'RT' : RT, 117 'NSAP' : NSAP, 118 'NSAP-PTR' : NSAP_PTR, 119 'SIG' : SIG, 120 'KEY' : KEY, 121 'PX' : PX, 122 'GPOS' : GPOS, 123 'AAAA' : AAAA, 124 'LOC' : LOC, 125 'NXT' : NXT, 126 'SRV' : SRV, 127 'NAPTR' : NAPTR, 128 'KX' : KX, 129 'CERT' : CERT, 130 'A6' : A6, 131 'DNAME' : DNAME, 132 'OPT' : OPT, 133 'APL' : APL, 134 'DS' : DS, 135 'SSHFP' : SSHFP, 136 'IPSECKEY' : IPSECKEY, 137 'RRSIG' : RRSIG, 138 'NSEC' : NSEC, 139 'DNSKEY' : DNSKEY, 140 'DHCID' : DHCID, 141 'NSEC3' : NSEC3, 142 'NSEC3PARAM' : NSEC3PARAM, 143 'HIP' : HIP, 144 'SPF' : SPF, 145 'UNSPEC' : UNSPEC, 146 'TKEY' : TKEY, 147 'TSIG' : TSIG, 148 'IXFR' : IXFR, 149 'AXFR' : AXFR, 150 'MAILB' : MAILB, 151 'MAILA' : MAILA, 152 'ANY' : ANY, 153 'TA' : TA, 154 'DLV' : DLV, 155 } 156 157# We construct the inverse mapping programmatically to ensure that we 158# cannot make any mistakes (e.g. omissions, cut-and-paste errors) that 159# would cause the mapping not to be true inverse. 160 161_by_value = dict([(y, x) for x, y in _by_text.iteritems()]) 162 163 164_metatypes = { 165 OPT : True 166 } 167 168_singletons = { 169 SOA : True, 170 NXT : True, 171 DNAME : True, 172 NSEC : True, 173 # CNAME is technically a singleton, but we allow multiple CNAMEs. 174 } 175 176_unknown_type_pattern = re.compile('TYPE([0-9]+)$', re.I); 177 178class UnknownRdatatype(dns.exception.DNSException): 179 """Raised if a type is unknown.""" 180 pass 181 182def from_text(text): 183 """Convert text into a DNS rdata type value. 184 @param text: the text 185 @type text: string 186 @raises dns.rdatatype.UnknownRdatatype: the type is unknown 187 @raises ValueError: the rdata type value is not >= 0 and <= 65535 188 @rtype: int""" 189 190 value = _by_text.get(text.upper()) 191 if value is None: 192 match = _unknown_type_pattern.match(text) 193 if match == None: 194 raise UnknownRdatatype 195 value = int(match.group(1)) 196 if value < 0 or value > 65535: 197 raise ValueError("type must be between >= 0 and <= 65535") 198 return value 199 200def to_text(value): 201 """Convert a DNS rdata type to text. 202 @param value: the rdata type value 203 @type value: int 204 @raises ValueError: the rdata type value is not >= 0 and <= 65535 205 @rtype: string""" 206 207 if value < 0 or value > 65535: 208 raise ValueError("type must be between >= 0 and <= 65535") 209 text = _by_value.get(value) 210 if text is None: 211 text = 'TYPE' + `value` 212 return text 213 214def is_metatype(rdtype): 215 """True if the type is a metatype. 216 @param rdtype: the type 217 @type rdtype: int 218 @rtype: bool""" 219 220 if rdtype >= TKEY and rdtype <= ANY or _metatypes.has_key(rdtype): 221 return True 222 return False 223 224def is_singleton(rdtype): 225 """True if the type is a singleton. 226 @param rdtype: the type 227 @type rdtype: int 228 @rtype: bool""" 229 230 if _singletons.has_key(rdtype): 231 return True 232 return False 233