├── .gitignore ├── README.md ├── config.py ├── dict ├── all-level.dict ├── second-level.dict └── top-level.dict ├── fuzz.py ├── lib ├── __init__.py ├── decorator.py ├── dns.py ├── dnspython │ ├── __init__.py │ ├── _compat.py │ ├── dnssec.py │ ├── e164.py │ ├── edns.py │ ├── entropy.py │ ├── exception.py │ ├── flags.py │ ├── grange.py │ ├── hash.py │ ├── inet.py │ ├── ipv4.py │ ├── ipv6.py │ ├── message.py │ ├── name.py │ ├── namedict.py │ ├── node.py │ ├── opcode.py │ ├── query.py │ ├── rcode.py │ ├── rdata.py │ ├── rdataclass.py │ ├── rdataset.py │ ├── rdatatype.py │ ├── rdtypes │ │ ├── ANY │ │ │ ├── AFSDB.py │ │ │ ├── CERT.py │ │ │ ├── CNAME.py │ │ │ ├── DLV.py │ │ │ ├── DNAME.py │ │ │ ├── DNSKEY.py │ │ │ ├── DS.py │ │ │ ├── GPOS.py │ │ │ ├── HINFO.py │ │ │ ├── HIP.py │ │ │ ├── ISDN.py │ │ │ ├── LOC.py │ │ │ ├── MX.py │ │ │ ├── NS.py │ │ │ ├── NSEC.py │ │ │ ├── NSEC3.py │ │ │ ├── NSEC3PARAM.py │ │ │ ├── PTR.py │ │ │ ├── RP.py │ │ │ ├── RRSIG.py │ │ │ ├── RT.py │ │ │ ├── SOA.py │ │ │ ├── SPF.py │ │ │ ├── SSHFP.py │ │ │ ├── TLSA.py │ │ │ ├── TXT.py │ │ │ ├── X25.py │ │ │ └── __init__.py │ │ ├── IN │ │ │ ├── A.py │ │ │ ├── AAAA.py │ │ │ ├── APL.py │ │ │ ├── DHCID.py │ │ │ ├── IPSECKEY.py │ │ │ ├── KX.py │ │ │ ├── NAPTR.py │ │ │ ├── NSAP.py │ │ │ ├── NSAP_PTR.py │ │ │ ├── PX.py │ │ │ ├── SRV.py │ │ │ ├── WKS.py │ │ │ └── __init__.py │ │ ├── __init__.py │ │ ├── dsbase.py │ │ ├── mxbase.py │ │ ├── nsbase.py │ │ └── txtbase.py │ ├── renderer.py │ ├── resolver.py │ ├── reversename.py │ ├── rrset.py │ ├── set.py │ ├── tokenizer.py │ ├── tsig.py │ ├── tsigkeyring.py │ ├── ttl.py │ ├── update.py │ ├── util.py │ ├── version.py │ ├── wiredata.py │ └── zone.py └── evil.py ├── output ├── g-queen.com.txt └── mail.qq.com.txt └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | # lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### FuzSub V2.0 2 | + AppName: FuzSub(Fuzz Sub-domain) 3 | + Create: 2015-04-08 4 | + Author: Dave, AAA 5 | 6 | FuzSub可以通过用户输入的域名进行自动化Fuzz,并可根据用户自身需求选择爆破方式。例如: 7 | 8 | ``` 9 | ➜ FuzSub git:(master) python fuzz.py alitrip.com 10 | [*] FuzSub is hot. 11 | [*] Target: alitrip.com 12 | [+] Name Server: ['ns4.taobao.com', 'ns5.taobao.com', 'ns6.taobao.com', 'ns7.taobao.com'] 13 | [*] Checking: alitrip.com NS: ns4.taobao.com 14 | [*] Checking: alitrip.com NS: ns5.taobao.com 15 | [*] Checking: alitrip.com NS: ns6.taobao.com 16 | [*] Checking: alitrip.com NS: ns7.taobao.com 17 | [*] < alitrip.com > FUZZING... 18 | [*] Pan Analysis: [['sh.wagbridge.alitrip.com'], ['140.205.230.45']] 19 | [+] 1111.alitrip.com ['113.107.235.241', '113.107.235.242', '113.107.239.108', '113.107.239.109', '183.61.180.195', '183.61.180.236'] 20 | [+] 61.alitrip.com ['119.147.69.236', '119.147.70.253', '121.14.89.253', '183.61.241.252'] 21 | [+] australia.alitrip.com ['140.205.250.51'] 22 | [+] bzy.alitrip.com ['106.11.55.235'] 23 | [+] decision.alitrip.com ['10.150.71.130'] 24 | ... 25 | [*] Done! 26 | [*] Total Time Consumption: 0s 27 | ``` 28 | 29 | ### TODO 30 | 31 | + 尝试控制域名枚举深度,即递归枚举到N级域名 32 | 33 | ### Usage 34 | 35 | ``` 36 | pip install -r requirements.txt 37 | ``` 38 | 39 | 安装完Python的相关支持库之后就可以直接食用。 40 | 41 | ``` 42 | # 一级域名枚举 43 | python fuzz.py qq.com 44 | # 无穷极域名枚举 45 | python fuzz.py qq.com full 46 | ``` 47 | 48 | ### Feature 49 | 50 | + 支持Python 2.7 & 3.0+ 51 | + 支持域传送漏洞检测 52 | + 较完美解决泛解析误报问题 53 | + 高效节能环保(在网络环境较好的情况80s跑完2.4W子域名) 54 | + 支持递归子域名枚举,即无穷级子域名爆破(python fuzz.py full) 55 | 56 | ### Note 57 | 58 | + `config.py`中设定线程数和DNS服务器 59 | + 默认进程数为50,可以根据自己机器的性能进行在源代码内进行调整。 60 | + 采用Gevent模式进行爆破提高效率 61 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- utf8 -*- 3 | # author=dave.fang@outlook.com 4 | # create=20160623 5 | import os 6 | 7 | BASE_DIR = os.path.abspath(os.path.dirname(__file__)) 8 | THREAD_BRUTE = 50 9 | MAX_TRY_COUNT = 5 10 | # DNS_LIST = ['8.8.8.8', '8.8.4.4'] 11 | DNS_LIST = ['114.114.114.114', '114.114.115.115'] 12 | IGNORE_DNS_LIST = ['f1g1ns2.dnspod.net', 'f1g1ns1.dnspod.net', 'ns1.dnsv2.com', 'ns2.dnsv2.com', 'ns1.dnsv3.com', 13 | 'ns2.dnsv3.com', 'ns1.dnsv4.com', 'ns2.dnsv4.com', 'ns1.dnsv5.com', 'ns2.dnsv5.com', 'ns3.dnsv2.com', 14 | 'ns4.dnsv2.com', 'ns3.dnsv3.com', 'ns4.dnsv3.com', 'ns3.dnsv4.com', 'ns4.dnsv4.com', 'ns3.dnsv5.com', 15 | 'ns4.dnsv5.com'] 16 | -------------------------------------------------------------------------------- /fuzz.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | # author=dave.fang@outlook.com 4 | # create=20160410 5 | 6 | """ 7 | * A Tool For Fuzzing Sub-domain. 8 | * GitHub: https://github.com/DavexPro/FuzSub 9 | * Version: 2.0 10 | * SUPPORT TOP-LEVEL & All-LEVEL 11 | """ 12 | import sys 13 | import datetime 14 | 15 | from lib.evil import Evil 16 | 17 | 18 | def start_fuzz(domain, depth=1): 19 | print('[*] Target: %s' % domain) 20 | evil = Evil(domain, depth) 21 | evil.start() 22 | 23 | 24 | if __name__ == '__main__': 25 | start_time = datetime.datetime.now() 26 | print('[*] FuzSub is hot.') 27 | if len(sys.argv) < 2: 28 | print('[-] E.g. python fuzz.py foo.com (top level) OR python fuzz.py foo.com full (full level)') 29 | exit() 30 | else: 31 | if len(sys.argv) == 2: 32 | start_fuzz(sys.argv[1], 1) 33 | elif sys.argv[2] == 'full': 34 | start_fuzz(sys.argv[1], -1) 35 | end_time = datetime.datetime.now() 36 | print('[*] Total Time Consumption: {0}s'.format((end_time - start_time).seconds)) 37 | -------------------------------------------------------------------------------- /lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davexpro/FuzSub/29f683b6f63eb2eaaa0553b151cae3c25b89fd1c/lib/__init__.py -------------------------------------------------------------------------------- /lib/decorator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- utf8 -*- 3 | # author=dave.fang@outlook.com 4 | # create=20160623 5 | import time 6 | 7 | from config import MAX_TRY_COUNT 8 | 9 | 10 | def max_try_wrapper(func): 11 | def wrapper(*args, **kwargs): 12 | for i in range(MAX_TRY_COUNT): 13 | try: 14 | func(*args, **kwargs) 15 | break 16 | except Exception as e: 17 | if func.__name__ != 'axfr_ns_check' or func.__name__ == 'get_ns_servers': 18 | print('[-] {0} Called Error: {1}'.format(func.__name__, e)) 19 | 20 | return wrapper 21 | 22 | 23 | def infinite_try_wrapper(func): 24 | def wrapper(*args, **kwargs): 25 | while True: 26 | try: 27 | func(*args, **kwargs) 28 | break 29 | except Exception as e: 30 | if func.__name__ != 'axfr_ns_check' or func.__name__ == 'get_ns_servers': 31 | print('[-] {0} Called Error: {1}'.format(func.__name__, e)) 32 | time.sleep(5) 33 | 34 | return wrapper 35 | -------------------------------------------------------------------------------- /lib/dns.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- utf8 -*- 3 | # author=dave.fang@outlook.com 4 | # create=20160410 5 | # update=20160630 6 | import re 7 | import os 8 | import sys 9 | import socket 10 | import binascii 11 | 12 | 13 | def get_analysis_from_dns(dns_server, sub_domain): 14 | # Core Content 15 | host = '' 16 | for i in sub_domain.split('.'): 17 | host += chr(len(i)) + i 18 | data = os.urandom(2) 19 | data += bytearray([0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) 20 | data += bytes(host.encode('utf-8')) 21 | data += bytearray([0x00, 0x00, 0x01, 0x00, 0x01]) 22 | while True: 23 | try: 24 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 25 | s.settimeout(8) 26 | s.sendto(data, (dns_server, 53)) 27 | respond = s.recv(512) 28 | break 29 | except Exception as e: 30 | # print('[-] Error 01: {0}'.format(e)) 31 | pass 32 | # print(str(binascii.hexlify(respond))) 33 | ip_list = [] 34 | """ 35 | 0000 6c 71 d9 82 3d 8c 00 fc 8d fe f4 42 08 00 45 00 lq..=......B..E. 36 | 0010 00 54 6c 1e 00 00 31 11 4c b5 08 08 08 08 c0 a8 .Tl...1.L....... 37 | 0020 00 0e 00 35 d7 6a 00 40 fa f0 c9 dc 81 80 00 01 ...5.j.@........ 38 | 0030 00 02 00 00 00 00 02 71 71 03 63 6f 6d 00 00 01 .......qq.com... 39 | 0040 00 01 c0 0c 00 01 00 01 00 00 01 f7 00 04 7d 27 ..............}' 40 | 0050 f0 71 c0 0c 00 01 00 01 00 00 01 f7 00 04 3d 87 .q............=. 41 | 0060 9d 9c 42 | 43 | 827107 3104.302029 8.8.8.8 192.168.0.14 44 | DNS 98 Standard query response 0xc9dc A qq.com A 125.39.240.113 A 61.135.157.156.. 45 | 7d.27 3d.87.9d.9c 46 | """ 47 | # Query Name 48 | try: 49 | if sys.version_info >= (3, 0): 50 | find = re.findall("^[\S]{26}[\S]{2}([\S]+?)0000010001", str(binascii.hexlify(respond))) 51 | else: 52 | find = re.findall("^[\S]{26}([\S]+?)0000010001", str(binascii.hexlify(respond))) 53 | query_name = '' 54 | for i in range(int(len(find[0]) / 2)): 55 | # print(chr(int(find[0][i*2:i*2+2], 16)), int(find[0][i*2:i*2+2], 16)) 56 | if int(find[0][i * 2:i * 2 + 2], 16) < 16: 57 | query_name += '.' 58 | else: 59 | query_name += chr(int(find[0][i * 2:i * 2 + 2], 16)) 60 | except Exception as e: 61 | print('[-] Query Name Error: {0} \n{1}'.format(str(e), find)) 62 | pass 63 | 64 | # CNAME Record 65 | sub_cnames = [] 66 | try: 67 | find = re.findall("c0[\S]{2}00050001[\S]{8}([\S]{4})", str(binascii.hexlify(respond))) 68 | if len(find) > 0: 69 | # for one_answer in find: 70 | one_answer = find[0] 71 | length = int(one_answer, 16) * 2 72 | find = re.findall("c0[\S]{2}00050001[\S]{8}[\S]{4}([\S]{%d})c0" % length, str(binascii.hexlify(respond))) 73 | offset = re.findall('c0([\S]{2})$', find[0]) 74 | sub_cname = '' 75 | for_range = int(len(find[0]) / 2) - 1 76 | if len(offset) > 0: 77 | for_range -= 1 78 | for i in range(for_range): 79 | # print(chr(int(find[0][i*2:i*2+2], 16)), find[0][i*2:i*2+2]) 80 | if 16 <= int(find[0][i * 2:i * 2 + 2], 16) < 32: 81 | pass 82 | elif int(find[0][i * 2:i * 2 + 2], 16) < 16: 83 | sub_cname += '.' 84 | else: 85 | sub_cname += chr(int(find[0][i * 2:i * 2 + 2], 16)) 86 | if len(offset) > 0: 87 | sub_cname += query_name[int(offset[0], 16) - 13:] 88 | while sub_cname[0] == '.': 89 | sub_cname = sub_cname[1:] 90 | sub_cnames.append(sub_cname) 91 | except Exception as e: 92 | print('[-] CNAME Error: {0} {1} {2}'.format(str(e), sub_domain, find)) 93 | pass 94 | 95 | # A Record 96 | find = re.findall("c0[\S]{2}00010001[\S]{12}([\S]{8})", str(binascii.hexlify(respond))) 97 | for j in find: 98 | ip = str(int('0x' + j[0:2], 0)) + '.' 99 | ip += str(int('0x' + j[2:4], 0)) + '.' 100 | ip += str(int('0x' + j[4:6], 0)) + '.' 101 | ip += str(int('0x' + j[6:8], 0)) 102 | ip_list.append(ip) 103 | ip_list.sort() 104 | 105 | return [sub_cnames, ip_list] 106 | -------------------------------------------------------------------------------- /lib/dnspython/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009, 2011 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 | """dnspython DNS toolkit""" 17 | 18 | __all__ = [ 19 | 'dnssec', 20 | 'e164', 21 | 'edns', 22 | 'entropy', 23 | 'exception', 24 | 'flags', 25 | 'hash', 26 | 'inet', 27 | 'ipv4', 28 | 'ipv6', 29 | 'message', 30 | 'name', 31 | 'namedict', 32 | 'node', 33 | 'opcode', 34 | 'query', 35 | 'rcode', 36 | 'rdata', 37 | 'rdataclass', 38 | 'rdataset', 39 | 'rdatatype', 40 | 'renderer', 41 | 'resolver', 42 | 'reversename', 43 | 'rrset', 44 | 'set', 45 | 'tokenizer', 46 | 'tsig', 47 | 'tsigkeyring', 48 | 'ttl', 49 | 'rdtypes', 50 | 'update', 51 | 'version', 52 | 'wiredata', 53 | 'zone', 54 | ] 55 | -------------------------------------------------------------------------------- /lib/dnspython/_compat.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if sys.version_info > (3,): 4 | long = int 5 | xrange = range 6 | else: 7 | long = long 8 | xrange = xrange 9 | 10 | # unicode / binary types 11 | if sys.version_info > (3,): 12 | text_type = str 13 | binary_type = bytes 14 | string_types = (str,) 15 | unichr = chr 16 | else: 17 | text_type = unicode 18 | binary_type = str 19 | string_types = (basestring,) 20 | unichr = unichr 21 | -------------------------------------------------------------------------------- /lib/dnspython/e164.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006, 2007, 2009, 2011 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 E.164 helpers 17 | 18 | @var public_enum_domain: The DNS public ENUM domain, e164.arpa. 19 | @type public_enum_domain: dns.name.Name object 20 | """ 21 | 22 | import dns.exception 23 | import dns.name 24 | import dns.resolver 25 | from ._compat import string_types 26 | 27 | public_enum_domain = dns.name.from_text('e164.arpa.') 28 | 29 | 30 | def from_e164(text, origin=public_enum_domain): 31 | """Convert an E.164 number in textual form into a Name object whose 32 | value is the ENUM domain name for that number. 33 | @param text: an E.164 number in textual form. 34 | @type text: str 35 | @param origin: The domain in which the number should be constructed. 36 | The default is e164.arpa. 37 | @type origin: dns.name.Name object or None 38 | @rtype: dns.name.Name object 39 | """ 40 | parts = [d for d in text if d.isdigit()] 41 | parts.reverse() 42 | return dns.name.from_text('.'.join(parts), origin=origin) 43 | 44 | 45 | def to_e164(name, origin=public_enum_domain, want_plus_prefix=True): 46 | """Convert an ENUM domain name into an E.164 number. 47 | @param name: the ENUM domain name. 48 | @type name: dns.name.Name object. 49 | @param origin: A domain containing the ENUM domain name. The 50 | name is relativized to this domain before being converted to text. 51 | @type origin: dns.name.Name object or None 52 | @param want_plus_prefix: if True, add a '+' to the beginning of the 53 | returned number. 54 | @rtype: str 55 | """ 56 | if origin is not None: 57 | name = name.relativize(origin) 58 | dlabels = [d for d in name.labels if (d.isdigit() and len(d) == 1)] 59 | if len(dlabels) != len(name.labels): 60 | raise dns.exception.SyntaxError('non-digit labels in ENUM domain name') 61 | dlabels.reverse() 62 | text = b''.join(dlabels) 63 | if want_plus_prefix: 64 | text = b'+' + text 65 | return text 66 | 67 | 68 | def query(number, domains, resolver=None): 69 | """Look for NAPTR RRs for the specified number in the specified domains. 70 | 71 | e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.']) 72 | """ 73 | if resolver is None: 74 | resolver = dns.resolver.get_default_resolver() 75 | for domain in domains: 76 | if isinstance(domain, string_types): 77 | domain = dns.name.from_text(domain) 78 | qname = dns.e164.from_e164(number, domain) 79 | try: 80 | return resolver.query(qname, 'NAPTR') 81 | except dns.resolver.NXDOMAIN: 82 | pass 83 | raise dns.resolver.NXDOMAIN 84 | -------------------------------------------------------------------------------- /lib/dnspython/edns.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009, 2011 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 | """EDNS Options""" 17 | 18 | NSID = 3 19 | 20 | 21 | class Option(object): 22 | """Base class for all EDNS option types. 23 | """ 24 | 25 | def __init__(self, otype): 26 | """Initialize an option. 27 | @param otype: The rdata type 28 | @type otype: int 29 | """ 30 | self.otype = otype 31 | 32 | def to_wire(self, file): 33 | """Convert an option to wire format. 34 | """ 35 | raise NotImplementedError 36 | 37 | @classmethod 38 | def from_wire(cls, otype, wire, current, olen): 39 | """Build an EDNS option object from wire format 40 | 41 | @param otype: The option type 42 | @type otype: int 43 | @param wire: The wire-format message 44 | @type wire: string 45 | @param current: The offset in wire of the beginning of the rdata. 46 | @type current: int 47 | @param olen: The length of the wire-format option data 48 | @type olen: int 49 | @rtype: dns.edns.Option instance""" 50 | raise NotImplementedError 51 | 52 | def _cmp(self, other): 53 | """Compare an EDNS option with another option of the same type. 54 | Return < 0 if self < other, 0 if self == other, 55 | and > 0 if self > other. 56 | """ 57 | raise NotImplementedError 58 | 59 | def __eq__(self, other): 60 | if not isinstance(other, Option): 61 | return False 62 | if self.otype != other.otype: 63 | return False 64 | return self._cmp(other) == 0 65 | 66 | def __ne__(self, other): 67 | if not isinstance(other, Option): 68 | return False 69 | if self.otype != other.otype: 70 | return False 71 | return self._cmp(other) != 0 72 | 73 | def __lt__(self, other): 74 | if not isinstance(other, Option) or \ 75 | self.otype != other.otype: 76 | return NotImplemented 77 | return self._cmp(other) < 0 78 | 79 | def __le__(self, other): 80 | if not isinstance(other, Option) or \ 81 | self.otype != other.otype: 82 | return NotImplemented 83 | return self._cmp(other) <= 0 84 | 85 | def __ge__(self, other): 86 | if not isinstance(other, Option) or \ 87 | self.otype != other.otype: 88 | return NotImplemented 89 | return self._cmp(other) >= 0 90 | 91 | def __gt__(self, other): 92 | if not isinstance(other, Option) or \ 93 | self.otype != other.otype: 94 | return NotImplemented 95 | return self._cmp(other) > 0 96 | 97 | 98 | class GenericOption(Option): 99 | """Generate Rdata Class 100 | 101 | This class is used for EDNS option types for which we have no better 102 | implementation. 103 | """ 104 | 105 | def __init__(self, otype, data): 106 | super(GenericOption, self).__init__(otype) 107 | self.data = data 108 | 109 | def to_wire(self, file): 110 | file.write(self.data) 111 | 112 | @classmethod 113 | def from_wire(cls, otype, wire, current, olen): 114 | return cls(otype, wire[current: current + olen]) 115 | 116 | def _cmp(self, other): 117 | if self.data == other.data: 118 | return 0 119 | if self.data > other.data: 120 | return 1 121 | return -1 122 | 123 | 124 | _type_to_class = { 125 | } 126 | 127 | 128 | def get_option_class(otype): 129 | cls = _type_to_class.get(otype) 130 | if cls is None: 131 | cls = GenericOption 132 | return cls 133 | 134 | 135 | def option_from_wire(otype, wire, current, olen): 136 | """Build an EDNS option object from wire format 137 | 138 | @param otype: The option type 139 | @type otype: int 140 | @param wire: The wire-format message 141 | @type wire: string 142 | @param current: The offset in wire of the beginning of the rdata. 143 | @type current: int 144 | @param olen: The length of the wire-format option data 145 | @type olen: int 146 | @rtype: dns.edns.Option instance""" 147 | 148 | cls = get_option_class(otype) 149 | return cls.from_wire(otype, wire, current, olen) 150 | -------------------------------------------------------------------------------- /lib/dnspython/entropy.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009, 2011 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 | import os 17 | import time 18 | from ._compat import long, binary_type 19 | 20 | try: 21 | import threading as _threading 22 | except ImportError: 23 | import dummy_threading as _threading 24 | 25 | 26 | class EntropyPool(object): 27 | def __init__(self, seed=None): 28 | self.pool_index = 0 29 | self.digest = None 30 | self.next_byte = 0 31 | self.lock = _threading.Lock() 32 | try: 33 | import hashlib 34 | self.hash = hashlib.sha1() 35 | self.hash_len = 20 36 | except: 37 | try: 38 | import sha 39 | self.hash = sha.new() 40 | self.hash_len = 20 41 | except: 42 | import md5 43 | self.hash = md5.new() 44 | self.hash_len = 16 45 | self.pool = bytearray(b'\0' * self.hash_len) 46 | if seed is not None: 47 | self.stir(bytearray(seed)) 48 | self.seeded = True 49 | else: 50 | self.seeded = False 51 | 52 | def stir(self, entropy, already_locked=False): 53 | if not already_locked: 54 | self.lock.acquire() 55 | try: 56 | for c in entropy: 57 | if self.pool_index == self.hash_len: 58 | self.pool_index = 0 59 | b = c & 0xff 60 | self.pool[self.pool_index] ^= b 61 | self.pool_index += 1 62 | finally: 63 | if not already_locked: 64 | self.lock.release() 65 | 66 | def _maybe_seed(self): 67 | if not self.seeded: 68 | try: 69 | seed = os.urandom(16) 70 | except: 71 | try: 72 | r = open('/dev/urandom', 'rb', 0) 73 | try: 74 | seed = r.read(16) 75 | finally: 76 | r.close() 77 | except: 78 | seed = str(time.time()) 79 | self.seeded = True 80 | seed = bytearray(seed) 81 | self.stir(seed, True) 82 | 83 | def random_8(self): 84 | self.lock.acquire() 85 | try: 86 | self._maybe_seed() 87 | if self.digest is None or self.next_byte == self.hash_len: 88 | self.hash.update(binary_type(self.pool)) 89 | self.digest = bytearray(self.hash.digest()) 90 | self.stir(self.digest, True) 91 | self.next_byte = 0 92 | value = self.digest[self.next_byte] 93 | self.next_byte += 1 94 | finally: 95 | self.lock.release() 96 | return value 97 | 98 | def random_16(self): 99 | return self.random_8() * 256 + self.random_8() 100 | 101 | def random_32(self): 102 | return self.random_16() * 65536 + self.random_16() 103 | 104 | def random_between(self, first, last): 105 | size = last - first + 1 106 | if size > long(4294967296): 107 | raise ValueError('too big') 108 | if size > 65536: 109 | rand = self.random_32 110 | max = long(4294967295) 111 | elif size > 256: 112 | rand = self.random_16 113 | max = 65535 114 | else: 115 | rand = self.random_8 116 | max = 255 117 | return (first + size * rand() // (max + 1)) 118 | 119 | 120 | pool = EntropyPool() 121 | 122 | 123 | def random_16(): 124 | return pool.random_16() 125 | 126 | 127 | def between(first, last): 128 | return pool.random_between(first, last) 129 | -------------------------------------------------------------------------------- /lib/dnspython/exception.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """Common DNS Exceptions.""" 17 | 18 | 19 | class DNSException(Exception): 20 | """Abstract base class shared by all dnspython exceptions. 21 | 22 | It supports two basic modes of operation: 23 | 24 | a) Old/compatible mode is used if __init__ was called with 25 | empty **kwargs. 26 | In compatible mode all *args are passed to standard Python Exception class 27 | as before and all *args are printed by standard __str__ implementation. 28 | Class variable msg (or doc string if msg is None) is returned from str() 29 | if *args is empty. 30 | 31 | b) New/parametrized mode is used if __init__ was called with 32 | non-empty **kwargs. 33 | In the new mode *args has to be empty and all kwargs has to exactly match 34 | set in class variable self.supp_kwargs. All kwargs are stored inside 35 | self.kwargs and used in new __str__ implementation to construct 36 | formatted message based on self.fmt string. 37 | 38 | In the simplest case it is enough to override supp_kwargs and fmt 39 | class variables to get nice parametrized messages. 40 | """ 41 | msg = None # non-parametrized message 42 | supp_kwargs = set() # accepted parameters for _fmt_kwargs (sanity check) 43 | fmt = None # message parametrized with results from _fmt_kwargs 44 | 45 | def __init__(self, *args, **kwargs): 46 | self._check_params(*args, **kwargs) 47 | self._check_kwargs(**kwargs) 48 | self.kwargs = kwargs 49 | if self.msg is None: 50 | # doc string is better implicit message than empty string 51 | self.msg = self.__doc__ 52 | if args: 53 | super(DNSException, self).__init__(*args) 54 | else: 55 | super(DNSException, self).__init__(self.msg) 56 | 57 | def _check_params(self, *args, **kwargs): 58 | """Old exceptions supported only args and not kwargs. 59 | 60 | For sanity we do not allow to mix old and new behavior.""" 61 | if args or kwargs: 62 | assert bool(args) != bool(kwargs), \ 63 | 'keyword arguments are mutually exclusive with positional args' 64 | 65 | def _check_kwargs(self, **kwargs): 66 | if kwargs: 67 | assert set(kwargs.keys()) == self.supp_kwargs, \ 68 | 'following set of keyword args is required: %s' % ( 69 | self.supp_kwargs) 70 | 71 | def _fmt_kwargs(self, **kwargs): 72 | """Format kwargs before printing them. 73 | 74 | Resulting dictionary has to have keys necessary for str.format call 75 | on fmt class variable. 76 | """ 77 | fmtargs = {} 78 | for kw, data in kwargs.items(): 79 | if isinstance(data, (list, set)): 80 | # convert list of to list of str() 81 | fmtargs[kw] = list(map(str, data)) 82 | if len(fmtargs[kw]) == 1: 83 | # remove list brackets [] from single-item lists 84 | fmtargs[kw] = fmtargs[kw].pop() 85 | else: 86 | fmtargs[kw] = data 87 | return fmtargs 88 | 89 | def __str__(self): 90 | if self.kwargs and self.fmt: 91 | # provide custom message constructed from keyword arguments 92 | fmtargs = self._fmt_kwargs(**self.kwargs) 93 | return self.fmt.format(**fmtargs) 94 | else: 95 | # print *args directly in the same way as old DNSException 96 | return super(DNSException, self).__str__() 97 | 98 | 99 | class FormError(DNSException): 100 | """DNS message is malformed.""" 101 | 102 | 103 | class SyntaxError(DNSException): 104 | """Text input is malformed.""" 105 | 106 | 107 | class UnexpectedEnd(SyntaxError): 108 | """Text input ended unexpectedly.""" 109 | 110 | 111 | class TooBig(DNSException): 112 | """The DNS message is too big.""" 113 | 114 | 115 | class Timeout(DNSException): 116 | """The DNS operation timed out.""" 117 | supp_kwargs = set(['timeout']) 118 | fmt = "The DNS operation timed out after {timeout} seconds" 119 | -------------------------------------------------------------------------------- /lib/dnspython/flags.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2001-2007, 2009-2011 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 Message Flags.""" 17 | 18 | # Standard DNS flags 19 | 20 | QR = 0x8000 21 | AA = 0x0400 22 | TC = 0x0200 23 | RD = 0x0100 24 | RA = 0x0080 25 | AD = 0x0020 26 | CD = 0x0010 27 | 28 | # EDNS flags 29 | 30 | DO = 0x8000 31 | 32 | _by_text = { 33 | 'QR': QR, 34 | 'AA': AA, 35 | 'TC': TC, 36 | 'RD': RD, 37 | 'RA': RA, 38 | 'AD': AD, 39 | 'CD': CD 40 | } 41 | 42 | _edns_by_text = { 43 | 'DO': DO 44 | } 45 | 46 | # We construct the inverse mappings programmatically to ensure that we 47 | # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that 48 | # would cause the mappings not to be true inverses. 49 | 50 | _by_value = dict((y, x) for x, y in _by_text.items()) 51 | 52 | _edns_by_value = dict((y, x) for x, y in _edns_by_text.items()) 53 | 54 | 55 | def _order_flags(table): 56 | order = list(table.items()) 57 | order.sort() 58 | order.reverse() 59 | return order 60 | 61 | 62 | _flags_order = _order_flags(_by_value) 63 | 64 | _edns_flags_order = _order_flags(_edns_by_value) 65 | 66 | 67 | def _from_text(text, table): 68 | flags = 0 69 | tokens = text.split() 70 | for t in tokens: 71 | flags = flags | table[t.upper()] 72 | return flags 73 | 74 | 75 | def _to_text(flags, table, order): 76 | text_flags = [] 77 | for k, v in order: 78 | if flags & k != 0: 79 | text_flags.append(v) 80 | return ' '.join(text_flags) 81 | 82 | 83 | def from_text(text): 84 | """Convert a space-separated list of flag text values into a flags 85 | value. 86 | @rtype: int""" 87 | 88 | return _from_text(text, _by_text) 89 | 90 | 91 | def to_text(flags): 92 | """Convert a flags value into a space-separated list of flag text 93 | values. 94 | @rtype: string""" 95 | 96 | return _to_text(flags, _by_value, _flags_order) 97 | 98 | 99 | def edns_from_text(text): 100 | """Convert a space-separated list of EDNS flag text values into a EDNS 101 | flags value. 102 | @rtype: int""" 103 | 104 | return _from_text(text, _edns_by_text) 105 | 106 | 107 | def edns_to_text(flags): 108 | """Convert an EDNS flags value into a space-separated list of EDNS flag 109 | text values. 110 | @rtype: string""" 111 | 112 | return _to_text(flags, _edns_by_value, _edns_flags_order) 113 | -------------------------------------------------------------------------------- /lib/dnspython/grange.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 GENERATE range conversion.""" 17 | 18 | import dns 19 | 20 | 21 | def from_text(text): 22 | """Convert the text form of a range in a GENERATE statement to an 23 | integer. 24 | 25 | @param text: the textual range 26 | @type text: string 27 | @return: The start, stop and step values. 28 | @rtype: tuple 29 | """ 30 | # TODO, figure out the bounds on start, stop and step. 31 | 32 | step = 1 33 | cur = '' 34 | state = 0 35 | # state 0 1 2 3 4 36 | # x - y / z 37 | for c in text: 38 | if c == '-' and state == 0: 39 | start = int(cur) 40 | cur = '' 41 | state = 2 42 | elif c == '/': 43 | stop = int(cur) 44 | cur = '' 45 | state = 4 46 | elif c.isdigit(): 47 | cur += c 48 | else: 49 | raise dns.exception.SyntaxError("Could not parse %s" % (c)) 50 | 51 | if state in (1, 3): 52 | raise dns.exception.SyntaxError 53 | 54 | if state == 2: 55 | stop = int(cur) 56 | 57 | if state == 4: 58 | step = int(cur) 59 | 60 | assert step >= 1 61 | assert start >= 0 62 | assert start <= stop 63 | # TODO, can start == stop? 64 | 65 | return (start, stop, step) 66 | -------------------------------------------------------------------------------- /lib/dnspython/hash.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 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 | """Hashing backwards compatibility wrapper""" 17 | 18 | import sys 19 | import hashlib 20 | 21 | hashes = {} 22 | hashes['MD5'] = hashlib.md5 23 | hashes['SHA1'] = hashlib.sha1 24 | hashes['SHA224'] = hashlib.sha224 25 | hashes['SHA256'] = hashlib.sha256 26 | hashes['SHA384'] = hashlib.sha384 27 | hashes['SHA512'] = hashlib.sha512 28 | 29 | 30 | def get(algorithm): 31 | return hashes[algorithm.upper()] 32 | -------------------------------------------------------------------------------- /lib/dnspython/inet.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """Generic Internet address helper functions.""" 17 | 18 | import socket 19 | 20 | import dns.ipv4 21 | import dns.ipv6 22 | 23 | # We assume that AF_INET is always defined. 24 | 25 | AF_INET = socket.AF_INET 26 | 27 | # AF_INET6 might not be defined in the socket module, but we need it. 28 | # We'll try to use the socket module's value, and if it doesn't work, 29 | # we'll use our own value. 30 | 31 | try: 32 | AF_INET6 = socket.AF_INET6 33 | except AttributeError: 34 | AF_INET6 = 9999 35 | 36 | 37 | def inet_pton(family, text): 38 | """Convert the textual form of a network address into its binary form. 39 | 40 | @param family: the address family 41 | @type family: int 42 | @param text: the textual address 43 | @type text: string 44 | @raises NotImplementedError: the address family specified is not 45 | implemented. 46 | @rtype: string 47 | """ 48 | 49 | if family == AF_INET: 50 | return dns.ipv4.inet_aton(text) 51 | elif family == AF_INET6: 52 | return dns.ipv6.inet_aton(text) 53 | else: 54 | raise NotImplementedError 55 | 56 | 57 | def inet_ntop(family, address): 58 | """Convert the binary form of a network address into its textual form. 59 | 60 | @param family: the address family 61 | @type family: int 62 | @param address: the binary address 63 | @type address: string 64 | @raises NotImplementedError: the address family specified is not 65 | implemented. 66 | @rtype: string 67 | """ 68 | if family == AF_INET: 69 | return dns.ipv4.inet_ntoa(address) 70 | elif family == AF_INET6: 71 | return dns.ipv6.inet_ntoa(address) 72 | else: 73 | raise NotImplementedError 74 | 75 | 76 | def af_for_address(text): 77 | """Determine the address family of a textual-form network address. 78 | 79 | @param text: the textual address 80 | @type text: string 81 | @raises ValueError: the address family cannot be determined from the input. 82 | @rtype: int 83 | """ 84 | try: 85 | dns.ipv4.inet_aton(text) 86 | return AF_INET 87 | except: 88 | try: 89 | dns.ipv6.inet_aton(text) 90 | return AF_INET6 91 | except: 92 | raise ValueError 93 | 94 | 95 | def is_multicast(text): 96 | """Is the textual-form network address a multicast address? 97 | 98 | @param text: the textual address 99 | @raises ValueError: the address family cannot be determined from the input. 100 | @rtype: bool 101 | """ 102 | try: 103 | first = ord(dns.ipv4.inet_aton(text)[0]) 104 | return (first >= 224 and first <= 239) 105 | except: 106 | try: 107 | first = ord(dns.ipv6.inet_aton(text)[0]) 108 | return (first == 255) 109 | except: 110 | raise ValueError 111 | -------------------------------------------------------------------------------- /lib/dnspython/ipv4.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """IPv4 helper functions.""" 17 | 18 | import struct 19 | 20 | import dns.exception 21 | from ._compat import binary_type 22 | 23 | 24 | def inet_ntoa(address): 25 | """Convert an IPv4 address in network form to text form. 26 | 27 | @param address: The IPv4 address 28 | @type address: string 29 | @returns: string 30 | """ 31 | if len(address) != 4: 32 | raise dns.exception.SyntaxError 33 | if not isinstance(address, bytearray): 34 | address = bytearray(address) 35 | return (u'%u.%u.%u.%u' % (address[0], address[1], 36 | address[2], address[3])).encode() 37 | 38 | 39 | def inet_aton(text): 40 | """Convert an IPv4 address in text form to network form. 41 | 42 | @param text: The IPv4 address 43 | @type text: string 44 | @returns: string 45 | """ 46 | if not isinstance(text, binary_type): 47 | text = text.encode() 48 | parts = text.split(b'.') 49 | if len(parts) != 4: 50 | raise dns.exception.SyntaxError 51 | for part in parts: 52 | if not part.isdigit(): 53 | raise dns.exception.SyntaxError 54 | if len(part) > 1 and part[0] == '0': 55 | # No leading zeros 56 | raise dns.exception.SyntaxError 57 | try: 58 | bytes = [int(part) for part in parts] 59 | return struct.pack('BBBB', *bytes) 60 | except: 61 | raise dns.exception.SyntaxError 62 | -------------------------------------------------------------------------------- /lib/dnspython/ipv6.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """IPv6 helper functions.""" 17 | 18 | import re 19 | import binascii 20 | 21 | import dns.exception 22 | import dns.ipv4 23 | from ._compat import xrange, binary_type 24 | 25 | _leading_zero = re.compile(b'0+([0-9a-f]+)') 26 | 27 | 28 | def inet_ntoa(address): 29 | """Convert a network format IPv6 address into text. 30 | 31 | @param address: the binary address 32 | @type address: string 33 | @rtype: string 34 | @raises ValueError: the address isn't 16 bytes long 35 | """ 36 | 37 | if len(address) != 16: 38 | raise ValueError("IPv6 addresses are 16 bytes long") 39 | hex = binascii.hexlify(address) 40 | chunks = [] 41 | i = 0 42 | l = len(hex) 43 | while i < l: 44 | chunk = hex[i: i + 4] 45 | # strip leading zeros. we do this with an re instead of 46 | # with lstrip() because lstrip() didn't support chars until 47 | # python 2.2.2 48 | m = _leading_zero.match(chunk) 49 | if not m is None: 50 | chunk = m.group(1) 51 | chunks.append(chunk) 52 | i += 4 53 | # 54 | # Compress the longest subsequence of 0-value chunks to :: 55 | # 56 | best_start = 0 57 | best_len = 0 58 | start = -1 59 | last_was_zero = False 60 | for i in xrange(8): 61 | if chunks[i] != b'0': 62 | if last_was_zero: 63 | end = i 64 | current_len = end - start 65 | if current_len > best_len: 66 | best_start = start 67 | best_len = current_len 68 | last_was_zero = False 69 | elif not last_was_zero: 70 | start = i 71 | last_was_zero = True 72 | if last_was_zero: 73 | end = 8 74 | current_len = end - start 75 | if current_len > best_len: 76 | best_start = start 77 | best_len = current_len 78 | if best_len > 1: 79 | if best_start == 0 and \ 80 | (best_len == 6 or 81 | best_len == 5 and chunks[5] == b'ffff'): 82 | # We have an embedded IPv4 address 83 | if best_len == 6: 84 | prefix = b'::' 85 | else: 86 | prefix = b'::ffff:' 87 | hex = prefix + dns.ipv4.inet_ntoa(address[12:]) 88 | else: 89 | hex = b':'.join(chunks[:best_start]) + b'::' + \ 90 | b':'.join(chunks[best_start + best_len:]) 91 | else: 92 | hex = b':'.join(chunks) 93 | return hex 94 | 95 | 96 | _v4_ending = re.compile(b'(.*):(\d+\.\d+\.\d+\.\d+)$') 97 | _colon_colon_start = re.compile(b'::.*') 98 | _colon_colon_end = re.compile(b'.*::$') 99 | 100 | 101 | def inet_aton(text): 102 | """Convert a text format IPv6 address into network format. 103 | 104 | @param text: the textual address 105 | @type text: string 106 | @rtype: string 107 | @raises dns.exception.SyntaxError: the text was not properly formatted 108 | """ 109 | 110 | # 111 | # Our aim here is not something fast; we just want something that works. 112 | # 113 | if not isinstance(text, binary_type): 114 | text = text.encode() 115 | 116 | if text == b'::': 117 | text = b'0::' 118 | # 119 | # Get rid of the icky dot-quad syntax if we have it. 120 | # 121 | m = _v4_ending.match(text) 122 | if not m is None: 123 | b = bytearray(dns.ipv4.inet_aton(m.group(2))) 124 | text = (u"%s:%02x%02x:%02x%02x" % (m.group(1).decode(), b[0], b[1], 125 | b[2], b[3])).encode() 126 | # 127 | # Try to turn '::' into ':'; if no match try to 128 | # turn '::' into ':' 129 | # 130 | m = _colon_colon_start.match(text) 131 | if not m is None: 132 | text = text[1:] 133 | else: 134 | m = _colon_colon_end.match(text) 135 | if not m is None: 136 | text = text[:-1] 137 | # 138 | # Now canonicalize into 8 chunks of 4 hex digits each 139 | # 140 | chunks = text.split(b':') 141 | l = len(chunks) 142 | if l > 8: 143 | raise dns.exception.SyntaxError 144 | seen_empty = False 145 | canonical = [] 146 | for c in chunks: 147 | if c == b'': 148 | if seen_empty: 149 | raise dns.exception.SyntaxError 150 | seen_empty = True 151 | for i in xrange(0, 8 - l + 1): 152 | canonical.append(b'0000') 153 | else: 154 | lc = len(c) 155 | if lc > 4: 156 | raise dns.exception.SyntaxError 157 | if lc != 4: 158 | c = (b'0' * (4 - lc)) + c 159 | canonical.append(c) 160 | if l < 8 and not seen_empty: 161 | raise dns.exception.SyntaxError 162 | text = b''.join(canonical) 163 | 164 | # 165 | # Finally we can go to binary. 166 | # 167 | try: 168 | return binascii.unhexlify(text) 169 | except (binascii.Error, TypeError): 170 | raise dns.exception.SyntaxError 171 | 172 | 173 | _mapped_prefix = b'\x00' * 10 + b'\xff\xff' 174 | 175 | 176 | def is_mapped(address): 177 | return address.startswith(_mapped_prefix) 178 | -------------------------------------------------------------------------------- /lib/dnspython/namedict.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 Nominum, Inc. 2 | # Copyright (C) 2016 Coresec Systems AB 3 | # 4 | # Permission to use, copy, modify, and distribute this software and its 5 | # documentation for any purpose with or without fee is hereby granted, 6 | # provided that the above copyright notice and this permission notice 7 | # appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 | # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS" AND CORESEC SYSTEMS AB DISCLAIMS ALL 18 | # WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 19 | # WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CORESEC 20 | # SYSTEMS AB BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR 21 | # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 22 | # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 23 | # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 24 | # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 25 | 26 | """DNS name dictionary""" 27 | 28 | import collections 29 | import dns.name 30 | from ._compat import xrange 31 | 32 | 33 | class NameDict(collections.MutableMapping): 34 | """A dictionary whose keys are dns.name.Name objects. 35 | @ivar max_depth: the maximum depth of the keys that have ever been 36 | added to the dictionary. 37 | @type max_depth: int 38 | @ivar max_depth_items: the number of items of maximum depth 39 | @type max_depth_items: int 40 | """ 41 | 42 | __slots__ = ["max_depth", "max_depth_items", "__store"] 43 | 44 | def __init__(self, *args, **kwargs): 45 | self.__store = dict() 46 | self.max_depth = 0 47 | self.max_depth_items = 0 48 | self.update(dict(*args, **kwargs)) 49 | 50 | def __update_max_depth(self, key): 51 | if len(key) == self.max_depth: 52 | self.max_depth_items = self.max_depth_items + 1 53 | elif len(key) > self.max_depth: 54 | self.max_depth = len(key) 55 | self.max_depth_items = 1 56 | 57 | def __getitem__(self, key): 58 | return self.__store[key] 59 | 60 | def __setitem__(self, key, value): 61 | if not isinstance(key, dns.name.Name): 62 | raise ValueError('NameDict key must be a name') 63 | self.__store[key] = value 64 | self.__update_max_depth(key) 65 | 66 | def __delitem__(self, key): 67 | value = self.__store.pop(key) 68 | if len(value) == self.max_depth: 69 | self.max_depth_items = self.max_depth_items - 1 70 | if self.max_depth_items == 0: 71 | self.max_depth = 0 72 | for k in self.__store: 73 | self.__update_max_depth(k) 74 | 75 | def __iter__(self): 76 | return iter(self.__store) 77 | 78 | def __len__(self): 79 | return len(self.__store) 80 | 81 | def has_key(self, key): 82 | return key in self.__store 83 | 84 | def get_deepest_match(self, name): 85 | """Find the deepest match to I{name} in the dictionary. 86 | 87 | The deepest match is the longest name in the dictionary which is 88 | a superdomain of I{name}. 89 | 90 | @param name: the name 91 | @type name: dns.name.Name object 92 | @rtype: (key, value) tuple 93 | """ 94 | 95 | depth = len(name) 96 | if depth > self.max_depth: 97 | depth = self.max_depth 98 | for i in xrange(-depth, 0): 99 | n = dns.name.Name(name[i:]) 100 | if n in self: 101 | return (n, self[n]) 102 | v = self[dns.name.empty] 103 | return (dns.name.empty, v) 104 | -------------------------------------------------------------------------------- /lib/dnspython/opcode.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2001-2007, 2009-2011 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 Opcodes.""" 17 | 18 | import dns.exception 19 | 20 | QUERY = 0 21 | IQUERY = 1 22 | STATUS = 2 23 | NOTIFY = 4 24 | UPDATE = 5 25 | 26 | _by_text = { 27 | 'QUERY': QUERY, 28 | 'IQUERY': IQUERY, 29 | 'STATUS': STATUS, 30 | 'NOTIFY': NOTIFY, 31 | 'UPDATE': UPDATE 32 | } 33 | 34 | # We construct the inverse mapping programmatically to ensure that we 35 | # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that 36 | # would cause the mapping not to be true inverse. 37 | 38 | _by_value = dict((y, x) for x, y in _by_text.items()) 39 | 40 | 41 | class UnknownOpcode(dns.exception.DNSException): 42 | """An DNS opcode is unknown.""" 43 | 44 | 45 | def from_text(text): 46 | """Convert text into an opcode. 47 | 48 | @param text: the textual opcode 49 | @type text: string 50 | @raises UnknownOpcode: the opcode is unknown 51 | @rtype: int 52 | """ 53 | 54 | if text.isdigit(): 55 | value = int(text) 56 | if value >= 0 and value <= 15: 57 | return value 58 | value = _by_text.get(text.upper()) 59 | if value is None: 60 | raise UnknownOpcode 61 | return value 62 | 63 | 64 | def from_flags(flags): 65 | """Extract an opcode from DNS message flags. 66 | 67 | @param flags: int 68 | @rtype: int 69 | """ 70 | 71 | return (flags & 0x7800) >> 11 72 | 73 | 74 | def to_flags(value): 75 | """Convert an opcode to a value suitable for ORing into DNS message 76 | flags. 77 | @rtype: int 78 | """ 79 | 80 | return (value << 11) & 0x7800 81 | 82 | 83 | def to_text(value): 84 | """Convert an opcode to text. 85 | 86 | @param value: the opcdoe 87 | @type value: int 88 | @raises UnknownOpcode: the opcode is unknown 89 | @rtype: string 90 | """ 91 | 92 | text = _by_value.get(value) 93 | if text is None: 94 | text = str(value) 95 | return text 96 | 97 | 98 | def is_update(flags): 99 | """True if the opcode in flags is UPDATE. 100 | 101 | @param flags: DNS flags 102 | @type flags: int 103 | @rtype: bool 104 | """ 105 | 106 | if (from_flags(flags) == UPDATE): 107 | return True 108 | return False 109 | -------------------------------------------------------------------------------- /lib/dnspython/rcode.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2001-2007, 2009-2011 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 Result Codes.""" 17 | 18 | import dns.exception 19 | from ._compat import long 20 | 21 | NOERROR = 0 22 | FORMERR = 1 23 | SERVFAIL = 2 24 | NXDOMAIN = 3 25 | NOTIMP = 4 26 | REFUSED = 5 27 | YXDOMAIN = 6 28 | YXRRSET = 7 29 | NXRRSET = 8 30 | NOTAUTH = 9 31 | NOTZONE = 10 32 | BADVERS = 16 33 | 34 | _by_text = { 35 | 'NOERROR': NOERROR, 36 | 'FORMERR': FORMERR, 37 | 'SERVFAIL': SERVFAIL, 38 | 'NXDOMAIN': NXDOMAIN, 39 | 'NOTIMP': NOTIMP, 40 | 'REFUSED': REFUSED, 41 | 'YXDOMAIN': YXDOMAIN, 42 | 'YXRRSET': YXRRSET, 43 | 'NXRRSET': NXRRSET, 44 | 'NOTAUTH': NOTAUTH, 45 | 'NOTZONE': NOTZONE, 46 | 'BADVERS': BADVERS 47 | } 48 | 49 | # We construct the inverse mapping programmatically to ensure that we 50 | # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that 51 | # would cause the mapping not to be a true inverse. 52 | 53 | _by_value = dict((y, x) for x, y in _by_text.items()) 54 | 55 | 56 | class UnknownRcode(dns.exception.DNSException): 57 | """A DNS rcode is unknown.""" 58 | 59 | 60 | def from_text(text): 61 | """Convert text into an rcode. 62 | 63 | @param text: the textual rcode 64 | @type text: string 65 | @raises UnknownRcode: the rcode is unknown 66 | @rtype: int 67 | """ 68 | 69 | if text.isdigit(): 70 | v = int(text) 71 | if v >= 0 and v <= 4095: 72 | return v 73 | v = _by_text.get(text.upper()) 74 | if v is None: 75 | raise UnknownRcode 76 | return v 77 | 78 | 79 | def from_flags(flags, ednsflags): 80 | """Return the rcode value encoded by flags and ednsflags. 81 | 82 | @param flags: the DNS flags 83 | @type flags: int 84 | @param ednsflags: the EDNS flags 85 | @type ednsflags: int 86 | @raises ValueError: rcode is < 0 or > 4095 87 | @rtype: int 88 | """ 89 | 90 | value = (flags & 0x000f) | ((ednsflags >> 20) & 0xff0) 91 | if value < 0 or value > 4095: 92 | raise ValueError('rcode must be >= 0 and <= 4095') 93 | return value 94 | 95 | 96 | def to_flags(value): 97 | """Return a (flags, ednsflags) tuple which encodes the rcode. 98 | 99 | @param value: the rcode 100 | @type value: int 101 | @raises ValueError: rcode is < 0 or > 4095 102 | @rtype: (int, int) tuple 103 | """ 104 | 105 | if value < 0 or value > 4095: 106 | raise ValueError('rcode must be >= 0 and <= 4095') 107 | v = value & 0xf 108 | ev = long(value & 0xff0) << 20 109 | return (v, ev) 110 | 111 | 112 | def to_text(value): 113 | """Convert rcode into text. 114 | 115 | @param value: the rcode 116 | @type value: int 117 | @rtype: string 118 | """ 119 | 120 | text = _by_value.get(value) 121 | if text is None: 122 | text = str(value) 123 | return text 124 | -------------------------------------------------------------------------------- /lib/dnspython/rdataclass.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2001-2007, 2009-2011 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 Classes. 17 | 18 | @var _by_text: The rdata class textual name to value mapping 19 | @type _by_text: dict 20 | @var _by_value: The rdata class value to textual name mapping 21 | @type _by_value: dict 22 | @var _metaclasses: If an rdataclass is a metaclass, there will be a mapping 23 | whose key is the rdatatype value and whose value is True in this dictionary. 24 | @type _metaclasses: dict""" 25 | 26 | import re 27 | 28 | import dns.exception 29 | 30 | RESERVED0 = 0 31 | IN = 1 32 | CH = 3 33 | HS = 4 34 | NONE = 254 35 | ANY = 255 36 | 37 | _by_text = { 38 | 'RESERVED0': RESERVED0, 39 | 'IN': IN, 40 | 'CH': CH, 41 | 'HS': HS, 42 | 'NONE': NONE, 43 | 'ANY': ANY 44 | } 45 | 46 | # We construct the inverse mapping programmatically to ensure that we 47 | # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that 48 | # would cause the mapping not to be true inverse. 49 | 50 | _by_value = dict((y, x) for x, y in _by_text.items()) 51 | 52 | # Now that we've built the inverse map, we can add class aliases to 53 | # the _by_text mapping. 54 | 55 | _by_text.update({ 56 | 'INTERNET': IN, 57 | 'CHAOS': CH, 58 | 'HESIOD': HS 59 | }) 60 | 61 | _metaclasses = { 62 | NONE: True, 63 | ANY: True 64 | } 65 | 66 | _unknown_class_pattern = re.compile('CLASS([0-9]+)$', re.I) 67 | 68 | 69 | class UnknownRdataclass(dns.exception.DNSException): 70 | """A DNS class is unknown.""" 71 | 72 | 73 | def from_text(text): 74 | """Convert text into a DNS rdata class value. 75 | @param text: the text 76 | @type text: string 77 | @rtype: int 78 | @raises dns.rdataclass.UnknownRdataclass: the class is unknown 79 | @raises ValueError: the rdata class value is not >= 0 and <= 65535 80 | """ 81 | 82 | value = _by_text.get(text.upper()) 83 | if value is None: 84 | match = _unknown_class_pattern.match(text) 85 | if match is None: 86 | raise UnknownRdataclass 87 | value = int(match.group(1)) 88 | if value < 0 or value > 65535: 89 | raise ValueError("class must be between >= 0 and <= 65535") 90 | return value 91 | 92 | 93 | def to_text(value): 94 | """Convert a DNS rdata class to text. 95 | @param value: the rdata class value 96 | @type value: int 97 | @rtype: string 98 | @raises ValueError: the rdata class value is not >= 0 and <= 65535 99 | """ 100 | 101 | if value < 0 or value > 65535: 102 | raise ValueError("class must be between >= 0 and <= 65535") 103 | text = _by_value.get(value) 104 | if text is None: 105 | text = 'CLASS' + repr(value) 106 | return text 107 | 108 | 109 | def is_metaclass(rdclass): 110 | """True if the class is a metaclass. 111 | @param rdclass: the rdata class 112 | @type rdclass: int 113 | @rtype: bool""" 114 | 115 | if rdclass in _metaclasses: 116 | return True 117 | return False 118 | -------------------------------------------------------------------------------- /lib/dnspython/rdatatype.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2001-2007, 2009-2011 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 23 | whose 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 26 | whose key is the rdatatype value and whose value is True in this dictionary. 27 | @type _singletons: dict""" 28 | 29 | import re 30 | 31 | import dns.exception 32 | 33 | NONE = 0 34 | A = 1 35 | NS = 2 36 | MD = 3 37 | MF = 4 38 | CNAME = 5 39 | SOA = 6 40 | MB = 7 41 | MG = 8 42 | MR = 9 43 | NULL = 10 44 | WKS = 11 45 | PTR = 12 46 | HINFO = 13 47 | MINFO = 14 48 | MX = 15 49 | TXT = 16 50 | RP = 17 51 | AFSDB = 18 52 | X25 = 19 53 | ISDN = 20 54 | RT = 21 55 | NSAP = 22 56 | NSAP_PTR = 23 57 | SIG = 24 58 | KEY = 25 59 | PX = 26 60 | GPOS = 27 61 | AAAA = 28 62 | LOC = 29 63 | NXT = 30 64 | SRV = 33 65 | NAPTR = 35 66 | KX = 36 67 | CERT = 37 68 | A6 = 38 69 | DNAME = 39 70 | OPT = 41 71 | APL = 42 72 | DS = 43 73 | SSHFP = 44 74 | IPSECKEY = 45 75 | RRSIG = 46 76 | NSEC = 47 77 | DNSKEY = 48 78 | DHCID = 49 79 | NSEC3 = 50 80 | NSEC3PARAM = 51 81 | TLSA = 52 82 | HIP = 55 83 | CDS = 59 84 | CDNSKEY = 60 85 | CSYNC = 62 86 | SPF = 99 87 | UNSPEC = 103 88 | EUI48 = 108 89 | EUI64 = 109 90 | TKEY = 249 91 | TSIG = 250 92 | IXFR = 251 93 | AXFR = 252 94 | MAILB = 253 95 | MAILA = 254 96 | ANY = 255 97 | URI = 256 98 | CAA = 257 99 | TA = 32768 100 | DLV = 32769 101 | 102 | _by_text = { 103 | 'NONE': NONE, 104 | 'A': A, 105 | 'NS': NS, 106 | 'MD': MD, 107 | 'MF': MF, 108 | 'CNAME': CNAME, 109 | 'SOA': SOA, 110 | 'MB': MB, 111 | 'MG': MG, 112 | 'MR': MR, 113 | 'NULL': NULL, 114 | 'WKS': WKS, 115 | 'PTR': PTR, 116 | 'HINFO': HINFO, 117 | 'MINFO': MINFO, 118 | 'MX': MX, 119 | 'TXT': TXT, 120 | 'RP': RP, 121 | 'AFSDB': AFSDB, 122 | 'X25': X25, 123 | 'ISDN': ISDN, 124 | 'RT': RT, 125 | 'NSAP': NSAP, 126 | 'NSAP-PTR': NSAP_PTR, 127 | 'SIG': SIG, 128 | 'KEY': KEY, 129 | 'PX': PX, 130 | 'GPOS': GPOS, 131 | 'AAAA': AAAA, 132 | 'LOC': LOC, 133 | 'NXT': NXT, 134 | 'SRV': SRV, 135 | 'NAPTR': NAPTR, 136 | 'KX': KX, 137 | 'CERT': CERT, 138 | 'A6': A6, 139 | 'DNAME': DNAME, 140 | 'OPT': OPT, 141 | 'APL': APL, 142 | 'DS': DS, 143 | 'SSHFP': SSHFP, 144 | 'IPSECKEY': IPSECKEY, 145 | 'RRSIG': RRSIG, 146 | 'NSEC': NSEC, 147 | 'DNSKEY': DNSKEY, 148 | 'DHCID': DHCID, 149 | 'NSEC3': NSEC3, 150 | 'NSEC3PARAM': NSEC3PARAM, 151 | 'TLSA': TLSA, 152 | 'HIP': HIP, 153 | 'CDS': CDS, 154 | 'CDNSKEY': CDNSKEY, 155 | 'CSYNC': CSYNC, 156 | 'SPF': SPF, 157 | 'UNSPEC': UNSPEC, 158 | 'EUI48': EUI48, 159 | 'EUI64': EUI64, 160 | 'TKEY': TKEY, 161 | 'TSIG': TSIG, 162 | 'IXFR': IXFR, 163 | 'AXFR': AXFR, 164 | 'MAILB': MAILB, 165 | 'MAILA': MAILA, 166 | 'ANY': ANY, 167 | 'URI': URI, 168 | 'CAA': CAA, 169 | 'TA': TA, 170 | 'DLV': DLV, 171 | } 172 | 173 | # We construct the inverse mapping programmatically to ensure that we 174 | # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that 175 | # would cause the mapping not to be true inverse. 176 | 177 | _by_value = dict((y, x) for x, y in _by_text.items()) 178 | 179 | _metatypes = { 180 | OPT: True 181 | } 182 | 183 | _singletons = { 184 | SOA: True, 185 | NXT: True, 186 | DNAME: True, 187 | NSEC: True, 188 | # CNAME is technically a singleton, but we allow multiple CNAMEs. 189 | } 190 | 191 | _unknown_type_pattern = re.compile('TYPE([0-9]+)$', re.I) 192 | 193 | 194 | class UnknownRdatatype(dns.exception.DNSException): 195 | """DNS resource record type is unknown.""" 196 | 197 | 198 | def from_text(text): 199 | """Convert text into a DNS rdata type value. 200 | @param text: the text 201 | @type text: string 202 | @raises dns.rdatatype.UnknownRdatatype: the type is unknown 203 | @raises ValueError: the rdata type value is not >= 0 and <= 65535 204 | @rtype: int""" 205 | 206 | value = _by_text.get(text.upper()) 207 | if value is None: 208 | match = _unknown_type_pattern.match(text) 209 | if match is None: 210 | raise UnknownRdatatype 211 | value = int(match.group(1)) 212 | if value < 0 or value > 65535: 213 | raise ValueError("type must be between >= 0 and <= 65535") 214 | return value 215 | 216 | 217 | def to_text(value): 218 | """Convert a DNS rdata type to text. 219 | @param value: the rdata type value 220 | @type value: int 221 | @raises ValueError: the rdata type value is not >= 0 and <= 65535 222 | @rtype: string""" 223 | 224 | if value < 0 or value > 65535: 225 | raise ValueError("type must be between >= 0 and <= 65535") 226 | text = _by_value.get(value) 227 | if text is None: 228 | text = 'TYPE' + repr(value) 229 | return text 230 | 231 | 232 | def is_metatype(rdtype): 233 | """True if the type is a metatype. 234 | @param rdtype: the type 235 | @type rdtype: int 236 | @rtype: bool""" 237 | 238 | if rdtype >= TKEY and rdtype <= ANY or rdtype in _metatypes: 239 | return True 240 | return False 241 | 242 | 243 | def is_singleton(rdtype): 244 | """True if the type is a singleton. 245 | @param rdtype: the type 246 | @type rdtype: int 247 | @rtype: bool""" 248 | 249 | if rdtype in _singletons: 250 | return True 251 | return False 252 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/AFSDB.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.mxbase 17 | 18 | 19 | class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX): 20 | """AFSDB record 21 | 22 | @ivar subtype: the subtype value 23 | @type subtype: int 24 | @ivar hostname: the hostname name 25 | @type hostname: dns.name.Name object""" 26 | 27 | # Use the property mechanism to make "subtype" an alias for the 28 | # "preference" attribute, and "hostname" an alias for the "exchange" 29 | # attribute. 30 | # 31 | # This lets us inherit the UncompressedMX implementation but lets 32 | # the caller use appropriate attribute names for the rdata type. 33 | # 34 | # We probably lose some performance vs. a cut-and-paste 35 | # implementation, but this way we don't copy code, and that's 36 | # good. 37 | 38 | def get_subtype(self): 39 | return self.preference 40 | 41 | def set_subtype(self, subtype): 42 | self.preference = subtype 43 | 44 | subtype = property(get_subtype, set_subtype) 45 | 46 | def get_hostname(self): 47 | return self.exchange 48 | 49 | def set_hostname(self, hostname): 50 | self.exchange = hostname 51 | 52 | hostname = property(get_hostname, set_hostname) 53 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/CERT.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import base64 17 | import io 18 | import struct 19 | 20 | import dns.exception 21 | import dns.dnssec 22 | import dns.rdata 23 | import dns.tokenizer 24 | import dns.util 25 | 26 | _ctype_by_value = { 27 | 1: 'PKIX', 28 | 2: 'SPKI', 29 | 3: 'PGP', 30 | 253: 'URI', 31 | 254: 'OID', 32 | } 33 | 34 | _ctype_by_name = { 35 | 'PKIX': 1, 36 | 'SPKI': 2, 37 | 'PGP': 3, 38 | 'URI': 253, 39 | 'OID': 254, 40 | } 41 | 42 | 43 | def _ctype_from_text(what): 44 | v = _ctype_by_name.get(what) 45 | if not v is None: 46 | return v 47 | return int(what) 48 | 49 | 50 | def _ctype_to_text(what): 51 | v = _ctype_by_value.get(what) 52 | if not v is None: 53 | return v 54 | return str(what) 55 | 56 | 57 | class CERT(dns.rdata.Rdata): 58 | """CERT record 59 | 60 | @ivar certificate_type: certificate type 61 | @type certificate_type: int 62 | @ivar key_tag: key tag 63 | @type key_tag: int 64 | @ivar algorithm: algorithm 65 | @type algorithm: int 66 | @ivar certificate: the certificate or CRL 67 | @type certificate: bytes 68 | @see: RFC 2538""" 69 | 70 | __slots__ = ['certificate_type', 'key_tag', 'algorithm', 'certificate'] 71 | 72 | def __init__(self, rdclass, rdtype, certificate_type, key_tag, algorithm, 73 | certificate): 74 | super(CERT, self).__init__(rdclass, rdtype) 75 | self.certificate_type = certificate_type 76 | self.key_tag = key_tag 77 | self.algorithm = algorithm 78 | self.certificate = certificate 79 | 80 | def to_text(self, origin=None, relativize=True, **kw): 81 | certificate_type = _ctype_to_text(self.certificate_type) 82 | return "%s %d %s %s" % (certificate_type, self.key_tag, 83 | dns.dnssec.algorithm_to_text(self.algorithm), 84 | dns.rdata._base64ify(self.certificate)) 85 | 86 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 87 | certificate_type = _ctype_from_text(tok.get_string()) 88 | key_tag = tok.get_uint16() 89 | algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) 90 | if algorithm < 0 or algorithm > 255: 91 | raise dns.exception.SyntaxError("bad algorithm type") 92 | chunks = [] 93 | while 1: 94 | t = tok.get().unescape() 95 | if t.is_eol_or_eof(): 96 | break 97 | if not t.is_identifier(): 98 | raise dns.exception.SyntaxError 99 | chunks.append(t.value) 100 | b64 = ''.join(chunks) 101 | certificate = base64.b64decode(b64.encode('ascii')) 102 | return cls(rdclass, rdtype, certificate_type, key_tag, 103 | algorithm, certificate) 104 | 105 | from_text = classmethod(from_text) 106 | 107 | def to_wire(self, file, compress=None, origin=None): 108 | prefix = struct.pack("!HHB", self.certificate_type, self.key_tag, 109 | self.algorithm) 110 | file.write(prefix) 111 | file.write(self.certificate) 112 | 113 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 114 | prefix = wire[current: current + 5].unwrap() 115 | current += 5 116 | rdlen -= 5 117 | if rdlen < 0: 118 | raise dns.exception.FormError 119 | (certificate_type, key_tag, algorithm) = struct.unpack("!HHB", prefix) 120 | certificate = wire[current: current + rdlen].unwrap() 121 | return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, 122 | certificate) 123 | 124 | from_wire = classmethod(from_wire) 125 | 126 | def _cmp(self, other): 127 | f = io.BytesIO() 128 | self.to_wire(f) 129 | wire1 = f.getvalue() 130 | f.seek(0) 131 | f.truncate() 132 | other.to_wire(f) 133 | wire2 = f.getvalue() 134 | f.close() 135 | 136 | return dns.util.cmp(wire1, wire2) 137 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/CNAME.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.nsbase 17 | 18 | 19 | class CNAME(dns.rdtypes.nsbase.NSBase): 20 | """CNAME record 21 | 22 | Note: although CNAME is officially a singleton type, dnspython allows 23 | non-singleton CNAME rdatasets because such sets have been commonly 24 | used by BIND and other nameservers for load balancing.""" 25 | pass 26 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/DLV.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009-2011 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 | import dns.rdtypes.dsbase 17 | 18 | 19 | class DLV(dns.rdtypes.dsbase.DSBase): 20 | """DLV record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/DNAME.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.nsbase 17 | 18 | 19 | class DNAME(dns.rdtypes.nsbase.UncompressedNS): 20 | """DNAME record""" 21 | 22 | def to_digestable(self, origin=None): 23 | return self.target.to_digestable(origin) 24 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/DNSKEY.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004-2007, 2009-2011 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 | import base64 17 | import struct 18 | 19 | import dns.exception 20 | import dns.dnssec 21 | import dns.rdata 22 | import dns.util 23 | 24 | # flag constants 25 | SEP = 0x0001 26 | REVOKE = 0x0080 27 | ZONE = 0x0100 28 | 29 | _flag_by_text = { 30 | 'SEP': SEP, 31 | 'REVOKE': REVOKE, 32 | 'ZONE': ZONE 33 | } 34 | 35 | # We construct the inverse mapping programmatically to ensure that we 36 | # cannot make any mistakes (e.g. omissions, cut-and-paste errors) that 37 | # would cause the mapping not to be true inverse. 38 | _flag_by_value = dict([(y, x) for x, y in _flag_by_text.items()]) 39 | 40 | 41 | def flags_to_text_set(flags): 42 | """Convert a DNSKEY flags value to set texts 43 | @rtype: set([string])""" 44 | 45 | flags_set = set() 46 | mask = 0x1 47 | while mask <= 0x8000: 48 | if flags & mask: 49 | text = _flag_by_value.get(mask) 50 | if not text: 51 | text = hex(mask) 52 | flags_set.add(text) 53 | mask <<= 1 54 | return flags_set 55 | 56 | 57 | def flags_from_text_set(texts_set): 58 | """Convert set of DNSKEY flag mnemonic texts to DNSKEY flag value 59 | @rtype: int""" 60 | 61 | flags = 0 62 | for text in texts_set: 63 | try: 64 | flags += _flag_by_text[text] 65 | except KeyError: 66 | raise NotImplementedError( 67 | "DNSKEY flag '%s' is not supported" % text) 68 | return flags 69 | 70 | 71 | class DNSKEY(dns.rdata.Rdata): 72 | """DNSKEY record 73 | 74 | @ivar flags: the key flags 75 | @type flags: int 76 | @ivar protocol: the protocol for which this key may be used 77 | @type protocol: int 78 | @ivar algorithm: the algorithm used for the key 79 | @type algorithm: int 80 | @ivar key: the public key 81 | @type key: string""" 82 | 83 | __slots__ = ['flags', 'protocol', 'algorithm', 'key'] 84 | 85 | def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key): 86 | super(DNSKEY, self).__init__(rdclass, rdtype) 87 | self.flags = flags 88 | self.protocol = protocol 89 | self.algorithm = algorithm 90 | self.key = key 91 | 92 | def to_text(self, origin=None, relativize=True, **kw): 93 | return '%d %d %d %s' % (self.flags, self.protocol, self.algorithm, 94 | dns.rdata._base64ify(self.key)) 95 | 96 | @classmethod 97 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 98 | flags = tok.get_uint16() 99 | protocol = tok.get_uint8() 100 | algorithm = dns.dnssec.algorithm_from_text(tok.get_string()) 101 | chunks = [] 102 | while 1: 103 | t = tok.get().unescape() 104 | if t.is_eol_or_eof(): 105 | break 106 | if not t.is_identifier(): 107 | raise dns.exception.SyntaxError 108 | chunks.append(t.value) 109 | b64 = ''.join(chunks) 110 | key = base64.b64decode(b64.encode('ascii')) 111 | return cls(rdclass, rdtype, flags, protocol, algorithm, key) 112 | 113 | def to_wire(self, file, compress=None, origin=None): 114 | header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) 115 | file.write(header) 116 | file.write(self.key) 117 | 118 | @classmethod 119 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 120 | if rdlen < 4: 121 | raise dns.exception.FormError 122 | header = struct.unpack('!HBB', wire[current: current + 4]) 123 | current += 4 124 | rdlen -= 4 125 | key = wire[current: current + rdlen].unwrap() 126 | return cls(rdclass, rdtype, header[0], header[1], header[2], 127 | key) 128 | 129 | def _cmp(self, other): 130 | hs = struct.pack("!HBB", self.flags, self.protocol, self.algorithm) 131 | ho = struct.pack("!HBB", other.flags, other.protocol, other.algorithm) 132 | v = dns.util.cmp(hs, ho) 133 | if v == 0: 134 | v = dns.util.cmp(self.key, other.key) 135 | return v 136 | 137 | def flags_to_text_set(self): 138 | """Convert a DNSKEY flags value to set texts 139 | @rtype: set([string])""" 140 | return flags_to_text_set(self.flags) 141 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/DS.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.dsbase 17 | 18 | 19 | class DS(dns.rdtypes.dsbase.DSBase): 20 | """DS record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/GPOS.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.rdata 18 | import dns.tokenizer 19 | import dns.util 20 | 21 | 22 | def _validate_float_string(what): 23 | if what[0] == '-' or what[0] == '+': 24 | what = what[1:] 25 | if what.isdigit(): 26 | return 27 | (left, right) = what.split('.') 28 | if left == '' and right == '': 29 | raise dns.exception.FormError 30 | if not left == '' and not left.isdigit(): 31 | raise dns.exception.FormError 32 | if not right == '' and not right.isdigit(): 33 | raise dns.exception.FormError 34 | 35 | 36 | class GPOS(dns.rdata.Rdata): 37 | """GPOS record 38 | 39 | @ivar latitude: latitude 40 | @type latitude: string 41 | @ivar longitude: longitude 42 | @type longitude: string 43 | @ivar altitude: altitude 44 | @type altitude: string 45 | @see: RFC 1712""" 46 | 47 | __slots__ = ['latitude', 'longitude', 'altitude'] 48 | 49 | def __init__(self, rdclass, rdtype, latitude, longitude, altitude): 50 | super(GPOS, self).__init__(rdclass, rdtype) 51 | if isinstance(latitude, float) or \ 52 | isinstance(latitude, int): 53 | latitude = str(latitude) 54 | if isinstance(longitude, float) or \ 55 | isinstance(longitude, int): 56 | longitude = str(longitude) 57 | if isinstance(altitude, float) or \ 58 | isinstance(altitude, int): 59 | altitude = str(altitude) 60 | _validate_float_string(latitude) 61 | _validate_float_string(longitude) 62 | _validate_float_string(altitude) 63 | self.latitude = latitude 64 | self.longitude = longitude 65 | self.altitude = altitude 66 | 67 | def to_text(self, origin=None, relativize=True, **kw): 68 | return '%s %s %s' % (self.latitude, self.longitude, self.altitude) 69 | 70 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 71 | latitude = tok.get_string() 72 | longitude = tok.get_string() 73 | altitude = tok.get_string() 74 | tok.get_eol() 75 | return cls(rdclass, rdtype, latitude, longitude, altitude) 76 | 77 | from_text = classmethod(from_text) 78 | 79 | def to_wire(self, file, compress=None, origin=None): 80 | l = len(self.latitude) 81 | assert l < 256 82 | dns.util.write_uint8(file, l) 83 | file.write(self.latitude.encode('latin_1')) 84 | l = len(self.longitude) 85 | assert l < 256 86 | dns.util.write_uint8(file, l) 87 | file.write(self.longitude.encode('latin_1')) 88 | l = len(self.altitude) 89 | assert l < 256 90 | dns.util.write_uint8(file, l) 91 | file.write(self.altitude.encode('latin_1')) 92 | 93 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 94 | l = wire[current] 95 | current += 1 96 | rdlen -= 1 97 | if l > rdlen: 98 | raise dns.exception.FormError 99 | latitude = wire[current: current + l].decode('latin_1') 100 | current += l 101 | rdlen -= l 102 | l = wire[current] 103 | current += 1 104 | rdlen -= 1 105 | if l > rdlen: 106 | raise dns.exception.FormError 107 | longitude = wire[current: current + l].decode('latin_1') 108 | current += l 109 | rdlen -= l 110 | l = wire[current] 111 | current += 1 112 | rdlen -= 1 113 | if l != rdlen: 114 | raise dns.exception.FormError 115 | altitude = wire[current: current + l].decode('latin_1') 116 | return cls(rdclass, rdtype, latitude, longitude, altitude) 117 | 118 | from_wire = classmethod(from_wire) 119 | 120 | def _cmp(self, other): 121 | v = dns.util.cmp(self.latitude, other.latitude) 122 | if v == 0: 123 | v = dns.util.cmp(self.longitude, other.longitude) 124 | if v == 0: 125 | v = dns.util.cmp(self.altitude, other.altitude) 126 | return v 127 | 128 | def _get_float_latitude(self): 129 | return float(self.latitude) 130 | 131 | def _set_float_latitude(self, value): 132 | self.latitude = str(value) 133 | 134 | float_latitude = property(_get_float_latitude, _set_float_latitude, 135 | doc="latitude as a floating point value") 136 | 137 | def _get_float_longitude(self): 138 | return float(self.longitude) 139 | 140 | def _set_float_longitude(self, value): 141 | self.longitude = str(value) 142 | 143 | float_longitude = property(_get_float_longitude, _set_float_longitude, 144 | doc="longitude as a floating point value") 145 | 146 | def _get_float_altitude(self): 147 | return float(self.altitude) 148 | 149 | def _set_float_altitude(self, value): 150 | self.altitude = str(value) 151 | 152 | float_altitude = property(_get_float_altitude, _set_float_altitude, 153 | doc="altitude as a floating point value") 154 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/HINFO.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.rdata 18 | import dns.tokenizer 19 | import dns.util 20 | 21 | 22 | class HINFO(dns.rdata.Rdata): 23 | """HINFO record 24 | 25 | @ivar cpu: the CPU type 26 | @type cpu: string 27 | @ivar os: the OS type 28 | @type os: string 29 | @see: RFC 1035""" 30 | 31 | __slots__ = ['cpu', 'os'] 32 | 33 | def __init__(self, rdclass, rdtype, cpu, os): 34 | super(HINFO, self).__init__(rdclass, rdtype) 35 | self.cpu = cpu 36 | self.os = os 37 | 38 | def to_text(self, origin=None, relativize=True, **kw): 39 | return '"%s" "%s"' % (dns.rdata._escapify(self.cpu), 40 | dns.rdata._escapify(self.os)) 41 | 42 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 43 | cpu = tok.get_string() 44 | os = tok.get_string() 45 | tok.get_eol() 46 | return cls(rdclass, rdtype, cpu, os) 47 | 48 | from_text = classmethod(from_text) 49 | 50 | def to_wire(self, file, compress=None, origin=None): 51 | l = len(self.cpu) 52 | assert l < 256 53 | dns.util.write_uint8(file, l) 54 | file.write(self.cpu.encode('latin_1')) 55 | l = len(self.os) 56 | assert l < 256 57 | dns.util.write_uint8(file, l) 58 | file.write(self.os.encode('latin_1')) 59 | 60 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 61 | l = wire[current] 62 | current += 1 63 | rdlen -= 1 64 | if l > rdlen: 65 | raise dns.exception.FormError 66 | cpu = wire[current: current + l].decode('latin_1') 67 | current += l 68 | rdlen -= l 69 | l = wire[current] 70 | current += 1 71 | rdlen -= 1 72 | if l != rdlen: 73 | raise dns.exception.FormError 74 | os = wire[current: current + l].decode('latin_1') 75 | return cls(rdclass, rdtype, cpu, os) 76 | 77 | from_wire = classmethod(from_wire) 78 | 79 | def _cmp(self, other): 80 | v = dns.util.cmp(self.cpu, other.cpu) 81 | if v == 0: 82 | v = dns.util.cmp(self.os, other.os) 83 | return v 84 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/HIP.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010, 2011 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 | import base64 17 | import io 18 | import string 19 | import struct 20 | 21 | import dns.exception 22 | import dns.rdata 23 | import dns.rdatatype 24 | import dns.util 25 | 26 | 27 | class HIP(dns.rdata.Rdata): 28 | """HIP record 29 | 30 | @ivar hit: the host identity tag 31 | @type hit: bytes 32 | @ivar algorithm: the public key cryptographic algorithm 33 | @type algorithm: int 34 | @ivar key: the public key 35 | @type key: bytes 36 | @ivar servers: the rendezvous servers 37 | @type servers: list of dns.name.Name objects 38 | @see: RFC 5205""" 39 | 40 | __slots__ = ['hit', 'algorithm', 'key', 'servers'] 41 | 42 | def __init__(self, rdclass, rdtype, hit, algorithm, key, servers): 43 | super(HIP, self).__init__(rdclass, rdtype) 44 | self.hit = hit 45 | self.algorithm = algorithm 46 | self.key = key 47 | self.servers = servers 48 | 49 | def to_text(self, origin=None, relativize=True, **kw): 50 | hit = base64.b16encode(self.hit).decode('ascii').lower() 51 | key = base64.b64encode(self.key).decode('ascii') 52 | text = '' 53 | servers = [] 54 | for server in self.servers: 55 | servers.append(str(server.choose_relativity(origin, relativize))) 56 | if len(servers) > 0: 57 | text += (' ' + ' '.join(servers)) 58 | return '%u %s %s%s' % (self.algorithm, hit, key, text) 59 | 60 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 61 | algorithm = tok.get_uint8() 62 | hit = bytes.fromhex(tok.get_string()) 63 | if len(hit) > 255: 64 | raise dns.exception.SyntaxError("HIT too long") 65 | key = base64.b64decode(tok.get_string().encode('ascii')) 66 | servers = [] 67 | while 1: 68 | token = tok.get() 69 | if token.is_eol_or_eof(): 70 | break 71 | server = dns.name.from_text(token.value, origin) 72 | server.choose_relativity(origin, relativize) 73 | servers.append(server) 74 | return cls(rdclass, rdtype, hit, algorithm, key, servers) 75 | 76 | from_text = classmethod(from_text) 77 | 78 | def to_wire(self, file, compress=None, origin=None): 79 | lh = len(self.hit) 80 | lk = len(self.key) 81 | file.write(struct.pack("!BBH", lh, self.algorithm, lk)) 82 | file.write(self.hit) 83 | file.write(self.key) 84 | for server in self.servers: 85 | server.to_wire(file, None, origin) 86 | 87 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 88 | (lh, algorithm, lk) = struct.unpack('!BBH', 89 | wire[current: current + 4]) 90 | current += 4 91 | rdlen -= 4 92 | hit = wire[current: current + lh].unwrap() 93 | current += lh 94 | rdlen -= lh 95 | key = wire[current: current + lk].unwrap() 96 | current += lk 97 | rdlen -= lk 98 | servers = [] 99 | while rdlen > 0: 100 | (server, cused) = dns.name.from_wire(wire[: current + rdlen], 101 | current) 102 | current += cused 103 | rdlen -= cused 104 | if not origin is None: 105 | server = server.relativize(origin) 106 | servers.append(server) 107 | return cls(rdclass, rdtype, hit, algorithm, key, servers) 108 | 109 | from_wire = classmethod(from_wire) 110 | 111 | def choose_relativity(self, origin=None, relativize=True): 112 | servers = [] 113 | for server in self.servers: 114 | server = server.choose_relativity(origin, relativize) 115 | servers.append(server) 116 | self.servers = servers 117 | 118 | def _cmp(self, other): 119 | b1 = io.BytesIO() 120 | lh = len(self.hit) 121 | lk = len(self.key) 122 | b1.write(struct.pack("!BBH", lh, self.algorithm, lk)) 123 | b1.write(self.hit) 124 | b1.write(self.key) 125 | b2 = io.BytesIO() 126 | lh = len(other.hit) 127 | lk = len(other.key) 128 | b2.write(struct.pack("!BBH", lh, other.algorithm, lk)) 129 | b2.write(other.hit) 130 | b2.write(other.key) 131 | v = dns.util.cmp(b1.getvalue(), b2.getvalue()) 132 | if v != 0: 133 | return v 134 | ls = len(self.servers) 135 | lo = len(other.servers) 136 | count = min(ls, lo) 137 | i = 0 138 | while i < count: 139 | v = dns.util.cmp(self.servers[i], other.servers[i]) 140 | if v != 0: 141 | return v 142 | i += 1 143 | return ls - lo 144 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/ISDN.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.rdata 18 | import dns.tokenizer 19 | import dns.util 20 | 21 | 22 | class ISDN(dns.rdata.Rdata): 23 | """ISDN record 24 | 25 | @ivar address: the ISDN address 26 | @type address: bytes 27 | @ivar subaddress: the ISDN subaddress (or '' if not present) 28 | @type subaddress: bytes 29 | @see: RFC 1183""" 30 | 31 | __slots__ = ['address', 'subaddress'] 32 | 33 | def __init__(self, rdclass, rdtype, address, subaddress): 34 | super(ISDN, self).__init__(rdclass, rdtype) 35 | self.address = address 36 | self.subaddress = subaddress 37 | 38 | def to_text(self, origin=None, relativize=True, **kw): 39 | if self.subaddress: 40 | return '"%s" "%s"' % (dns.rdata._escapify(self.address), 41 | dns.rdata._escapify(self.subaddress)) 42 | else: 43 | return '"%s"' % dns.rdata._escapify(self.address) 44 | 45 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 46 | address = tok.get_string().encode('ascii') 47 | t = tok.get() 48 | if not t.is_eol_or_eof(): 49 | tok.unget(t) 50 | subaddress = tok.get_string().encode('ascii') 51 | else: 52 | tok.unget(t) 53 | subaddress = b'' 54 | tok.get_eol() 55 | return cls(rdclass, rdtype, address, subaddress) 56 | 57 | from_text = classmethod(from_text) 58 | 59 | def to_wire(self, file, compress=None, origin=None): 60 | l = len(self.address) 61 | assert l < 256 62 | dns.util.write_uint8(file, l) 63 | file.write(self.address) 64 | l = len(self.subaddress) 65 | if l > 0: 66 | assert l < 256 67 | dns.util.write_uint8(file, l) 68 | file.write(self.subaddress) 69 | 70 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 71 | l = wire[current] 72 | current += 1 73 | rdlen -= 1 74 | if l > rdlen: 75 | raise dns.exception.FormError 76 | address = wire[current: current + l].unwrap() 77 | current += l 78 | rdlen -= l 79 | if rdlen > 0: 80 | l = wire[current] 81 | current += 1 82 | rdlen -= 1 83 | if l != rdlen: 84 | raise dns.exception.FormError 85 | subaddress = wire[current: current + l].unwrap() 86 | else: 87 | subaddress = b'' 88 | return cls(rdclass, rdtype, address, subaddress) 89 | 90 | from_wire = classmethod(from_wire) 91 | 92 | def _cmp(self, other): 93 | v = dns.util.cmp(self.address, other.address) 94 | if v == 0: 95 | v = dns.util.cmp(self.subaddress, other.subaddress) 96 | return v 97 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/MX.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.mxbase 17 | 18 | 19 | class MX(dns.rdtypes.mxbase.MXBase): 20 | """MX record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/NS.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.nsbase 17 | 18 | 19 | class NS(dns.rdtypes.nsbase.NSBase): 20 | """NS record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/NSEC.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004-2007, 2009-2011 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 | import io 17 | 18 | import dns.exception 19 | import dns.rdata 20 | import dns.rdatatype 21 | import dns.name 22 | import dns.util 23 | 24 | 25 | class NSEC(dns.rdata.Rdata): 26 | """NSEC record 27 | 28 | @ivar next: the next name 29 | @type next: dns.name.Name object 30 | @ivar windows: the windowed bitmap list 31 | @type windows: list of (window number, bytes) tuples""" 32 | 33 | __slots__ = ['next', 'windows'] 34 | 35 | def __init__(self, rdclass, rdtype, next, windows): 36 | super(NSEC, self).__init__(rdclass, rdtype) 37 | self.next = next 38 | self.windows = windows 39 | 40 | def to_text(self, origin=None, relativize=True, **kw): 41 | next = self.next.choose_relativity(origin, relativize) 42 | text = '' 43 | for (window, bitmap) in self.windows: 44 | bits = [] 45 | for i in range(0, len(bitmap)): 46 | byte = bitmap[i] 47 | for j in range(0, 8): 48 | if byte & (0x80 >> j): 49 | bits.append(dns.rdatatype.to_text(window * 256 + \ 50 | i * 8 + j)) 51 | text += (' ' + ' '.join(bits)) 52 | return '%s%s' % (next, text) 53 | 54 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 55 | next = tok.get_name() 56 | next = next.choose_relativity(origin, relativize) 57 | rdtypes = [] 58 | while 1: 59 | token = tok.get().unescape() 60 | if token.is_eol_or_eof(): 61 | break 62 | nrdtype = dns.rdatatype.from_text(token.value) 63 | if nrdtype == 0: 64 | raise dns.exception.SyntaxError("NSEC with bit 0") 65 | if nrdtype > 65535: 66 | raise dns.exception.SyntaxError("NSEC with bit > 65535") 67 | rdtypes.append(nrdtype) 68 | rdtypes.sort() 69 | window = 0 70 | octets = 0 71 | prior_rdtype = 0 72 | bitmap = bytearray(32) 73 | windows = [] 74 | for nrdtype in rdtypes: 75 | if nrdtype == prior_rdtype: 76 | continue 77 | prior_rdtype = nrdtype 78 | new_window = nrdtype // 256 79 | if new_window != window: 80 | windows.append((window, bytes(bitmap[0:octets]))) 81 | bitmap = bytearray(32) 82 | window = new_window 83 | offset = nrdtype % 256 84 | byte = offset // 8 85 | bit = offset % 8 86 | octets = byte + 1 87 | bitmap[byte] = bitmap[byte] | (0x80 >> bit) 88 | windows.append((window, bytes(bitmap[0:octets]))) 89 | return cls(rdclass, rdtype, next, windows) 90 | 91 | from_text = classmethod(from_text) 92 | 93 | def to_wire(self, file, compress=None, origin=None): 94 | self.next.to_wire(file, None, origin) 95 | for (window, bitmap) in self.windows: 96 | dns.util.write_uint8(file, window) 97 | dns.util.write_uint8(file, len(bitmap)) 98 | file.write(bitmap) 99 | 100 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 101 | (next, cused) = dns.name.from_wire(wire[: current + rdlen], current) 102 | current += cused 103 | rdlen -= cused 104 | windows = [] 105 | while rdlen > 0: 106 | if rdlen < 3: 107 | raise dns.exception.FormError("NSEC too short") 108 | window = wire[current] 109 | octets = wire[current + 1] 110 | if octets == 0 or octets > 32: 111 | raise dns.exception.FormError("bad NSEC octets") 112 | current += 2 113 | rdlen -= 2 114 | if rdlen < octets: 115 | raise dns.exception.FormError("bad NSEC bitmap length") 116 | bitmap = wire[current: current + octets].unwrap() 117 | current += octets 118 | rdlen -= octets 119 | windows.append((window, bitmap)) 120 | if not origin is None: 121 | next = next.relativize(origin) 122 | return cls(rdclass, rdtype, next, windows) 123 | 124 | from_wire = classmethod(from_wire) 125 | 126 | def choose_relativity(self, origin=None, relativize=True): 127 | self.next = self.next.choose_relativity(origin, relativize) 128 | 129 | def _cmp(self, other): 130 | return self._wire_cmp(other) 131 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/NSEC3PARAM.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2004-2007, 2009-2011 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 | import base64 17 | import io 18 | import struct 19 | 20 | import dns.exception 21 | import dns.rdata 22 | import dns.util 23 | 24 | 25 | class NSEC3PARAM(dns.rdata.Rdata): 26 | """NSEC3PARAM record 27 | 28 | @ivar algorithm: the hash algorithm number 29 | @type algorithm: int 30 | @ivar flags: the flags 31 | @type flags: int 32 | @ivar iterations: the number of iterations 33 | @type iterations: int 34 | @ivar salt: the salt 35 | @type salt: bytes""" 36 | 37 | __slots__ = ['algorithm', 'flags', 'iterations', 'salt'] 38 | 39 | def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt): 40 | super(NSEC3PARAM, self).__init__(rdclass, rdtype) 41 | self.algorithm = algorithm 42 | self.flags = flags 43 | self.iterations = iterations 44 | self.salt = salt 45 | 46 | def to_text(self, origin=None, relativize=True, **kw): 47 | if self.salt == b'': 48 | salt = '-' 49 | else: 50 | salt = base64.b16encode(self.salt).decode('ascii').lower() 51 | return '%u %u %u %s' % (self.algorithm, self.flags, self.iterations, salt) 52 | 53 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 54 | algorithm = tok.get_uint8() 55 | flags = tok.get_uint8() 56 | iterations = tok.get_uint16() 57 | salt = tok.get_string() 58 | if salt == '-': 59 | salt = b'' 60 | else: 61 | salt = bytes.fromhex(salt) 62 | tok.get_eol() 63 | return cls(rdclass, rdtype, algorithm, flags, iterations, salt) 64 | 65 | from_text = classmethod(from_text) 66 | 67 | def to_wire(self, file, compress=None, origin=None): 68 | l = len(self.salt) 69 | file.write(struct.pack("!BBHB", self.algorithm, self.flags, 70 | self.iterations, l)) 71 | file.write(self.salt) 72 | 73 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 74 | (algorithm, flags, iterations, slen) = struct.unpack('!BBHB', 75 | wire[current: current + 5]) 76 | current += 5 77 | rdlen -= 5 78 | salt = wire[current: current + slen].unwrap() 79 | current += slen 80 | rdlen -= slen 81 | if rdlen != 0: 82 | raise dns.exception.FormError 83 | return cls(rdclass, rdtype, algorithm, flags, iterations, salt) 84 | 85 | from_wire = classmethod(from_wire) 86 | 87 | def _cmp(self, other): 88 | return self._wire_cmp(other) 89 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/PTR.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.nsbase 17 | 18 | 19 | class PTR(dns.rdtypes.nsbase.NSBase): 20 | """PTR record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/RP.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.rdata 18 | import dns.name 19 | import dns.util 20 | 21 | 22 | class RP(dns.rdata.Rdata): 23 | """RP record 24 | 25 | @ivar mbox: The responsible person's mailbox 26 | @type mbox: dns.name.Name object 27 | @ivar txt: The owner name of a node with TXT records, or the root name 28 | if no TXT records are associated with this RP. 29 | @type txt: dns.name.Name object 30 | @see: RFC 1183""" 31 | 32 | __slots__ = ['mbox', 'txt'] 33 | 34 | def __init__(self, rdclass, rdtype, mbox, txt): 35 | super(RP, self).__init__(rdclass, rdtype) 36 | self.mbox = mbox 37 | self.txt = txt 38 | 39 | def to_text(self, origin=None, relativize=True, **kw): 40 | mbox = self.mbox.choose_relativity(origin, relativize) 41 | txt = self.txt.choose_relativity(origin, relativize) 42 | return "%s %s" % (str(mbox), str(txt)) 43 | 44 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 45 | mbox = tok.get_name() 46 | txt = tok.get_name() 47 | mbox = mbox.choose_relativity(origin, relativize) 48 | txt = txt.choose_relativity(origin, relativize) 49 | tok.get_eol() 50 | return cls(rdclass, rdtype, mbox, txt) 51 | 52 | from_text = classmethod(from_text) 53 | 54 | def to_wire(self, file, compress=None, origin=None): 55 | self.mbox.to_wire(file, None, origin) 56 | self.txt.to_wire(file, None, origin) 57 | 58 | def to_digestable(self, origin=None): 59 | return self.mbox.to_digestable(origin) + \ 60 | self.txt.to_digestable(origin) 61 | 62 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 63 | (mbox, cused) = dns.name.from_wire(wire[: current + rdlen], 64 | current) 65 | current += cused 66 | rdlen -= cused 67 | if rdlen <= 0: 68 | raise dns.exception.FormError 69 | (txt, cused) = dns.name.from_wire(wire[: current + rdlen], 70 | current) 71 | if cused != rdlen: 72 | raise dns.exception.FormError 73 | if not origin is None: 74 | mbox = mbox.relativize(origin) 75 | txt = txt.relativize(origin) 76 | return cls(rdclass, rdtype, mbox, txt) 77 | 78 | from_wire = classmethod(from_wire) 79 | 80 | def choose_relativity(self, origin=None, relativize=True): 81 | self.mbox = self.mbox.choose_relativity(origin, relativize) 82 | self.txt = self.txt.choose_relativity(origin, relativize) 83 | 84 | def _cmp(self, other): 85 | v = dns.util.cmp(self.mbox, other.mbox) 86 | if v == 0: 87 | v = dns.util.cmp(self.txt, other.txt) 88 | return v 89 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/RT.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.mxbase 17 | 18 | 19 | class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX): 20 | """RT record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/SOA.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import struct 17 | 18 | import dns.exception 19 | import dns.rdata 20 | import dns.name 21 | import dns.util 22 | 23 | 24 | class SOA(dns.rdata.Rdata): 25 | """SOA record 26 | 27 | @ivar mname: the SOA MNAME (master name) field 28 | @type mname: dns.name.Name object 29 | @ivar rname: the SOA RNAME (responsible name) field 30 | @type rname: dns.name.Name object 31 | @ivar serial: The zone's serial number 32 | @type serial: int 33 | @ivar refresh: The zone's refresh value (in seconds) 34 | @type refresh: int 35 | @ivar retry: The zone's retry value (in seconds) 36 | @type retry: int 37 | @ivar expire: The zone's expiration value (in seconds) 38 | @type expire: int 39 | @ivar minimum: The zone's negative caching time (in seconds, called 40 | "minimum" for historical reasons) 41 | @type minimum: int 42 | @see: RFC 1035""" 43 | 44 | __slots__ = ['mname', 'rname', 'serial', 'refresh', 'retry', 'expire', 45 | 'minimum'] 46 | 47 | def __init__(self, rdclass, rdtype, mname, rname, serial, refresh, retry, 48 | expire, minimum): 49 | super(SOA, self).__init__(rdclass, rdtype) 50 | self.mname = mname 51 | self.rname = rname 52 | self.serial = serial 53 | self.refresh = refresh 54 | self.retry = retry 55 | self.expire = expire 56 | self.minimum = minimum 57 | 58 | def to_text(self, origin=None, relativize=True, **kw): 59 | mname = self.mname.choose_relativity(origin, relativize) 60 | rname = self.rname.choose_relativity(origin, relativize) 61 | return '%s %s %d %d %d %d %d' % ( 62 | mname, rname, self.serial, self.refresh, self.retry, 63 | self.expire, self.minimum) 64 | 65 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 66 | mname = tok.get_name() 67 | rname = tok.get_name() 68 | mname = mname.choose_relativity(origin, relativize) 69 | rname = rname.choose_relativity(origin, relativize) 70 | serial = tok.get_uint32() 71 | refresh = tok.get_ttl() 72 | retry = tok.get_ttl() 73 | expire = tok.get_ttl() 74 | minimum = tok.get_ttl() 75 | tok.get_eol() 76 | return cls(rdclass, rdtype, mname, rname, serial, refresh, retry, 77 | expire, minimum) 78 | 79 | from_text = classmethod(from_text) 80 | 81 | def to_wire(self, file, compress=None, origin=None): 82 | self.mname.to_wire(file, compress, origin) 83 | self.rname.to_wire(file, compress, origin) 84 | five_ints = struct.pack('!IIIII', self.serial, self.refresh, 85 | self.retry, self.expire, self.minimum) 86 | file.write(five_ints) 87 | 88 | def to_digestable(self, origin=None): 89 | return self.mname.to_digestable(origin) + \ 90 | self.rname.to_digestable(origin) + \ 91 | struct.pack('!IIIII', self.serial, self.refresh, 92 | self.retry, self.expire, self.minimum) 93 | 94 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 95 | (mname, cused) = dns.name.from_wire(wire[: current + rdlen], current) 96 | current += cused 97 | rdlen -= cused 98 | (rname, cused) = dns.name.from_wire(wire[: current + rdlen], current) 99 | current += cused 100 | rdlen -= cused 101 | if rdlen != 20: 102 | raise dns.exception.FormError 103 | five_ints = struct.unpack('!IIIII', 104 | wire[current: current + rdlen]) 105 | if not origin is None: 106 | mname = mname.relativize(origin) 107 | rname = rname.relativize(origin) 108 | return cls(rdclass, rdtype, mname, rname, 109 | five_ints[0], five_ints[1], five_ints[2], five_ints[3], 110 | five_ints[4]) 111 | 112 | from_wire = classmethod(from_wire) 113 | 114 | def choose_relativity(self, origin=None, relativize=True): 115 | self.mname = self.mname.choose_relativity(origin, relativize) 116 | self.rname = self.rname.choose_relativity(origin, relativize) 117 | 118 | def _cmp(self, other): 119 | v = dns.util.cmp(self.mname, other.mname) 120 | if v == 0: 121 | v = dns.util.cmp(self.rname, other.rname) 122 | if v == 0: 123 | self_ints = struct.pack('!IIIII', self.serial, self.refresh, 124 | self.retry, self.expire, self.minimum) 125 | other_ints = struct.pack('!IIIII', other.serial, other.refresh, 126 | other.retry, other.expire, 127 | other.minimum) 128 | v = dns.util.cmp(self_ints, other_ints) 129 | return v 130 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/SPF.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006, 2007, 2009-2011 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 | import dns.rdtypes.txtbase 17 | 18 | 19 | class SPF(dns.rdtypes.txtbase.TXTBase): 20 | """SPF record 21 | 22 | @see: RFC 4408""" 23 | pass 24 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/SSHFP.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2005-2007, 2009-2011 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 | import struct 17 | 18 | import dns.rdata 19 | import dns.rdatatype 20 | import dns.util 21 | 22 | 23 | class SSHFP(dns.rdata.Rdata): 24 | """SSHFP record 25 | 26 | @ivar algorithm: the algorithm 27 | @type algorithm: int 28 | @ivar fp_type: the digest type 29 | @type fp_type: int 30 | @ivar fingerprint: the fingerprint 31 | @type fingerprint: bytes 32 | @see: draft-ietf-secsh-dns-05.txt""" 33 | 34 | __slots__ = ['algorithm', 'fp_type', 'fingerprint'] 35 | 36 | def __init__(self, rdclass, rdtype, algorithm, fp_type, 37 | fingerprint): 38 | super(SSHFP, self).__init__(rdclass, rdtype) 39 | self.algorithm = algorithm 40 | self.fp_type = fp_type 41 | self.fingerprint = fingerprint 42 | 43 | def to_text(self, origin=None, relativize=True, **kw): 44 | return '%d %d %s' % (self.algorithm, 45 | self.fp_type, 46 | dns.rdata._hexify(self.fingerprint, 47 | chunksize=128)) 48 | 49 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 50 | algorithm = tok.get_uint8() 51 | fp_type = tok.get_uint8() 52 | chunks = [] 53 | while 1: 54 | t = tok.get().unescape() 55 | if t.is_eol_or_eof(): 56 | break 57 | if not t.is_identifier(): 58 | raise dns.exception.SyntaxError 59 | chunks.append(t.value) 60 | hex = ''.join(chunks) 61 | fingerprint = bytes.fromhex(hex) 62 | return cls(rdclass, rdtype, algorithm, fp_type, fingerprint) 63 | 64 | from_text = classmethod(from_text) 65 | 66 | def to_wire(self, file, compress=None, origin=None): 67 | header = struct.pack("!BB", self.algorithm, self.fp_type) 68 | file.write(header) 69 | file.write(self.fingerprint) 70 | 71 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 72 | header = struct.unpack("!BB", wire[current: current + 2]) 73 | current += 2 74 | rdlen -= 2 75 | fingerprint = wire[current: current + rdlen].unwrap() 76 | return cls(rdclass, rdtype, header[0], header[1], fingerprint) 77 | 78 | from_wire = classmethod(from_wire) 79 | 80 | def _cmp(self, other): 81 | hs = struct.pack("!BB", self.algorithm, self.fp_type) 82 | ho = struct.pack("!BB", other.algorithm, other.fp_type) 83 | v = dns.util.cmp(hs, ho) 84 | if v == 0: 85 | v = dns.util.cmp(self.fingerprint, other.fingerprint) 86 | return v 87 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/TLSA.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2005-2007, 2009-2013 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 | import struct 17 | 18 | import dns.rdata 19 | import dns.rdatatype 20 | import dns.util 21 | 22 | 23 | class TLSA(dns.rdata.Rdata): 24 | """TLSA record 25 | 26 | @ivar usage: The certificate usage 27 | @type usage: int 28 | @ivar selector: The selector field 29 | @type selector: int 30 | @ivar mtype: The 'matching type' field 31 | @type mtype: int 32 | @ivar cert: The 'Certificate Association Data' field 33 | @type cert: bytes 34 | @see: RFC 6698""" 35 | 36 | __slots__ = ['usage', 'selector', 'mtype', 'cert'] 37 | 38 | def __init__(self, rdclass, rdtype, usage, selector, 39 | mtype, cert): 40 | super(TLSA, self).__init__(rdclass, rdtype) 41 | self.usage = usage 42 | self.selector = selector 43 | self.mtype = mtype 44 | self.cert = cert 45 | 46 | def to_text(self, origin=None, relativize=True, **kw): 47 | return '%d %d %d %s' % (self.usage, 48 | self.selector, 49 | self.mtype, 50 | dns.rdata._hexify(self.cert, 51 | chunksize=128)) 52 | 53 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 54 | usage = tok.get_uint8() 55 | selector = tok.get_uint8() 56 | mtype = tok.get_uint8() 57 | cert_chunks = [] 58 | while 1: 59 | t = tok.get().unescape() 60 | if t.is_eol_or_eof(): 61 | break 62 | if not t.is_identifier(): 63 | raise dns.exception.SyntaxError 64 | cert_chunks.append(t.value) 65 | hex = ''.join(cert_chunks) 66 | cert = bytes.fromhex(hex) 67 | return cls(rdclass, rdtype, usage, selector, mtype, cert) 68 | 69 | from_text = classmethod(from_text) 70 | 71 | def to_wire(self, file, compress=None, origin=None): 72 | header = struct.pack("!BBB", self.usage, self.selector, self.mtype) 73 | file.write(header) 74 | file.write(self.cert) 75 | 76 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 77 | header = struct.unpack("!BBB", wire[current: current + 3]) 78 | current += 3 79 | rdlen -= 3 80 | cert = wire[current: current + rdlen].unwrap() 81 | return cls(rdclass, rdtype, header[0], header[1], header[2], cert) 82 | 83 | from_wire = classmethod(from_wire) 84 | 85 | def _cmp(self, other): 86 | hs = struct.pack("!BBB", self.usage, self.selector, self.mtype) 87 | ho = struct.pack("!BBB", other.usage, other.selector, other.mtype) 88 | v = dns.util.cmp(hs, ho) 89 | if v == 0: 90 | v = dns.util.cmp(self.cert, other.cert) 91 | return v 92 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/TXT.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.txtbase 17 | 18 | 19 | class TXT(dns.rdtypes.txtbase.TXTBase): 20 | """TXT record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/X25.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.rdata 18 | import dns.tokenizer 19 | import dns.util 20 | 21 | 22 | class X25(dns.rdata.Rdata): 23 | """X25 record 24 | 25 | @ivar address: the PSDN address 26 | @type address: string 27 | @see: RFC 1183""" 28 | 29 | __slots__ = ['address'] 30 | 31 | def __init__(self, rdclass, rdtype, address): 32 | super(X25, self).__init__(rdclass, rdtype) 33 | self.address = address 34 | 35 | def to_text(self, origin=None, relativize=True, **kw): 36 | return '"%s"' % dns.rdata._escapify(self.address) 37 | 38 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 39 | address = tok.get_string() 40 | tok.get_eol() 41 | return cls(rdclass, rdtype, address) 42 | 43 | from_text = classmethod(from_text) 44 | 45 | def to_wire(self, file, compress=None, origin=None): 46 | l = len(self.address) 47 | assert l < 256 48 | dns.util.write_uint8(file, l) 49 | file.write(self.address.encode('latin_1')) 50 | 51 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 52 | l = wire[current] 53 | current += 1 54 | rdlen -= 1 55 | if l != rdlen: 56 | raise dns.exception.FormError 57 | address = wire[current: current + l].decode('latin_1') 58 | return cls(rdclass, rdtype, address) 59 | 60 | from_wire = classmethod(from_wire) 61 | 62 | def _cmp(self, other): 63 | return dns.util.cmp(self.address, other.address) 64 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/ANY/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """Class ANY (generic) rdata type classes.""" 17 | 18 | __all__ = [ 19 | 'AFSDB', 20 | 'CERT', 21 | 'CNAME', 22 | 'DLV', 23 | 'DNAME', 24 | 'DNSKEY', 25 | 'DS', 26 | 'GPOS', 27 | 'HINFO', 28 | 'HIP', 29 | 'ISDN', 30 | 'LOC', 31 | 'MX', 32 | 'NS', 33 | 'NSEC', 34 | 'NSEC3', 35 | 'NSEC3PARAM', 36 | 'PTR', 37 | 'RP', 38 | 'RRSIG', 39 | 'RT', 40 | 'SOA', 41 | 'SPF', 42 | 'SSHFP', 43 | 'TXT', 44 | 'X25', 45 | ] 46 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/A.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.ipv4 18 | import dns.rdata 19 | import dns.tokenizer 20 | import dns.util 21 | 22 | 23 | class A(dns.rdata.Rdata): 24 | """A record. 25 | 26 | @ivar address: an IPv4 address 27 | @type address: string (in the standard "dotted quad" format)""" 28 | 29 | __slots__ = ['address'] 30 | 31 | def __init__(self, rdclass, rdtype, address): 32 | super(A, self).__init__(rdclass, rdtype) 33 | # check that it's OK 34 | junk = dns.ipv4.inet_aton(address) 35 | self.address = address 36 | 37 | def to_text(self, origin=None, relativize=True, **kw): 38 | return self.address 39 | 40 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 41 | address = tok.get_identifier() 42 | tok.get_eol() 43 | return cls(rdclass, rdtype, address) 44 | 45 | from_text = classmethod(from_text) 46 | 47 | def to_wire(self, file, compress=None, origin=None): 48 | file.write(dns.ipv4.inet_aton(self.address)) 49 | 50 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 51 | address = dns.ipv4.inet_ntoa(wire[current: current + rdlen]) 52 | return cls(rdclass, rdtype, address) 53 | 54 | from_wire = classmethod(from_wire) 55 | 56 | def _cmp(self, other): 57 | sa = dns.ipv4.inet_aton(self.address) 58 | oa = dns.ipv4.inet_aton(other.address) 59 | return dns.util.cmp(sa, oa) 60 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/AAAA.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.inet 18 | import dns.rdata 19 | import dns.tokenizer 20 | import dns.util 21 | 22 | 23 | class AAAA(dns.rdata.Rdata): 24 | """AAAA record. 25 | 26 | @ivar address: an IPv6 address 27 | @type address: string (in the standard IPv6 format)""" 28 | 29 | __slots__ = ['address'] 30 | 31 | def __init__(self, rdclass, rdtype, address): 32 | super(AAAA, self).__init__(rdclass, rdtype) 33 | # check that it's OK 34 | junk = dns.inet.inet_pton(dns.inet.AF_INET6, address) 35 | self.address = address 36 | 37 | def to_text(self, origin=None, relativize=True, **kw): 38 | return self.address 39 | 40 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 41 | address = tok.get_identifier() 42 | tok.get_eol() 43 | return cls(rdclass, rdtype, address) 44 | 45 | from_text = classmethod(from_text) 46 | 47 | def to_wire(self, file, compress=None, origin=None): 48 | file.write(dns.inet.inet_pton(dns.inet.AF_INET6, self.address)) 49 | 50 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 51 | address = dns.inet.inet_ntop(dns.inet.AF_INET6, 52 | wire[current: current + rdlen]) 53 | return cls(rdclass, rdtype, address) 54 | 55 | from_wire = classmethod(from_wire) 56 | 57 | def _cmp(self, other): 58 | sa = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) 59 | oa = dns.inet.inet_pton(dns.inet.AF_INET6, other.address) 60 | return dns.util.cmp(sa, oa) 61 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/APL.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import io 17 | import struct 18 | 19 | import dns.exception 20 | import dns.inet 21 | import dns.rdata 22 | import dns.tokenizer 23 | import dns.util 24 | 25 | 26 | class APLItem(object): 27 | """An APL list item. 28 | 29 | @ivar family: the address family (IANA address family registry) 30 | @type family: int 31 | @ivar negation: is this item negated? 32 | @type negation: bool 33 | @ivar address: the address 34 | @type address: string 35 | @ivar prefix: the prefix length 36 | @type prefix: int 37 | """ 38 | 39 | __slots__ = ['family', 'negation', 'address', 'prefix'] 40 | 41 | def __init__(self, family, negation, address, prefix): 42 | self.family = family 43 | self.negation = negation 44 | self.address = address 45 | self.prefix = prefix 46 | 47 | def __str__(self): 48 | if self.negation: 49 | return "!%d:%s/%s" % (self.family, self.address, self.prefix) 50 | else: 51 | return "%d:%s/%s" % (self.family, self.address, self.prefix) 52 | 53 | def to_wire(self, file): 54 | if self.family == 1: 55 | address = dns.inet.inet_pton(dns.inet.AF_INET, self.address) 56 | elif self.family == 2: 57 | address = dns.inet.inet_pton(dns.inet.AF_INET6, self.address) 58 | else: 59 | address = self.address.decode('hex_codec') 60 | # 61 | # Truncate least significant zero bytes. 62 | # 63 | last = 0 64 | for i in range(len(address) - 1, -1, -1): 65 | if address[i] != 0: 66 | last = i + 1 67 | break 68 | address = address[0: last] 69 | l = len(address) 70 | assert l < 128 71 | if self.negation: 72 | l |= 0x80 73 | header = struct.pack('!HBB', self.family, self.prefix, l) 74 | file.write(header) 75 | file.write(address) 76 | 77 | 78 | class APL(dns.rdata.Rdata): 79 | """APL record. 80 | 81 | @ivar items: a list of APL items 82 | @type items: list of APL_Item 83 | @see: RFC 3123""" 84 | 85 | __slots__ = ['items'] 86 | 87 | def __init__(self, rdclass, rdtype, items): 88 | super(APL, self).__init__(rdclass, rdtype) 89 | self.items = items 90 | 91 | def to_text(self, origin=None, relativize=True, **kw): 92 | return ' '.join(map(lambda x: str(x), self.items)) 93 | 94 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 95 | items = [] 96 | while 1: 97 | token = tok.get().unescape() 98 | if token.is_eol_or_eof(): 99 | break 100 | item = token.value 101 | if item[0] == '!': 102 | negation = True 103 | item = item[1:] 104 | else: 105 | negation = False 106 | (family, rest) = item.split(':', 1) 107 | family = int(family) 108 | (address, prefix) = rest.split('/', 1) 109 | prefix = int(prefix) 110 | item = APLItem(family, negation, address, prefix) 111 | items.append(item) 112 | 113 | return cls(rdclass, rdtype, items) 114 | 115 | from_text = classmethod(from_text) 116 | 117 | def to_wire(self, file, compress=None, origin=None): 118 | for item in self.items: 119 | item.to_wire(file) 120 | 121 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 122 | items = [] 123 | while 1: 124 | if rdlen == 0: 125 | break 126 | if rdlen < 4: 127 | raise dns.exception.FormError 128 | header = struct.unpack('!HBB', wire[current: current + 4]) 129 | afdlen = header[2] 130 | if afdlen > 127: 131 | negation = True 132 | afdlen -= 128 133 | else: 134 | negation = False 135 | current += 4 136 | rdlen -= 4 137 | if rdlen < afdlen: 138 | raise dns.exception.FormError 139 | address = wire[current: current + afdlen].unwrap() 140 | l = len(address) 141 | if header[0] == 1: 142 | if l < 4: 143 | address += b'\x00' * (4 - l) 144 | address = dns.inet.inet_ntop(dns.inet.AF_INET, address) 145 | elif header[0] == 2: 146 | if l < 16: 147 | address += b'\x00' * (16 - l) 148 | address = dns.inet.inet_ntop(dns.inet.AF_INET6, address) 149 | else: 150 | # 151 | # This isn't really right according to the RFC, but it 152 | # seems better than throwing an exception 153 | # 154 | address = dns.rdata._hexify(address) 155 | current += afdlen 156 | rdlen -= afdlen 157 | item = APLItem(header[0], negation, address, header[1]) 158 | items.append(item) 159 | return cls(rdclass, rdtype, items) 160 | 161 | from_wire = classmethod(from_wire) 162 | 163 | def _cmp(self, other): 164 | f = io.BytesIO() 165 | self.to_wire(f) 166 | wire1 = f.getvalue() 167 | f.seek(0) 168 | f.truncate() 169 | other.to_wire(f) 170 | wire2 = f.getvalue() 171 | f.close() 172 | 173 | return dns.util.cmp(wire1, wire2) 174 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/DHCID.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006, 2007, 2009-2011 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 | import base64 17 | 18 | import dns.exception 19 | import dns.util 20 | 21 | 22 | class DHCID(dns.rdata.Rdata): 23 | """DHCID record 24 | 25 | @ivar data: the data (the content of the RR is opaque as far as the 26 | DNS is concerned) 27 | @type data: bytes 28 | @see: RFC 4701""" 29 | 30 | __slots__ = ['data'] 31 | 32 | def __init__(self, rdclass, rdtype, data): 33 | super(DHCID, self).__init__(rdclass, rdtype) 34 | self.data = data 35 | 36 | def to_text(self, origin=None, relativize=True, **kw): 37 | return dns.rdata._base64ify(self.data) 38 | 39 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 40 | chunks = [] 41 | while 1: 42 | t = tok.get().unescape() 43 | if t.is_eol_or_eof(): 44 | break 45 | if not t.is_identifier(): 46 | raise dns.exception.SyntaxError 47 | chunks.append(t.value) 48 | b64 = ''.join(chunks) 49 | data = base64.b64decode(b64.encode('ascii')) 50 | return cls(rdclass, rdtype, data) 51 | 52 | from_text = classmethod(from_text) 53 | 54 | def to_wire(self, file, compress=None, origin=None): 55 | file.write(self.data) 56 | 57 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 58 | data = wire[current: current + rdlen].unwrap() 59 | return cls(rdclass, rdtype, data) 60 | 61 | from_wire = classmethod(from_wire) 62 | 63 | def _cmp(self, other): 64 | return dns.util.cmp(self.data, other.data) 65 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/KX.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.mxbase 17 | 18 | 19 | class KX(dns.rdtypes.mxbase.UncompressedMX): 20 | """KX record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/NAPTR.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import struct 17 | 18 | import dns.exception 19 | import dns.name 20 | import dns.rdata 21 | import dns.util 22 | 23 | 24 | def _write_string(file, s): 25 | l = len(s) 26 | assert l < 256 27 | dns.util.write_uint8(file, l) 28 | file.write(s.encode('ascii')) 29 | 30 | 31 | class NAPTR(dns.rdata.Rdata): 32 | """NAPTR record 33 | 34 | @ivar order: order 35 | @type order: int 36 | @ivar preference: preference 37 | @type preference: int 38 | @ivar flags: flags 39 | @type flags: string 40 | @ivar service: service 41 | @type service: string 42 | @ivar regexp: regular expression 43 | @type regexp: string 44 | @ivar replacement: replacement name 45 | @type replacement: dns.name.Name object 46 | @see: RFC 3403""" 47 | 48 | __slots__ = ['order', 'preference', 'flags', 'service', 'regexp', 49 | 'replacement'] 50 | 51 | def __init__(self, rdclass, rdtype, order, preference, flags, service, 52 | regexp, replacement): 53 | super(NAPTR, self).__init__(rdclass, rdtype) 54 | self.order = order 55 | self.preference = preference 56 | self.flags = flags 57 | self.service = service 58 | self.regexp = regexp 59 | self.replacement = replacement 60 | 61 | def to_text(self, origin=None, relativize=True, **kw): 62 | replacement = self.replacement.choose_relativity(origin, relativize) 63 | return '%d %d "%s" "%s" "%s" %s' % \ 64 | (self.order, self.preference, 65 | dns.rdata._escapify(self.flags), 66 | dns.rdata._escapify(self.service), 67 | dns.rdata._escapify(self.regexp), 68 | self.replacement) 69 | 70 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 71 | order = tok.get_uint16() 72 | preference = tok.get_uint16() 73 | flags = tok.get_string() 74 | service = tok.get_string() 75 | regexp = tok.get_string() 76 | replacement = tok.get_name() 77 | replacement = replacement.choose_relativity(origin, relativize) 78 | tok.get_eol() 79 | return cls(rdclass, rdtype, order, preference, flags, service, 80 | regexp, replacement) 81 | 82 | from_text = classmethod(from_text) 83 | 84 | def to_wire(self, file, compress=None, origin=None): 85 | two_ints = struct.pack("!HH", self.order, self.preference) 86 | file.write(two_ints) 87 | _write_string(file, self.flags) 88 | _write_string(file, self.service) 89 | _write_string(file, self.regexp) 90 | self.replacement.to_wire(file, compress, origin) 91 | 92 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 93 | (order, preference) = struct.unpack('!HH', wire[current: current + 4]) 94 | current += 4 95 | rdlen -= 4 96 | strings = [] 97 | for i in range(3): 98 | l = wire[current] 99 | current += 1 100 | rdlen -= 1 101 | if l > rdlen or rdlen < 0: 102 | raise dns.exception.FormError 103 | s = wire[current: current + l].decode('latin_1') 104 | current += l 105 | rdlen -= l 106 | strings.append(s) 107 | (replacement, cused) = dns.name.from_wire(wire[: current + rdlen], 108 | current) 109 | if cused != rdlen: 110 | raise dns.exception.FormError 111 | if not origin is None: 112 | replacement = replacement.relativize(origin) 113 | return cls(rdclass, rdtype, order, preference, strings[0], strings[1], 114 | strings[2], replacement) 115 | 116 | from_wire = classmethod(from_wire) 117 | 118 | def choose_relativity(self, origin=None, relativize=True): 119 | self.replacement = self.replacement.choose_relativity(origin, 120 | relativize) 121 | 122 | def _cmp(self, other): 123 | sp = struct.pack("!HH", self.order, self.preference) 124 | op = struct.pack("!HH", other.order, other.preference) 125 | v = dns.util.cmp(sp, op) 126 | if v == 0: 127 | v = dns.util.cmp(self.flags, other.flags) 128 | if v == 0: 129 | v = dns.util.cmp(self.service, other.service) 130 | if v == 0: 131 | v = dns.util.cmp(self.regexp, other.regexp) 132 | if v == 0: 133 | v = dns.util.cmp(self.replacement, other.replacement) 134 | return v 135 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/NSAP.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.exception 17 | import dns.rdata 18 | import dns.tokenizer 19 | import dns.util 20 | 21 | 22 | class NSAP(dns.rdata.Rdata): 23 | """NSAP record. 24 | 25 | @ivar address: a NSAP 26 | @type address: bytes 27 | @see: RFC 1706""" 28 | 29 | __slots__ = ['address'] 30 | 31 | def __init__(self, rdclass, rdtype, address): 32 | super(NSAP, self).__init__(rdclass, rdtype) 33 | self.address = address 34 | 35 | def to_text(self, origin=None, relativize=True, **kw): 36 | return "0x%s" % dns.rdata._hexify(self.address, 256) 37 | 38 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 39 | address = tok.get_string() 40 | t = tok.get_eol() 41 | if address[0:2] != '0x': 42 | raise dns.exception.SyntaxError('string does not start with 0x') 43 | address = address[2:].replace('.', '') 44 | if len(address) % 2 != 0: 45 | raise dns.exception.SyntaxError('hexstring has odd length') 46 | address = bytes.fromhex(address) 47 | return cls(rdclass, rdtype, address) 48 | 49 | from_text = classmethod(from_text) 50 | 51 | def to_wire(self, file, compress=None, origin=None): 52 | file.write(self.address) 53 | 54 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 55 | address = wire[current: current + rdlen].unwrap() 56 | return cls(rdclass, rdtype, address) 57 | 58 | from_wire = classmethod(from_wire) 59 | 60 | def _cmp(self, other): 61 | return dns.util.cmp(self.address, other.address) 62 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/NSAP_PTR.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import dns.rdtypes.nsbase 17 | 18 | 19 | class NSAP_PTR(dns.rdtypes.nsbase.UncompressedNS): 20 | """NSAP-PTR record""" 21 | pass 22 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/PX.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import struct 17 | 18 | import dns.exception 19 | import dns.rdata 20 | import dns.name 21 | import dns.util 22 | 23 | 24 | class PX(dns.rdata.Rdata): 25 | """PX record. 26 | 27 | @ivar preference: the preference value 28 | @type preference: int 29 | @ivar map822: the map822 name 30 | @type map822: dns.name.Name object 31 | @ivar mapx400: the mapx400 name 32 | @type mapx400: dns.name.Name object 33 | @see: RFC 2163""" 34 | 35 | __slots__ = ['preference', 'map822', 'mapx400'] 36 | 37 | def __init__(self, rdclass, rdtype, preference, map822, mapx400): 38 | super(PX, self).__init__(rdclass, rdtype) 39 | self.preference = preference 40 | self.map822 = map822 41 | self.mapx400 = mapx400 42 | 43 | def to_text(self, origin=None, relativize=True, **kw): 44 | map822 = self.map822.choose_relativity(origin, relativize) 45 | mapx400 = self.mapx400.choose_relativity(origin, relativize) 46 | return '%d %s %s' % (self.preference, map822, mapx400) 47 | 48 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 49 | preference = tok.get_uint16() 50 | map822 = tok.get_name() 51 | map822 = map822.choose_relativity(origin, relativize) 52 | mapx400 = tok.get_name(None) 53 | mapx400 = mapx400.choose_relativity(origin, relativize) 54 | tok.get_eol() 55 | return cls(rdclass, rdtype, preference, map822, mapx400) 56 | 57 | from_text = classmethod(from_text) 58 | 59 | def to_wire(self, file, compress=None, origin=None): 60 | pref = struct.pack("!H", self.preference) 61 | file.write(pref) 62 | self.map822.to_wire(file, None, origin) 63 | self.mapx400.to_wire(file, None, origin) 64 | 65 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 66 | (preference,) = struct.unpack('!H', wire[current: current + 2]) 67 | current += 2 68 | rdlen -= 2 69 | (map822, cused) = dns.name.from_wire(wire[: current + rdlen], 70 | current) 71 | if cused > rdlen: 72 | raise dns.exception.FormError 73 | current += cused 74 | rdlen -= cused 75 | if not origin is None: 76 | map822 = map822.relativize(origin) 77 | (mapx400, cused) = dns.name.from_wire(wire[: current + rdlen], 78 | current) 79 | if cused != rdlen: 80 | raise dns.exception.FormError 81 | if not origin is None: 82 | mapx400 = mapx400.relativize(origin) 83 | return cls(rdclass, rdtype, preference, map822, mapx400) 84 | 85 | from_wire = classmethod(from_wire) 86 | 87 | def choose_relativity(self, origin=None, relativize=True): 88 | self.map822 = self.map822.choose_relativity(origin, relativize) 89 | self.mapx400 = self.mapx400.choose_relativity(origin, relativize) 90 | 91 | def _cmp(self, other): 92 | sp = struct.pack("!H", self.preference) 93 | op = struct.pack("!H", other.preference) 94 | v = dns.util.cmp(sp, op) 95 | if v == 0: 96 | v = dns.util.cmp(self.map822, other.map822) 97 | if v == 0: 98 | v = dns.util.cmp(self.mapx400, other.mapx400) 99 | return v 100 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/SRV.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import struct 17 | 18 | import dns.exception 19 | import dns.rdata 20 | import dns.name 21 | import dns.util 22 | 23 | 24 | class SRV(dns.rdata.Rdata): 25 | """SRV record 26 | 27 | @ivar priority: the priority 28 | @type priority: int 29 | @ivar weight: the weight 30 | @type weight: int 31 | @ivar port: the port of the service 32 | @type port: int 33 | @ivar target: the target host 34 | @type target: dns.name.Name object 35 | @see: RFC 2782""" 36 | 37 | __slots__ = ['priority', 'weight', 'port', 'target'] 38 | 39 | def __init__(self, rdclass, rdtype, priority, weight, port, target): 40 | super(SRV, self).__init__(rdclass, rdtype) 41 | self.priority = priority 42 | self.weight = weight 43 | self.port = port 44 | self.target = target 45 | 46 | def to_text(self, origin=None, relativize=True, **kw): 47 | target = self.target.choose_relativity(origin, relativize) 48 | return '%d %d %d %s' % (self.priority, self.weight, self.port, 49 | target) 50 | 51 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 52 | priority = tok.get_uint16() 53 | weight = tok.get_uint16() 54 | port = tok.get_uint16() 55 | target = tok.get_name(None) 56 | target = target.choose_relativity(origin, relativize) 57 | tok.get_eol() 58 | return cls(rdclass, rdtype, priority, weight, port, target) 59 | 60 | from_text = classmethod(from_text) 61 | 62 | def to_wire(self, file, compress=None, origin=None): 63 | three_ints = struct.pack("!HHH", self.priority, self.weight, self.port) 64 | file.write(three_ints) 65 | self.target.to_wire(file, compress, origin) 66 | 67 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 68 | (priority, weight, port) = struct.unpack('!HHH', 69 | wire[current: current + 6]) 70 | current += 6 71 | rdlen -= 6 72 | (target, cused) = dns.name.from_wire(wire[: current + rdlen], 73 | current) 74 | if cused != rdlen: 75 | raise dns.exception.FormError 76 | if not origin is None: 77 | target = target.relativize(origin) 78 | return cls(rdclass, rdtype, priority, weight, port, target) 79 | 80 | from_wire = classmethod(from_wire) 81 | 82 | def choose_relativity(self, origin=None, relativize=True): 83 | self.target = self.target.choose_relativity(origin, relativize) 84 | 85 | def _cmp(self, other): 86 | sp = struct.pack("!HHH", self.priority, self.weight, self.port) 87 | op = struct.pack("!HHH", other.priority, other.weight, other.port) 88 | v = dns.util.cmp(sp, op) 89 | if v == 0: 90 | v = dns.util.cmp(self.target, other.target) 91 | return v 92 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/WKS.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | import socket 17 | import struct 18 | 19 | import dns.ipv4 20 | import dns.rdata 21 | import dns.util 22 | 23 | _proto_tcp = socket.getprotobyname('tcp') 24 | _proto_udp = socket.getprotobyname('udp') 25 | 26 | 27 | class WKS(dns.rdata.Rdata): 28 | """WKS record 29 | 30 | @ivar address: the address 31 | @type address: string 32 | @ivar protocol: the protocol 33 | @type protocol: int 34 | @ivar bitmap: the bitmap 35 | @type bitmap: bytes 36 | @see: RFC 1035""" 37 | 38 | __slots__ = ['address', 'protocol', 'bitmap'] 39 | 40 | def __init__(self, rdclass, rdtype, address, protocol, bitmap): 41 | super(WKS, self).__init__(rdclass, rdtype) 42 | self.address = address 43 | self.protocol = protocol 44 | self.bitmap = bitmap 45 | 46 | def to_text(self, origin=None, relativize=True, **kw): 47 | bits = [] 48 | for i in range(0, len(self.bitmap)): 49 | byte = self.bitmap[i] 50 | for j in range(0, 8): 51 | if byte & (0x80 >> j): 52 | bits.append(str(i * 8 + j)) 53 | text = ' '.join(bits) 54 | return '%s %d %s' % (self.address, self.protocol, text) 55 | 56 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 57 | address = tok.get_string() 58 | protocol = tok.get_string() 59 | if protocol.isdigit(): 60 | protocol = int(protocol) 61 | else: 62 | protocol = socket.getprotobyname(protocol) 63 | bitmap = bytearray(32 * 256) 64 | while 1: 65 | token = tok.get().unescape() 66 | if token.is_eol_or_eof(): 67 | break 68 | if token.value.isdigit(): 69 | serv = int(token.value) 70 | else: 71 | if protocol != _proto_udp and protocol != _proto_tcp: 72 | raise NotImplementedError("protocol must be TCP or UDP") 73 | if protocol == _proto_udp: 74 | protocol_text = "udp" 75 | else: 76 | protocol_text = "tcp" 77 | serv = socket.getservbyname(token.value, protocol_text) 78 | i = serv // 8 79 | bitmap[i] = bitmap[i] | (0x80 >> (serv % 8)) 80 | bitmap = dns.rdata._truncate_bitmap(bitmap) 81 | return cls(rdclass, rdtype, address, protocol, bitmap) 82 | 83 | from_text = classmethod(from_text) 84 | 85 | def to_wire(self, file, compress=None, origin=None): 86 | file.write(dns.ipv4.inet_aton(self.address)) 87 | protocol = struct.pack('!B', self.protocol) 88 | file.write(protocol) 89 | file.write(self.bitmap) 90 | 91 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 92 | address = dns.ipv4.inet_ntoa(wire[current: current + 4]) 93 | protocol, = struct.unpack('!B', wire[current + 4: current + 5]) 94 | current += 5 95 | rdlen -= 5 96 | bitmap = wire[current: current + rdlen].unwrap() 97 | return cls(rdclass, rdtype, address, protocol, bitmap) 98 | 99 | from_wire = classmethod(from_wire) 100 | 101 | def _cmp(self, other): 102 | sa = dns.ipv4.inet_aton(self.address) 103 | oa = dns.ipv4.inet_aton(other.address) 104 | v = dns.util.cmp(sa, oa) 105 | if v == 0: 106 | sp = struct.pack('!B', self.protocol) 107 | op = struct.pack('!B', other.protocol) 108 | v = dns.util.cmp(sp, op) 109 | if v == 0: 110 | v = dns.util.cmp(self.bitmap, other.bitmap) 111 | return v 112 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/IN/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """Class IN rdata type classes.""" 17 | 18 | __all__ = [ 19 | 'A', 20 | 'AAAA', 21 | 'APL', 22 | 'DHCID', 23 | 'KX', 24 | 'NAPTR', 25 | 'NSAP', 26 | 'NSAP_PTR', 27 | 'PX', 28 | 'SRV', 29 | 'WKS', 30 | ] 31 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 type classes""" 17 | 18 | __all__ = [ 19 | 'ANY', 20 | 'IN', 21 | 'mxbase', 22 | 'nsbase', 23 | ] 24 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/dsbase.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2010, 2011 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 | import struct 17 | 18 | import dns.rdata 19 | import dns.rdatatype 20 | import dns.util 21 | 22 | 23 | class DSBase(dns.rdata.Rdata): 24 | """Base class for rdata that is like a DS record 25 | 26 | @ivar key_tag: the key tag 27 | @type key_tag: int 28 | @ivar algorithm: the algorithm 29 | @type algorithm: int 30 | @ivar digest_type: the digest type 31 | @type digest_type: int 32 | @ivar digest: the digest 33 | @type digest: bytes 34 | @see: draft-ietf-dnsext-delegation-signer-14.txt""" 35 | 36 | __slots__ = ['key_tag', 'algorithm', 'digest_type', 'digest'] 37 | 38 | def __init__(self, rdclass, rdtype, key_tag, algorithm, digest_type, 39 | digest): 40 | super(DSBase, self).__init__(rdclass, rdtype) 41 | self.key_tag = key_tag 42 | self.algorithm = algorithm 43 | self.digest_type = digest_type 44 | self.digest = digest 45 | 46 | def to_text(self, origin=None, relativize=True, **kw): 47 | return '%d %d %d %s' % (self.key_tag, self.algorithm, 48 | self.digest_type, 49 | dns.rdata._hexify(self.digest, 50 | chunksize=128)) 51 | 52 | @classmethod 53 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 54 | key_tag = tok.get_uint16() 55 | algorithm = tok.get_uint8() 56 | digest_type = tok.get_uint8() 57 | chunks = [] 58 | while 1: 59 | t = tok.get().unescape() 60 | if t.is_eol_or_eof(): 61 | break 62 | if not t.is_identifier(): 63 | raise dns.exception.SyntaxError 64 | chunks.append(t.value) 65 | digest = bytes.fromhex(''.join(chunks)) 66 | return cls(rdclass, rdtype, key_tag, algorithm, digest_type, 67 | digest) 68 | 69 | def to_wire(self, file, compress=None, origin=None): 70 | header = struct.pack("!HBB", self.key_tag, self.algorithm, 71 | self.digest_type) 72 | file.write(header) 73 | file.write(self.digest) 74 | 75 | @classmethod 76 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 77 | header = struct.unpack("!HBB", wire[current: current + 4]) 78 | current += 4 79 | rdlen -= 4 80 | digest = wire[current: current + rdlen].unwrap() 81 | return cls(rdclass, rdtype, header[0], header[1], header[2], digest) 82 | 83 | def _cmp(self, other): 84 | hs = struct.pack("!HBB", self.key_tag, self.algorithm, 85 | self.digest_type) 86 | ho = struct.pack("!HBB", other.key_tag, other.algorithm, 87 | other.digest_type) 88 | v = dns.util.cmp(hs, ho) 89 | if v == 0: 90 | v = dns.util.cmp(self.digest, other.digest) 91 | return v 92 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/mxbase.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """MX-like base classes.""" 17 | 18 | import struct 19 | 20 | import dns.exception 21 | import dns.rdata 22 | import dns.name 23 | import dns.util 24 | 25 | 26 | class MXBase(dns.rdata.Rdata): 27 | """Base class for rdata that is like an MX record. 28 | 29 | @ivar preference: the preference value 30 | @type preference: int 31 | @ivar exchange: the exchange name 32 | @type exchange: dns.name.Name object""" 33 | 34 | __slots__ = ['preference', 'exchange'] 35 | 36 | def __init__(self, rdclass, rdtype, preference, exchange): 37 | super(MXBase, self).__init__(rdclass, rdtype) 38 | self.preference = preference 39 | self.exchange = exchange 40 | 41 | def to_text(self, origin=None, relativize=True, **kw): 42 | exchange = self.exchange.choose_relativity(origin, relativize) 43 | return '%d %s' % (self.preference, exchange) 44 | 45 | @classmethod 46 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 47 | preference = tok.get_uint16() 48 | exchange = tok.get_name() 49 | exchange = exchange.choose_relativity(origin, relativize) 50 | tok.get_eol() 51 | return cls(rdclass, rdtype, preference, exchange) 52 | 53 | def to_wire(self, file, compress=None, origin=None): 54 | pref = struct.pack("!H", self.preference) 55 | file.write(pref) 56 | self.exchange.to_wire(file, compress, origin) 57 | 58 | def to_digestable(self, origin=None): 59 | return struct.pack("!H", self.preference) + \ 60 | self.exchange.to_digestable(origin) 61 | 62 | @classmethod 63 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 64 | (preference,) = struct.unpack('!H', wire[current: current + 2]) 65 | current += 2 66 | rdlen -= 2 67 | (exchange, cused) = dns.name.from_wire(wire[: current + rdlen], 68 | current) 69 | if cused != rdlen: 70 | raise dns.exception.FormError 71 | if not origin is None: 72 | exchange = exchange.relativize(origin) 73 | return cls(rdclass, rdtype, preference, exchange) 74 | 75 | def choose_relativity(self, origin=None, relativize=True): 76 | self.exchange = self.exchange.choose_relativity(origin, relativize) 77 | 78 | def _cmp(self, other): 79 | sp = struct.pack("!H", self.preference) 80 | op = struct.pack("!H", other.preference) 81 | v = dns.util.cmp(sp, op) 82 | if v == 0: 83 | v = dns.util.cmp(self.exchange, other.exchange) 84 | return v 85 | 86 | 87 | class UncompressedMX(MXBase): 88 | """Base class for rdata that is like an MX record, but whose name 89 | is not compressed when converted to DNS wire format, and whose 90 | digestable form is not downcased.""" 91 | 92 | def to_wire(self, file, compress=None, origin=None): 93 | super(UncompressedMX, self).to_wire(file, None, origin) 94 | 95 | def to_digestable(self, origin=None): 96 | return self.to_wire(f, None, origin) 97 | 98 | 99 | class UncompressedDowncasingMX(MXBase): 100 | """Base class for rdata that is like an MX record, but whose name 101 | is not compressed when convert to DNS wire format.""" 102 | 103 | def to_wire(self, file, compress=None, origin=None): 104 | super(UncompressedDowncasingMX, self).to_wire(file, None, origin) 105 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/nsbase.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """NS-like base classes.""" 17 | 18 | import io 19 | 20 | import dns.exception 21 | import dns.rdata 22 | import dns.name 23 | import dns.util 24 | 25 | 26 | class NSBase(dns.rdata.Rdata): 27 | """Base class for rdata that is like an NS record. 28 | 29 | @ivar target: the target name of the rdata 30 | @type target: dns.name.Name object""" 31 | 32 | __slots__ = ['target'] 33 | 34 | def __init__(self, rdclass, rdtype, target): 35 | super(NSBase, self).__init__(rdclass, rdtype) 36 | self.target = target 37 | 38 | def to_text(self, origin=None, relativize=True, **kw): 39 | target = self.target.choose_relativity(origin, relativize) 40 | return str(target) 41 | 42 | @classmethod 43 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 44 | target = tok.get_name() 45 | target = target.choose_relativity(origin, relativize) 46 | tok.get_eol() 47 | return cls(rdclass, rdtype, target) 48 | 49 | def to_wire(self, file, compress=None, origin=None): 50 | self.target.to_wire(file, compress, origin) 51 | 52 | def to_digestable(self, origin=None): 53 | return self.target.to_digestable(origin) 54 | 55 | @classmethod 56 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 57 | (target, cused) = dns.name.from_wire(wire[: current + rdlen], 58 | current) 59 | if cused != rdlen: 60 | raise dns.exception.FormError 61 | if not origin is None: 62 | target = target.relativize(origin) 63 | return cls(rdclass, rdtype, target) 64 | 65 | def choose_relativity(self, origin=None, relativize=True): 66 | self.target = self.target.choose_relativity(origin, relativize) 67 | 68 | def _cmp(self, other): 69 | return dns.util.cmp(self.target, other.target) 70 | 71 | 72 | class UncompressedNS(NSBase): 73 | """Base class for rdata that is like an NS record, but whose name 74 | is not compressed when convert to DNS wire format, and whose 75 | digestable form is not downcased.""" 76 | 77 | def to_wire(self, file, compress=None, origin=None): 78 | super(UncompressedNS, self).to_wire(file, None, origin) 79 | 80 | def to_digestable(self, origin=None): 81 | return self.to_wire(None, None, origin) 82 | -------------------------------------------------------------------------------- /lib/dnspython/rdtypes/txtbase.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006, 2007, 2009-2011 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 | """TXT-like base class.""" 17 | 18 | import dns.exception 19 | import dns.rdata 20 | import dns.tokenizer 21 | import dns.util 22 | 23 | 24 | class TXTBase(dns.rdata.Rdata): 25 | """Base class for rdata that is like a TXT record 26 | 27 | @ivar strings: the text strings 28 | @type strings: list of string 29 | @see: RFC 1035""" 30 | 31 | __slots__ = ['strings'] 32 | 33 | def __init__(self, rdclass, rdtype, strings): 34 | super(TXTBase, self).__init__(rdclass, rdtype) 35 | if isinstance(strings, str): 36 | strings = [strings] 37 | self.strings = strings[:] 38 | 39 | def to_text(self, origin=None, relativize=True, **kw): 40 | txt = '' 41 | prefix = '' 42 | for s in self.strings: 43 | txt += '%s"%s"' % (prefix, dns.rdata._escapify(s)) 44 | prefix = ' ' 45 | return txt 46 | 47 | @classmethod 48 | def from_text(cls, rdclass, rdtype, tok, origin=None, relativize=True): 49 | strings = [] 50 | while 1: 51 | token = tok.get().unescape() 52 | if token.is_eol_or_eof(): 53 | break 54 | if not (token.is_quoted_string() or token.is_identifier()): 55 | raise dns.exception.SyntaxError("expected a string") 56 | if len(token.value) > 255: 57 | raise dns.exception.SyntaxError("string too long") 58 | strings.append(token.value) 59 | if len(strings) == 0: 60 | raise dns.exception.UnexpectedEnd 61 | return cls(rdclass, rdtype, strings) 62 | 63 | def to_wire(self, file, compress=None, origin=None): 64 | for s in self.strings: 65 | l = len(s) 66 | assert l < 256 67 | dns.util.write_uint8(file, l) 68 | file.write(s.encode('latin_1')) 69 | 70 | @classmethod 71 | def from_wire(cls, rdclass, rdtype, wire, current, rdlen, origin=None): 72 | strings = [] 73 | while rdlen > 0: 74 | l = wire[current] 75 | current += 1 76 | rdlen -= 1 77 | if l > rdlen: 78 | raise dns.exception.FormError 79 | s = wire[current: current + l].decode('latin_1') 80 | current += l 81 | rdlen -= l 82 | strings.append(s) 83 | return cls(rdclass, rdtype, strings) 84 | 85 | def _cmp(self, other): 86 | return dns.util.cmp(self.strings, other.strings) 87 | -------------------------------------------------------------------------------- /lib/dnspython/reversename.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2006, 2007, 2009-2011 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 Reverse Map Names. 17 | 18 | @var ipv4_reverse_domain: The DNS IPv4 reverse-map domain, in-addr.arpa. 19 | @type ipv4_reverse_domain: dns.name.Name object 20 | @var ipv6_reverse_domain: The DNS IPv6 reverse-map domain, ip6.arpa. 21 | @type ipv6_reverse_domain: dns.name.Name object 22 | """ 23 | 24 | import binascii 25 | import sys 26 | 27 | import dns.name 28 | import dns.ipv6 29 | import dns.ipv4 30 | 31 | ipv4_reverse_domain = dns.name.from_text('in-addr.arpa.') 32 | ipv6_reverse_domain = dns.name.from_text('ip6.arpa.') 33 | 34 | 35 | def from_address(text): 36 | """Convert an IPv4 or IPv6 address in textual form into a Name object whose 37 | value is the reverse-map domain name of the address. 38 | @param text: an IPv4 or IPv6 address in textual form (e.g. '127.0.0.1', 39 | '::1') 40 | @type text: str 41 | @rtype: dns.name.Name object 42 | """ 43 | try: 44 | v6 = dns.ipv6.inet_aton(text) 45 | if dns.ipv6.is_mapped(v6): 46 | if sys.version_info >= (3,): 47 | parts = ['%d' % byte for byte in v6[12:]] 48 | else: 49 | parts = ['%d' % ord(byte) for byte in v6[12:]] 50 | origin = ipv4_reverse_domain 51 | else: 52 | parts = [x for x in str(binascii.hexlify(v6).decode())] 53 | origin = ipv6_reverse_domain 54 | except: 55 | parts = ['%d' % 56 | byte for byte in bytearray(dns.ipv4.inet_aton(text))] 57 | origin = ipv4_reverse_domain 58 | parts.reverse() 59 | return dns.name.from_text('.'.join(parts), origin=origin) 60 | 61 | 62 | def to_address(name): 63 | """Convert a reverse map domain name into textual address form. 64 | @param name: an IPv4 or IPv6 address in reverse-map form. 65 | @type name: dns.name.Name object 66 | @rtype: str 67 | """ 68 | if name.is_subdomain(ipv4_reverse_domain): 69 | name = name.relativize(ipv4_reverse_domain) 70 | labels = list(name.labels) 71 | labels.reverse() 72 | text = b'.'.join(labels) 73 | # run through inet_aton() to check syntax and make pretty. 74 | return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text)) 75 | elif name.is_subdomain(ipv6_reverse_domain): 76 | name = name.relativize(ipv6_reverse_domain) 77 | labels = list(name.labels) 78 | labels.reverse() 79 | parts = [] 80 | i = 0 81 | l = len(labels) 82 | while i < l: 83 | parts.append(b''.join(labels[i:i + 4])) 84 | i += 4 85 | text = b':'.join(parts) 86 | # run through inet_aton() to check syntax and make pretty. 87 | return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text)) 88 | else: 89 | raise dns.exception.SyntaxError('unknown reverse-map address family') 90 | -------------------------------------------------------------------------------- /lib/dnspython/rrset.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 RRsets (an RRset is a named rdataset)""" 17 | 18 | import dns.name 19 | import dns.rdataset 20 | import dns.rdataclass 21 | import dns.renderer 22 | from ._compat import string_types 23 | 24 | 25 | class RRset(dns.rdataset.Rdataset): 26 | """A DNS RRset (named rdataset). 27 | 28 | RRset inherits from Rdataset, and RRsets can be treated as 29 | Rdatasets in most cases. There are, however, a few notable 30 | exceptions. RRsets have different to_wire() and to_text() method 31 | arguments, reflecting the fact that RRsets always have an owner 32 | name. 33 | """ 34 | 35 | __slots__ = ['name', 'deleting'] 36 | 37 | def __init__(self, name, rdclass, rdtype, covers=dns.rdatatype.NONE, 38 | deleting=None): 39 | """Create a new RRset.""" 40 | 41 | super(RRset, self).__init__(rdclass, rdtype, covers) 42 | self.name = name 43 | self.deleting = deleting 44 | 45 | def _clone(self): 46 | obj = super(RRset, self)._clone() 47 | obj.name = self.name 48 | obj.deleting = self.deleting 49 | return obj 50 | 51 | def __repr__(self): 52 | if self.covers == 0: 53 | ctext = '' 54 | else: 55 | ctext = '(' + dns.rdatatype.to_text(self.covers) + ')' 56 | if self.deleting is not None: 57 | dtext = ' delete=' + dns.rdataclass.to_text(self.deleting) 58 | else: 59 | dtext = '' 60 | return '' 63 | 64 | def __str__(self): 65 | return self.to_text() 66 | 67 | def __eq__(self, other): 68 | """Two RRsets are equal if they have the same name and the same 69 | rdataset 70 | 71 | @rtype: bool""" 72 | if not isinstance(other, RRset): 73 | return False 74 | if self.name != other.name: 75 | return False 76 | return super(RRset, self).__eq__(other) 77 | 78 | def match(self, name, rdclass, rdtype, covers, deleting=None): 79 | """Returns True if this rrset matches the specified class, type, 80 | covers, and deletion state.""" 81 | 82 | if not super(RRset, self).match(rdclass, rdtype, covers): 83 | return False 84 | if self.name != name or self.deleting != deleting: 85 | return False 86 | return True 87 | 88 | def to_text(self, origin=None, relativize=True, **kw): 89 | """Convert the RRset into DNS master file format. 90 | 91 | @see: L{dns.name.Name.choose_relativity} for more information 92 | on how I{origin} and I{relativize} determine the way names 93 | are emitted. 94 | 95 | Any additional keyword arguments are passed on to the rdata 96 | to_text() method. 97 | 98 | @param origin: The origin for relative names, or None. 99 | @type origin: dns.name.Name object 100 | @param relativize: True if names should names be relativized 101 | @type relativize: bool""" 102 | 103 | return super(RRset, self).to_text(self.name, origin, relativize, 104 | self.deleting, **kw) 105 | 106 | def to_wire(self, file, compress=None, origin=None, **kw): 107 | """Convert the RRset to wire format.""" 108 | 109 | return super(RRset, self).to_wire(self.name, file, compress, origin, 110 | self.deleting, **kw) 111 | 112 | def to_rdataset(self): 113 | """Convert an RRset into an Rdataset. 114 | 115 | @rtype: dns.rdataset.Rdataset object 116 | """ 117 | return dns.rdataset.from_rdata_list(self.ttl, list(self)) 118 | 119 | 120 | def from_text_list(name, ttl, rdclass, rdtype, text_rdatas): 121 | """Create an RRset with the specified name, TTL, class, and type, and with 122 | the specified list of rdatas in text format. 123 | 124 | @rtype: dns.rrset.RRset object 125 | """ 126 | 127 | if isinstance(name, string_types): 128 | name = dns.name.from_text(name, None) 129 | if isinstance(rdclass, string_types): 130 | rdclass = dns.rdataclass.from_text(rdclass) 131 | if isinstance(rdtype, string_types): 132 | rdtype = dns.rdatatype.from_text(rdtype) 133 | r = RRset(name, rdclass, rdtype) 134 | r.update_ttl(ttl) 135 | for t in text_rdatas: 136 | rd = dns.rdata.from_text(r.rdclass, r.rdtype, t) 137 | r.add(rd) 138 | return r 139 | 140 | 141 | def from_text(name, ttl, rdclass, rdtype, *text_rdatas): 142 | """Create an RRset with the specified name, TTL, class, and type and with 143 | the specified rdatas in text format. 144 | 145 | @rtype: dns.rrset.RRset object 146 | """ 147 | 148 | return from_text_list(name, ttl, rdclass, rdtype, text_rdatas) 149 | 150 | 151 | def from_rdata_list(name, ttl, rdatas): 152 | """Create an RRset with the specified name and TTL, and with 153 | the specified list of rdata objects. 154 | 155 | @rtype: dns.rrset.RRset object 156 | """ 157 | 158 | if isinstance(name, string_types): 159 | name = dns.name.from_text(name, None) 160 | 161 | if len(rdatas) == 0: 162 | raise ValueError("rdata list must not be empty") 163 | r = None 164 | for rd in rdatas: 165 | if r is None: 166 | r = RRset(name, rd.rdclass, rd.rdtype) 167 | r.update_ttl(ttl) 168 | r.add(rd) 169 | return r 170 | 171 | 172 | def from_rdata(name, ttl, *rdatas): 173 | """Create an RRset with the specified name and TTL, and with 174 | the specified rdata objects. 175 | 176 | @rtype: dns.rrset.RRset object 177 | """ 178 | 179 | return from_rdata_list(name, ttl, rdatas) 180 | -------------------------------------------------------------------------------- /lib/dnspython/tsigkeyring.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """A place to store TSIG keys.""" 17 | 18 | import base64 19 | 20 | import dns.name 21 | 22 | 23 | def from_text(textring): 24 | """Convert a dictionary containing (textual DNS name, base64 secret) pairs 25 | into a binary keyring which has (dns.name.Name, binary secret) pairs. 26 | @rtype: dict""" 27 | 28 | keyring = {} 29 | for keytext in textring: 30 | keyname = dns.name.from_text(keytext) 31 | secret = base64.decodestring(textring[keytext]) 32 | keyring[keyname] = secret 33 | return keyring 34 | 35 | 36 | def to_text(keyring): 37 | """Convert a dictionary containing (dns.name.Name, binary secret) pairs 38 | into a text keyring which has (textual DNS name, base64 secret) pairs. 39 | @rtype: dict""" 40 | 41 | textring = {} 42 | for keyname in keyring: 43 | keytext = keyname.to_text() 44 | secret = base64.encodestring(keyring[keyname]) 45 | textring[keytext] = secret 46 | return textring 47 | -------------------------------------------------------------------------------- /lib/dnspython/ttl.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 TTL conversion.""" 17 | 18 | import dns.exception 19 | from ._compat import long 20 | 21 | 22 | class BadTTL(dns.exception.SyntaxError): 23 | """DNS TTL value is not well-formed.""" 24 | 25 | 26 | def from_text(text): 27 | """Convert the text form of a TTL to an integer. 28 | 29 | The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported. 30 | 31 | @param text: the textual TTL 32 | @type text: string 33 | @raises dns.ttl.BadTTL: the TTL is not well-formed 34 | @rtype: int 35 | """ 36 | 37 | if text.isdigit(): 38 | total = long(text) 39 | else: 40 | if not text[0].isdigit(): 41 | raise BadTTL 42 | total = long(0) 43 | current = long(0) 44 | for c in text: 45 | if c.isdigit(): 46 | current *= 10 47 | current += long(c) 48 | else: 49 | c = c.lower() 50 | if c == 'w': 51 | total += current * long(604800) 52 | elif c == 'd': 53 | total += current * long(86400) 54 | elif c == 'h': 55 | total += current * long(3600) 56 | elif c == 'm': 57 | total += current * long(60) 58 | elif c == 's': 59 | total += current 60 | else: 61 | raise BadTTL("unknown unit '%s'" % c) 62 | current = 0 63 | if not current == 0: 64 | raise BadTTL("trailing integer") 65 | if total < long(0) or total > long(2147483647): 66 | raise BadTTL("TTL should be between 0 and 2^31 - 1 (inclusive)") 67 | return total 68 | -------------------------------------------------------------------------------- /lib/dnspython/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 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 | """Miscellaneous Implementation Helpers""" 17 | 18 | import struct 19 | 20 | 21 | def cmp(x, y): 22 | """The cmp() function from Python 2""" 23 | if x > y: 24 | return 1 25 | elif x < y: 26 | return -1 27 | else: 28 | return 0 29 | 30 | 31 | def write_uint8(bfile, value): 32 | """Write an unsigned 8-bit integer to an io.BytesIO file 33 | """ 34 | bfile.write(struct.pack('B', value)) 35 | 36 | 37 | def write_uint16(bfile, value): 38 | """Write an unsigned 16-bit integer to an io.BytesIO file 39 | """ 40 | bfile.write(struct.pack('!H', value)) 41 | 42 | 43 | def write_uint32(bfile, value): 44 | """Write an unsigned 32-bit integer to an io.BytesIO file 45 | """ 46 | bfile.write(struct.pack('!L', value)) 47 | 48 | 49 | def write_uint64(bfile, value): 50 | """Write an unsigned 64-bit integer to an io.BytesIO file 51 | """ 52 | bfile.write(struct.pack('!Q', value)) 53 | -------------------------------------------------------------------------------- /lib/dnspython/version.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2003-2007, 2009-2011 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 | """dnspython release version information.""" 17 | 18 | MAJOR = 1 19 | MINOR = 14 20 | MICRO = 0 21 | RELEASELEVEL = 0x0f 22 | SERIAL = 0 23 | 24 | if RELEASELEVEL == 0x0f: 25 | version = '%d.%d.%d' % (MAJOR, MINOR, MICRO) 26 | elif RELEASELEVEL == 0x00: 27 | version = '%d.%d.%dx%d' % \ 28 | (MAJOR, MINOR, MICRO, SERIAL) 29 | else: 30 | version = '%d.%d.%d%x%d' % \ 31 | (MAJOR, MINOR, MICRO, RELEASELEVEL, SERIAL) 32 | 33 | hexversion = MAJOR << 24 | MINOR << 16 | MICRO << 8 | RELEASELEVEL << 4 | \ 34 | SERIAL 35 | -------------------------------------------------------------------------------- /lib/dnspython/wiredata.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011 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 Wire Data Helper""" 17 | 18 | import dns.exception 19 | from ._compat import binary_type, string_types 20 | 21 | 22 | # Figure out what constant python passes for an unspecified slice bound. 23 | # It's supposed to be sys.maxint, yet on 64-bit windows sys.maxint is 2^31 - 1 24 | # but Python uses 2^63 - 1 as the constant. Rather than making pointless 25 | # extra comparisons, duplicating code, or weakening WireData, we just figure 26 | # out what constant Python will use. 27 | 28 | 29 | class _SliceUnspecifiedBound(str): 30 | def __getslice__(self, i, j): 31 | return j 32 | 33 | 34 | _unspecified_bound = _SliceUnspecifiedBound('')[1:] 35 | 36 | 37 | class WireData(binary_type): 38 | # WireData is a string with stricter slicing 39 | 40 | def __getitem__(self, key): 41 | try: 42 | if isinstance(key, slice): 43 | return WireData(super(WireData, self).__getitem__(key)) 44 | return bytearray(self.unwrap())[key] 45 | except IndexError: 46 | raise dns.exception.FormError 47 | 48 | def __getslice__(self, i, j): 49 | try: 50 | if j == _unspecified_bound: 51 | # handle the case where the right bound is unspecified 52 | j = len(self) 53 | if i < 0 or j < 0: 54 | raise dns.exception.FormError 55 | # If it's not an empty slice, access left and right bounds 56 | # to make sure they're valid 57 | if i != j: 58 | super(WireData, self).__getitem__(i) 59 | super(WireData, self).__getitem__(j - 1) 60 | return WireData(super(WireData, self).__getslice__(i, j)) 61 | except IndexError: 62 | raise dns.exception.FormError 63 | 64 | def __iter__(self): 65 | i = 0 66 | while 1: 67 | try: 68 | yield self[i] 69 | i += 1 70 | except dns.exception.FormError: 71 | raise StopIteration 72 | 73 | def unwrap(self): 74 | return binary_type(self) 75 | 76 | 77 | def maybe_wrap(wire): 78 | if isinstance(wire, WireData): 79 | return wire 80 | elif isinstance(wire, binary_type): 81 | return WireData(wire) 82 | elif isinstance(wire, string_types): 83 | return WireData(wire.encode()) 84 | raise ValueError("unhandled type %s" % type(wire)) 85 | -------------------------------------------------------------------------------- /lib/evil.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- utf8 -*- 3 | # author=dave.fang@outlook.com 4 | # create=20160410 5 | import queue 6 | import random 7 | import gevent.pool 8 | import gevent.monkey 9 | 10 | from lib.dnspython import zone 11 | from lib.dnspython import query 12 | from lib.dnspython import resolver 13 | from config import DNS_LIST, IGNORE_DNS_LIST, THREAD_BRUTE, BASE_DIR, MAX_TRY_COUNT 14 | from lib.decorator import max_try_wrapper 15 | from lib.dns import get_analysis_from_dns 16 | 17 | 18 | class Evil(object): 19 | def __init__(self, domain, depth=1): 20 | self.main_domain = domain 21 | self.current_domain = domain 22 | self.depth = depth 23 | self.name_servers = [] 24 | self.pan_analysis = [] 25 | self.domain_queue = queue.Queue() 26 | self.domain_queue.put(domain) 27 | self.zone_transfer = False 28 | self.pool = gevent.pool.Pool(THREAD_BRUTE) 29 | gevent.monkey.patch_socket() 30 | 31 | def start(self): 32 | file_handle = open('{0}/output/{1}.txt'.format(BASE_DIR, self.main_domain), 'w') 33 | file_handle.close() 34 | self.get_ns_servers() 35 | self.axfr_check() 36 | if not self.zone_transfer: 37 | while not self.domain_queue.empty(): 38 | self.current_domain = self.domain_queue.get() 39 | self.fuzz_domain_level() 40 | print('[*] Done!') 41 | 42 | @max_try_wrapper 43 | def get_pan_analyse(self, domain): 44 | for i in range(MAX_TRY_COUNT): 45 | if self.pan_analysis != [] and self.pan_analysis != [[], []]: 46 | break 47 | self.pan_analysis = get_analysis_from_dns(random.choice(DNS_LIST), '*.{0}'.format(domain)) 48 | file_handle = open('{0}/output/{1}.txt'.format(BASE_DIR, self.main_domain), 'a') 49 | file_handle.write('{0}\t{1}\t{2}\n'. 50 | format('*.{0}'.format(domain), self.pan_analysis[0], self.pan_analysis[1])) 51 | file_handle.close() 52 | 53 | def fuzz_domain_level(self): 54 | print('[*] < {0} > FUZZING...'.format(self.current_domain)) 55 | self.get_pan_analyse(self.current_domain) 56 | print('[*] Pan Analysis: {0}'.format(str(self.pan_analysis))) 57 | file_handle = open("./dict/all-level.dict") 58 | content_dict = file_handle.read().split('\n') 59 | if content_dict[-1] == '': 60 | del content_dict[-1] 61 | self.pool.map(self.get_analysis, content_dict) 62 | 63 | def get_analysis(self, sub_domain): 64 | if sub_domain == '' or sub_domain.startswith('.'): 65 | return 66 | sub_domain = '{0}.{1}'.format(sub_domain, self.current_domain) 67 | analysis = get_analysis_from_dns(random.choice(DNS_LIST), sub_domain) 68 | if not analysis[1] or analysis[1] == self.pan_analysis[1]: 69 | return 70 | if analysis[0] != [] and analysis[0] == self.pan_analysis[0]: 71 | return 72 | file_handle = open('{0}/output/{1}.txt'.format(BASE_DIR, self.main_domain), 'a') 73 | print('[+] {0}\t{1}'.format(sub_domain, str(analysis[1]))) 74 | if self.depth < 0: 75 | self.domain_queue.put(sub_domain) # Recursive Detect 76 | file_handle.write('{0}\t{1}\t{2}\n'.format(sub_domain, analysis[0], analysis[1])) 77 | file_handle.close() 78 | 79 | @max_try_wrapper 80 | def get_ns_servers(self): 81 | resolver_tmo = resolver.Resolver() 82 | resolver_tmo.timeout = 5 83 | resolver_tmo.lifetime = 10 84 | resolver_tmo.nameservers = DNS_LIST 85 | answers = resolver_tmo.query(self.main_domain, "NS") 86 | if answers: 87 | for answer in answers: 88 | ns_one = str(answer) 89 | self.name_servers.append(ns_one[0:-1]) 90 | self.name_servers.sort() 91 | print('[+] Name Server: {0}'.format(self.name_servers)) 92 | 93 | def axfr_check(self): 94 | for ns in self.name_servers: 95 | print('[*] Checking: ' + self.main_domain + ' NS: ' + ns) 96 | if ns in IGNORE_DNS_LIST: 97 | continue 98 | self.axfr_ns_check(ns) 99 | if self.zone_transfer: 100 | break 101 | 102 | @max_try_wrapper 103 | def axfr_ns_check(self, ns): 104 | zone_tmp = zone.from_xfr(query.xfr(str(ns), self.main_domain, timeout=5, lifetime=10)) 105 | if zone_tmp: 106 | self.zone_transfer = True 107 | print('[+] ' + self.main_domain + ' HAS THE ZONE TRANSFER VULNERABILITY') 108 | # get detail info 109 | file_handle = open('{0}/output/{1}.txt'.format(BASE_DIR, self.main_domain), 'a') 110 | for name, node in zone_tmp.nodes.items(): 111 | rdatasets = node.rdatasets 112 | for rdataset in rdatasets: 113 | file_handle.write('{0}\t{1}\n'.format(name, rdataset)) 114 | print('\t{0} {1}'.format(name, rdataset)) 115 | file_handle.close() 116 | -------------------------------------------------------------------------------- /output/g-queen.com.txt: -------------------------------------------------------------------------------- 1 | @ 86400 IN SOA ns1.i-netex.com. techadmin.oc11.com. 1371851839 10800 3600 604800 86400 2 | @ 86400 IN NS ns1.i-netex.com. 3 | 86400 IN NS ns2.i-netex.com. 4 | @ 86400 IN A b'67.43.170.100' 5 | @ 86400 IN MX 10 mail 6 | @ 86400 IN TXT "v=spf1 +ip4:67.43.170.xn--0/24 all" "-j1f" 7 | admin 86400 IN A b'67.43.170.12' 8 | ml 86400 IN A b'67.43.170.25' 9 | ml 86400 IN MX 50 ml 10 | www3 86400 IN A b'67.43.170.100' 11 | webmail 86400 IN A b'67.43.170.2' 12 | ftp 86400 IN CNAME @ 13 | munin 86400 IN A b'67.43.170.104' 14 | m 86400 IN A b'67.43.170.100' 15 | cache1 86400 IN A b'67.43.170.67' 16 | ana 86400 IN A b'67.43.170.52' 17 | ns 86400 IN A b'67.43.170.2' 18 | mail 86400 IN A b'67.43.170.2' 19 | lists 86400 IN CNAME @ 20 | www4 86400 IN A b'67.43.170.100' 21 | www 86400 IN CNAME @ 22 | www2 86400 IN A b'67.43.170.100' 23 | -------------------------------------------------------------------------------- /output/mail.qq.com.txt: -------------------------------------------------------------------------------- 1 | *.mail.qq.com [] ['14.17.19.106'] 2 | 3g.mail.qq.com ['i.mail.qq.com'] ['219.133.60.166', '59.37.96.108'] 3 | a.mail.qq.com ['i.mail.qq.com'] ['219.133.60.166', '59.37.96.108'] 4 | app.mail.qq.com ['i.mail.qq.com'] ['219.133.60.166', '59.37.96.108'] 5 | api.mail.qq.com [] ['112.90.136.160'] 6 | auth.mail.qq.com ['i.wework.qq.com'] ['14.17.41.162', '183.57.48.56'] 7 | bbs.mail.qq.com ['demo.forum.discuz.qq.com'] ['101.226.76.33'] 8 | biz.mail.qq.com [] ['219.153.42.238'] 9 | blog.mail.qq.com ['common.mail.qq.com'] ['14.18.245.164'] 10 | campus.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 11 | cnc.mail.qq.com [] ['163.177.72.161', '163.177.89.191', '58.251.61.186'] 12 | common.mail.qq.com [] ['14.18.245.164'] 13 | d1.mail.qq.com [] ['113.108.67.16'] 14 | d8.mail.qq.com [] ['119.147.16.232'] 15 | d9.mail.qq.com [] ['119.147.20.171'] 16 | d5.mail.qq.com [] ['113.108.77.19'] 17 | d4.mail.qq.com [] ['1.1.1.1'] 18 | d2.mail.qq.com [] ['1.1.1.1'] 19 | d6.mail.qq.com [] ['183.60.2.33'] 20 | d3.mail.qq.com [] ['1.1.1.1'] 21 | domain.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 22 | dr.mail.qq.com ['stockweb.mail.qq.com'] ['113.108.11.37', '14.17.18.193'] 23 | edu.mail.qq.com [] ['115.25.209.29'] 24 | en.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 25 | ftn.mail.qq.com ['i.mail.qq.com'] ['219.133.60.166', '59.37.96.108'] 26 | gp.mail.qq.com [] ['14.18.245.190'] 27 | group.mail.qq.com [] ['219.133.48.237'] 28 | hk.mail.qq.com [] ['1.1.1.1'] 29 | i.mail.qq.com [] ['219.133.60.166', '59.37.96.108'] 30 | i1.mail.qq.com [] ['1.1.1.1'] 31 | i3.mail.qq.com [] ['1.1.1.1'] 32 | i5.mail.qq.com [] ['1.1.1.1'] 33 | i2.mail.qq.com [] ['1.1.1.1'] 34 | imap.mail.qq.com [] ['219.153.42.238'] 35 | m.mail.qq.com [] ['183.61.46.182', '59.37.96.184'] 36 | mob.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 37 | open.mail.qq.com ['common.mail.qq.com'] ['14.18.245.164'] 38 | oss.mail.qq.com ['common.mail.qq.com'] ['14.18.245.164'] 39 | pic.mail.qq.com [] ['1.1.1.1'] 40 | pop.mail.qq.com [] ['219.153.42.238'] 41 | r.mail.qq.com ['reader.qq.com'] ['180.153.8.30', '180.153.8.42'] 42 | r1.mail.qq.com [] ['1.1.1.1'] 43 | res.mail.qq.com [] ['113.108.20.83', '59.37.96.191'] 44 | rl.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 45 | rw.mail.qq.com ['reader.qq.com'] ['180.153.8.30', '180.153.8.42'] 46 | s.mail.qq.com ['sync.qq.com'] ['1.1.1.1'] 47 | sales.mail.qq.com [] ['183.62.126.230', '183.62.126.232'] 48 | service.mail.qq.com ['common.mail.qq.com'] ['14.18.245.164'] 49 | smart.mail.qq.com ['service.mail.qq.com', 'common.mail.qq.com'] ['14.18.245.164'] 50 | smtp.mail.qq.com [] ['219.153.42.238'] 51 | spf.mail.qq.com [] ['1.1.1.1'] 52 | stream.mail.qq.com [] ['119.147.192.114', '14.17.32.53'] 53 | tel.mail.qq.com [] ['14.17.19.167', '14.17.32.178'] 54 | test.mail.qq.com [] ['1.1.1.1'] 55 | u1.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 56 | u2.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 57 | u3.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 58 | u4.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 59 | u5.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 60 | u6.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 61 | u7.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 62 | u8.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 63 | u9.mail.qq.com ['upload.mail.qq.com'] ['119.147.207.157'] 64 | upload.mail.qq.com [] ['119.147.207.157'] 65 | url.mail.qq.com ['ur', 'common.mail.qq.com'] ['14.18.245.164'] 66 | vip.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 67 | w.mail.qq.com ['m.mail.qq.com'] ['183.61.46.182', '59.37.96.184'] 68 | w1.mail.qq.com [] ['1.1.1.1'] 69 | wap.mail.qq.com ['m.mail.qq.com'] ['183.61.46.182', '59.37.96.184'] 70 | wap2.mail.qq.com ['nul'] ['1.1.1.1'] 71 | webdisk.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 72 | wp.mail.qq.com [] ['14.18.245.239', '219.133.60.209'] 73 | ws.mail.qq.com ['stockweb.mail.qq.com'] ['113.108.11.37', '14.17.18.193'] 74 | www.mail.qq.com ['mail.qq.com'] ['14.17.42.24', '14.18.245.237', '183.60.15.162', '183.60.15.245'] 75 | xy.mail.qq.com ['stockweb.mail.qq.com'] ['113.108.11.37', '14.17.18.193'] 76 | z.mail.qq.com [] ['1.1.1.1'] 77 | zzz.mail.qq.com ['z.mail.qq.com'] ['1.1.1.1'] 78 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | future 2 | gevent --------------------------------------------------------------------------------