Ticket #5450: dnssec-security-aware-nonvalidating-client.patch
File dnssec-security-aware-nonvalidating-client.patch, 61.7 KB (added by , 8 years ago) |
---|
-
names/client.py
71 71 protocol = property(_getProtocol) 72 72 73 73 74 def __init__(self, resolv=None, servers=None, timeout=(1, 3, 11, 45), reactor=None): 74 def __init__(self, 75 resolv=None, 76 servers=None, 77 timeout=(1, 3, 11, 45), 78 reactor=None, 79 dnssecConfig=None): 75 80 """ 76 81 Construct a resolver which will query domain name servers listed in 77 82 the C{resolv.conf(5)}-format file given by C{resolv} as well as … … 98 103 L{IReactorTCP} which will be used to establish connections, listen 99 104 for DNS datagrams, and enforce timeouts. If not provided, the 100 105 global reactor will be used. 106 107 @param dnssecConfig: A provider of DNSSEC parameters - see common.DnssecConfig() 101 108 102 109 @raise ValueError: Raised if no nameserver addresses can be found. 103 110 """ 104 common.ResolverBase.__init__(self )111 common.ResolverBase.__init__(self, dnssecConfig) 105 112 106 113 if reactor is None: 107 114 from twisted.internet import reactor … … 129 136 130 137 self.maybeParseConfig() 131 138 132 133 139 def __getstate__(self): 134 140 d = self.__dict__.copy() 135 141 d['connections'] = [] … … 240 246 for (d, q, t) in self.pending: 241 247 self.queryTCP(q, t).chainDeferred(d) 242 248 del self.pending[:] 249 250 def connectionLost(self, protocol): 251 """ 252 Called on UDP protocol when a DNS UDP query times out and is retried 253 on the TCP protocol. 30 seconds after the TCP query completes, this 254 method is called on the UDP protocol. 255 """ 256 self.connections.remove(protocol) 257 del protocol 243 258 244 245 259 def messageReceived(self, message, protocol, address = None): 246 260 log.msg("Unexpected message (%d) received from %r" % (message.id, address)) 247 261 … … 370 384 return self.queryTCP(message.queries).addCallback(self.filterAnswers) 371 385 if message.rCode != dns.OK: 372 386 return failure.Failure(self.exceptionForCode(message.rCode)(message)) 373 return (message.answers, message.authority, message.additional) 387 388 #if edns0 is enabled, return a reference to the message as the 4th member of 389 #the tuple, so the caller can access AD. You could just return AD, but if you 390 #return message, the caller can also access a reference to the query and you 391 #never know when that might come in handy. 392 if self.dnssecConfig.ednsEnabled: 393 return (message.answers, message.authority, message.additional, message) 394 else: 395 #not edns0Enabled - return a legacy 3-tuple 396 return (message.answers, message.authority, message.additional) 374 397 375 376 398 def _lookup(self, name, cls, type, timeout): 377 399 """ 378 400 Build a L{dns.Query} for the given parameters and dispatch it via UDP. … … 942 964 @rtype: C{Deferred} 943 965 """ 944 966 return getResolver().lookupNamingAuthorityPointer(name, timeout) 967 968 def lookupDNSKey(name, timeout=None): 969 """ 970 DNSKEY lookup. 971 972 @type name: C{str} 973 @param name: DNS name to resolve. 974 975 @type timeout: Sequence of C{int} 976 @param timeout: Number of seconds after which to reissue the query. 977 When the last timeout expires, the query is considered failed. 978 979 @rtype: C{Deferred} 980 """ 981 return getResolver().lookupDNSKey(name, timeout) 982 No newline at end of file -
names/common.py
18 18 19 19 EMPTY_RESULT = (), (), () 20 20 21 class DnssecConfig(): 22 """ 23 Sets recDes and the DNSSEC parameters. See RFC's 4033, 4034 and 4035. 24 25 recDes (RD) - Recursion Desired. Not a DNSSEC parameter and does not require ednsEnabled, 26 but still nice to be able to control whether or not you're asking for recursion. 27 (bool) 28 29 ednsEnabled - EDNS Enabled adds an OPT record to the query. The OPT record contains a 30 version field that indicates the version of EDNS that you can handle. 31 Presently, only EDNS Version 0 is defined. 32 (bool) 33 34 maxUdpPktSz - The max size UDP packet (bytes) that your end-to-end network can handle 35 (on a modern network a reliable size is 1492, although up to 65535 is possible). 36 Requires ednsEnabled. 37 (int) 38 39 dnssecOK (DO) - Dnssec Ok. A bit that indicates you want DNSSEC RR's and validation 40 if the resolver validates. If DO is set, AD will be set in the response 41 if the answer validates. Requires ednsEnabled. 42 (bool) 43 44 chkDis (CD) - Checking Disabled. If DO and CD are set, a validating resolver won't do 45 validation but will return the DNSSEC RR's so that YOU can. 46 (bool) 47 48 version - sets the edns version level. Currently, only 0 is defined and supported. 49 (int) 50 51 authData (AD) - Authentic Data. If set in a response from a validating resolver that you can 52 trust, indicates that the validating resolver validated the answer. Requires 53 ednsEnabled and DO set. (See note below.) 54 (bool) 55 56 Note - RFC-4035 does not define AD for a query. However, most validating resolvers seem 57 to honor it set in a query and return AD set in a response to a query that validates. But 58 you should not to rely on this behavior - set DO instead. 59 """ 60 def __init__(self, 61 recDes=True, 62 ednsEnabled=False, 63 maxUdpPktSz=512, 64 dnssecOk=False, 65 chkDis=False, 66 version=0, 67 authData=False): 68 69 self.recDes = recDes 70 self.ednsEnabled = ednsEnabled 71 self.maxUdpPktSz = maxUdpPktSz 72 self.dnssecOk = dnssecOk 73 self.chkDis = chkDis 74 self.version = version 75 self.authData = authData 76 77 assert not self.ednsEnabled or 512 <= self.maxUdpPktSz <= 65535 78 assert version == 0 79 21 80 class ResolverBase: 22 81 """ 23 82 L{ResolverBase} is a base class for L{IResolver} implementations which … … 36 95 37 96 typeToMethod = None 38 97 39 def __init__(self ):98 def __init__(self, dnssecConfig=None): 40 99 self.typeToMethod = {} 41 100 for (k, v) in typeToMethod.items(): 42 101 self.typeToMethod[k] = getattr(self, v) 102 self.dnssecConfig = dnssecConfig 103 if self.dnssecConfig == None: 104 self.dnssecConfig = DnssecConfig() 43 105 44 45 106 def exceptionForCode(self, responseCode): 46 107 """ 47 108 Convert a response code (one of the possible values of … … 200 261 @see: twisted.names.client.lookupAllRecords 201 262 """ 202 263 return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) 264 265 def lookupDNSKey(self, name, timeout=None): 266 """ 267 @see: twisted.names.client.lookupDNSKey 268 """ 269 return self._lookup(name, dns.IN, dns.DNSKEY, timeout) 203 270 204 271 def getHostByName(self, name, timeout = None, effort = 10): 205 272 """ … … 268 335 dns.MX: 'lookupMailExchange', 269 336 dns.TXT: 'lookupText', 270 337 dns.SPF: 'lookupSenderPolicy', 338 dns.DNSKEY:'lookupDNSKey', 271 339 272 340 dns.RP: 'lookupResponsibility', 273 341 dns.AFSDB: 'lookupAFSDatabase', -
names/dns.py
15 15 __all__ = [ 16 16 'IEncodable', 'IRecord', 17 17 18 'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', ' HINFO',18 'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'DNSKEY', 'DS', 'HINFO', 19 19 'MAILA', 'MAILB', 'MB', 'MD', 'MF', 'MG', 'MINFO', 'MR', 'MX', 20 'NAPTR', 'NS', 'NULL', 'PTR', 'RP', 'SOA', 'SPF', 'SRV', 'TXT', 'WKS', 20 'NAPTR', 'NS', 'NSEC', 'NSEC3', 'NULL', 'OPT', 'PTR', 'RP', 'RRSIG', 'SOA', 'SPF', 21 'SRV', 'TXT', 'WKS', 21 22 22 23 'ANY', 'CH', 'CS', 'HS', 'IN', 23 24 … … 26 27 'EFORMAT', 'ENAME', 'ENOTIMP', 'EREFUSED', 'ESERVER', 27 28 28 29 'Record_A', 'Record_A6', 'Record_AAAA', 'Record_AFSDB', 'Record_CNAME', 29 'Record_DNAME', 'Record_HINFO', 'Record_MB', 'Record_MD', 'Record_MF', 30 'Record_DNAME', 'Record_DNSKEY', 'Record_DS', 'Record_HINFO', 'Record_MB', 31 'Record_MD', 'Record_MF', 30 32 'Record_MG', 'Record_MINFO', 'Record_MR', 'Record_MX', 'Record_NAPTR', 31 'Record_NS', 'Record_N ULL', 'Record_PTR', 'Record_RP', 'Record_SOA',32 'Record_S PF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord',33 'Record_NS', 'Record_NSEC', 'Record_NSEC3', 'Record_NULL', 'Record_OPT', 'Record_PTR', 'Record_RP', 'Record_RRSIG', 34 'Record_SOA', 'Record_SPF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 33 35 34 36 'QUERY_CLASSES', 'QUERY_TYPES', 'REV_CLASSES', 'REV_TYPES', 'EXT_QUERIES', 35 37 36 'Charstr', 'Message', 'Name', ' Query', 'RRHeader', 'SimpleRecord',38 'Charstr', 'Message', 'Name', 'OPTHeader', 'Query', 'RRHeader', 'SimpleRecord', 37 39 'DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', 38 40 39 41 'OK', 'OP_INVERSE', 'OP_NOTIFY', 'OP_QUERY', 'OP_STATUS', 'OP_UPDATE', … … 46 48 # System imports 47 49 import warnings 48 50 51 import re 52 49 53 import struct, random, types, socket 50 54 51 55 import cStringIO as StringIO … … 54 58 55 59 from zope.interface import implements, Interface, Attribute 56 60 61 from base64 import b64decode, b64encode 57 62 63 58 64 # Twisted imports 59 65 from twisted.internet import protocol, defer 60 66 from twisted.internet.error import CannotListenError 61 67 from twisted.python import log, failure 62 68 from twisted.python import util as tputil 63 69 from twisted.python import randbytes 70 from twisted.names.serialNumberArithmetic import SNA, DateSNA 64 71 65 72 66 73 def randomSource(): … … 79 86 NAPTR = 35 80 87 A6 = 38 81 88 DNAME = 39 89 OPT = 41 90 DS = 43 91 RRSIG = 46 92 NSEC = 47 93 DNSKEY = 48 94 NSEC3 = 50 82 95 SPF = 99 83 96 84 97 QUERY_TYPES = { … … 108 121 NAPTR: 'NAPTR', 109 122 A6: 'A6', 110 123 DNAME: 'DNAME', 111 SPF: 'SPF' 124 OPT: 'OPT', 125 DS: 'DS', 126 RRSIG: 'RRSIG', 127 NSEC: 'NSEC', 128 DNSKEY: 'DNSKEY', 129 NSEC3: 'NSEC3', 130 SPF: 'SPF', 112 131 } 113 132 114 133 IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) … … 277 296 def __str__(self): 278 297 return self.string 279 298 280 281 282 299 class Name: 283 300 implements(IEncodable) 284 301 … … 370 387 371 388 def __str__(self): 372 389 return self.name 390 391 class Sigstr(object): 392 ''' 393 for signatures and keys. display as b64 encoded 394 ''' 395 implements(IEncodable) 396 397 def __init__(self, string=''): 398 if not isinstance(string, str): 399 raise ValueError("%r is not a string" % (string, )) 400 self.string = string #b64encoded string 401 402 def encode(self, strio, compDict=None): 403 ''' 404 Write the byte representation (the un-b64-encoded string) 405 to the file. 406 407 @type strio: file 408 @param srio: The byte representation of this signature or key 409 will be written to this file 410 411 @type compDict: dict 412 @param compDict: not used. 413 ''' 414 strio.write(b64decode(self.string)) 415 416 def decode(self, strio, length=None): 417 ''' 418 Decode a signature or a key. 373 419 420 @type strio: file 421 @param strio: Exactly length bytes will be read from this file 422 to decode the full signature or key 423 424 @type length: int 425 @param lenth: length must always be given. A signature or key 426 is always the last thing in an RR and so you can always determine 427 its length. 428 ''' 429 self.string = '' 430 if length == None: 431 return 432 433 assert isinstance(length, int) 434 buff = readPrecisely(strio, length) 435 self.string = b64encode(buff) 436 437 def __eq__(self, other): 438 if isinstance(other, Sigstr): 439 return self.string == other.string 440 return False 441 442 def __hash__(self): 443 return hash(self.string) 444 445 def __str__(self): 446 return self.string 447 448 449 class TypeBitmaps(object): 450 ''' 451 bitmap encoding scheme used by NSEC and NSEC3 RR's 452 to indicate the RRset types that exist at the 453 NSEC/NSEC3 RR's original owner name or hashed name. 454 See RFC 4034 and RFC 5155. 455 ''' 456 fmt = 'BB' 457 typeRegex = re.compile('TYPE(\d+)') 458 459 def __init__(self, string=''): 460 self.string = string 461 462 def encode(self, strio, compDict=None): 463 """ 464 Encode the string field, which consists of a set 465 of type names, into an NSEC/NSEC3 type bitmap. 466 467 @type strio: file 468 @param strio: the byte representation of the type bitmap 469 will be written to this file. 470 471 @type compDict: dict 472 @param compDict: not used. 473 """ 474 if not self.string: 475 return; 476 477 #get a sorted list of RR Type Values 478 mnus = self.string.split(' ') 479 mnuVals = [] 480 for mnu in mnus: 481 mnuVal = REV_TYPES.get(mnu, None) 482 if not mnuVal: 483 m = self.typeRegex.match(mnu) 484 if m.groups(): 485 mnuVal = int(m.group(1)) 486 assert mnuVal < 65536 487 else: 488 log.err("can't parse %s in %s" % (mnu, self.string, )) 489 continue; 490 mnuVals.append(mnuVal) 491 mnuVals.sort() 492 493 #convert that to a dict of windows and lists 494 windDict = {} 495 for v in mnuVals: 496 window = (v >> 8) & 0xFF 497 if window not in windDict: 498 windDict[window] = [] 499 windDict[window].append(v & 0xFF) 500 501 #have to sort the keys - they're not in order! 502 windows = windDict.keys() 503 windows.sort() 504 505 #create the bitmaps 506 bmap = bytearray() 507 for w in windows: 508 bmapseg = bytearray(32) 509 maxoff = 0 510 for v in windDict[w]: 511 vm1 = v - 1 512 off = vm1 >> 3 513 bit = vm1 & 0x7 514 msk = 1 << bit 515 bmapseg[off] |= msk 516 maxoff = max(off, maxoff) 517 bmapseg = bmapseg[0:maxoff+1] 518 bmap += chr(w) + chr(maxoff+1) + bmapseg 519 520 strio.write(str(bmap)) 521 522 def decode(self, strio, length=None): 523 """ 524 Decode an NSEC/NSEC3 type bitmap into a string 525 representation of type names. 526 """ 527 self.type_bitmaps = "" 528 if length == None: 529 return 530 531 type_bitmaps = bytearray() 532 l = struct.calcsize(self.fmt) 533 parsed_length = 0 534 while parsed_length < length: 535 buff = readPrecisely(strio, l) 536 wb_num, bm_len = struct.unpack(self.fmt, buff) 537 assert parsed_length + 2 + bm_len <= length 538 bm = readPrecisely(strio, bm_len) 539 byteNum = -1 540 for b in bm: 541 byteNum += 1 542 ob = ord(b) 543 if ob == 0: 544 continue 545 546 for v in range(8): 547 msk = 1<<v 548 if ob & msk: 549 val = wb_num*256 + byteNum*8 + v + 1 550 mnu = QUERY_TYPES.get(val, None) 551 if not mnu: 552 mnu = 'TYPE' + str(val) 553 type_bitmaps += (mnu + ' ') 554 555 parsed_length += 2 + bm_len 556 557 self.type_bitmaps = str(type_bitmaps[0:-1]) 558 559 def __eq__(self, other): 560 if isinstance(other, TypeBitmaps): 561 return self.string == other.string 562 return False 563 564 def __hash__(self): 565 return hash(self.string) 566 567 def __str__(self): 568 return self.string 569 570 374 571 class Query: 375 572 """ 376 573 Represent a single DNS query. … … 434 631 return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 435 632 436 633 437 class RRHeader(tputil.FancyEqMixin): 634 635 class OPTHeader(tputil.FancyEqMixin): 438 636 """ 637 A OPT record header. 638 639 @cvar fmt: C{str} specifying the byte format of an OPT Header. 640 641 @ivar name: Root (0, 8-bits) 642 @ivar type: 41 (OPT Record) 643 @ivar payload: An object that implements the IEncodable interface 644 @ivar auth: Whether this header is authoritative or not. 645 """ 646 647 implements(IEncodable) 648 649 compareAttributes = ('name', 'type', 'payload', 'auth') 650 651 fmt = "!H" 652 653 name = None 654 type = None 655 payload = None 656 657 #OPTHeader _really_ has no ttl or rdlength, but the 658 #existence of the attributes is required. 659 ttl = None 660 rdlength = None 661 662 cachedResponse = None 663 664 def __init__(self, payload=None, auth=False): 665 """ 666 @type name: C{str} 667 @param name: Root (0) 668 669 @type type: C{int} 670 @param type: Query type 41. 671 672 @type payload: An object implementing C{IEncodable} 673 @param payload: The OPT payload 674 """ 675 assert (payload is None) or (payload.TYPE == OPT) 676 677 self.name = 0 678 self.type = OPT 679 self.payload = payload 680 self.auth = auth 681 682 def encode(self, strio, compDict=None): 683 strio.write(struct.pack('!B', 0)) 684 strio.write(struct.pack(self.fmt, self.type)) 685 if self.payload: 686 prefix = strio.tell() 687 self.payload.encode(strio, compDict) 688 aft = strio.tell() 689 strio.seek(prefix - 2, 0) 690 strio.write(struct.pack('!H', aft - prefix)) 691 strio.seek(aft, 0) 692 693 def decode(self, strio, length = None): 694 self.name.decode(strio) 695 l = struct.calcsize(self.fmt) 696 buff = readPrecisely(strio, l) 697 r = struct.unpack(self.fmt, buff) 698 self.type = r[0] 699 700 def isAuthoritative(self): 701 return self.auth 702 703 def __str__(self): 704 return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 705 706 @staticmethod 707 def factory(strio): 708 ''' 709 reads enough of the stream to figure out if what is there is 710 an OPTHeader or an RRHeader 711 ''' 712 beginPos = strio.tell() 713 name = Name() 714 name.decode(strio) 715 type = struct.unpack(OPTHeader.fmt, readPrecisely(strio, 2))[0] 716 717 if len(name.name) == 0 and type == OPT: 718 return OPTHeader() 719 else: 720 #back up to the beginning and try again 721 strio.seek(beginPos, 0) 722 rrh = RRHeader() 723 rrh.decode(strio) 724 return rrh 725 726 __repr__ = __str__ 727 728 729 class RRHeader(OPTHeader): 730 """ 439 731 A resource record header. 440 732 441 733 @cvar fmt: C{str} specifying the byte format of an RR. … … 1467 1759 return hash(tuple(self.data)) 1468 1760 1469 1761 1762 class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 1763 """ 1764 EDNS0 Option record. 1765 1766 @type payload_size: C{int} 1767 @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 1768 network can handle. 1769 1770 @type dnssecOk: C{bool} 1771 @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 1772 validation (and set the AD bit if the response validates). 1773 1774 @type version: C{int} 1775 @ivar version: The version of DNSSEC used. Currently only version 0 1776 is defined. 1777 """ 1778 implements(IEncodable, IRecord) 1779 TYPE = OPT 1780 fmt = '!HBBHH' 1781 1782 fancybasename = 'OPT' 1783 showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 1784 compareAttributes = ('payload_size', 'flags', 'version') 1785 1786 def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 1787 self.payload_size = payload_size 1788 self.version = version 1789 self.flags = (dnssecOk & 1) << 15 1790 1791 def encode(self, strio, compDict = None): 1792 OPTHeader().encode(strio) 1793 strio.write(struct.pack('!H', self.payload_size)) 1794 strio.write(struct.pack('!B', 0)) # high order 0 1795 strio.write(struct.pack('!B', self.version)) 1796 strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 1797 strio.write(struct.pack('!H', 0)) # Data length: 0 1798 1799 def decode(self, strio, length=None): 1800 ''' 1801 are OPT Records always 0 rdlength? 1802 ''' 1803 l = struct.calcsize(self.fmt) 1804 buff = readPrecisely(strio, l) 1805 r = struct.unpack(self.fmt, buff) 1806 self.payload_size, z, self.version, self.flags, length = r 1807 assert length == 0 1808 1809 def __hash__(self): 1810 return hash((self.payload_size, self.version, self.flags)) 1470 1811 1812 class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 1813 """ 1814 DNSSEC RRSIG record. See RFC 4034 for details. 1815 1816 @type type_covered: C{int} 1817 @ivar type_covered: Identifies the type of the RRset that this RRSIG covers. 1818 1819 @type algo: C{int} 1820 @ivar algo: Identifies the crypto algorithm type used to create the signature. 1821 (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 1822 1823 @type labels: C{int} 1824 @ivar labels: Specifies the number of labels in the original RRSIG RR owner name. 1825 A validator can use this to determine whether the answer was synthesized from 1826 a wildcard. 1827 1828 @type original_ttl: C{int} 1829 @ivar original_ttl: Specifies the TTL of the covered RRset as it appears in the 1830 authoritative zone. 1831 1832 @type sig_expiration: C{int} 1833 @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 1834 since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 1835 1836 @type sig_inception: C{int} 1837 @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 1838 since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 1839 1840 @type key_tag: C{int} 1841 @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates this 1842 signature, in network byte order. See RFC 4034 App B. 1843 1844 @type signers_name: L{Name} 1845 @ivar signers_name: Identifies the owner name of the DNSKEY RR that a validator 1846 should use to validate this signature. Must not use DNS name compression. 1847 1848 @type signature: L{Sigstr} 1849 @ivar signature: Contains the cryptographic signature that covers the RRSIG 1850 RDATA (excluding the Signature field and the RRset specified by the RRSIG 1851 owner name, RRSIG class and RRSIG Type Covered fields. 1852 1853 @type ttl: C{int} 1854 @ivar ttl: The maximum number of seconds which this record should be 1855 cached. 1856 """ 1857 implements(IEncodable, IRecord) 1858 TYPE = RRSIG 1859 fmt = '!HBBIIIH' 1860 1861 fancybasename = 'RRSIG' 1862 showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 1863 ('_sig_expiration', 'sig_expiration', '%s'), 1864 ('_sig_inception', 'sig_inception', '%s'), 1865 'key_tag', 1866 ('signers_name', 'signers_name', '%s'), 1867 ('_signature', 'signature', '%s'), 'ttl') 1868 compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 1869 'sig_expiration', 'sig_inception', 'key_tag', 1870 'signers_name', 'signature', 'ttl') 1871 1872 _sig_expiration = property(lambda self: str(self.sig_expiration)) 1873 _sig_inception = property(lambda self: str(self.sig_inception)) 1874 _signature = property(lambda self: self.signature.string) 1875 1876 def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0, 1877 sig_expiration='', sig_inception='', key_tag=0, 1878 signers_name='', signature='', ttl=None): 1879 self.type_covered = type_covered 1880 self.algo = algo 1881 self.labels = labels 1882 self.original_ttl = original_ttl 1883 self.sig_expiration = DateSNA(sig_expiration) 1884 self.sig_inception = DateSNA(sig_inception) 1885 self.key_tag = key_tag 1886 self.signers_name = Name(signers_name) 1887 self.signature = Sigstr(signature) 1888 self.ttl = str2time(ttl) 1889 1890 def encode(self, strio, compDict = None): 1891 strio.write(struct.pack(self.fmt, 1892 self.type_covered, 1893 self.algo, 1894 self.labels, 1895 self.original_ttl, 1896 self.sig_expiration.asInt(), 1897 self.sig_inception.asInt(), 1898 self.key_tag)) 1899 self.signers_name.encode(strio, None) 1900 self.signature.encode(strio, compDict) 1901 1902 def decode(self, strio, length=None): 1903 start = strio.tell() 1904 l = struct.calcsize(self.fmt) 1905 buff = readPrecisely(strio, l) 1906 r = struct.unpack(self.fmt, buff) 1907 self.type_covered, self.algo, self.labels, self.original_ttl, \ 1908 sig_expiration, sig_inception, self.key_tag = r 1909 self.sig_expiration = DateSNA.fromInt(sig_expiration) 1910 self.sig_inception = DateSNA.fromInt(sig_inception) 1911 self.signers_name.decode(strio) 1912 here = strio.tell() 1913 self.signature.decode(strio, length + start - here if length else None) 1914 1915 def __hash__(self): 1916 return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 1917 self.sig_expiration, self.sig_inception, self.key_tag, 1918 self.signers_name, self.signature)) 1919 1920 class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 1921 """ 1922 A DNSSEC DS record. 1923 1924 @type key_tag: C{int} 1925 @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS record. 1926 1927 @type algo: C{int} 1928 @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this DS record. 1929 1930 @type digest_type: C{int} 1931 @ivar digest_type: Identifies the algorithm used to construct the digest field. 1932 1933 @type digest: L{Sigstr} 1934 @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by the 1935 algorithm identified by the digest_type field. 1936 1937 @type ttl: C{int} 1938 @ivar ttl: The maximum number of seconds which this record should be 1939 cached. 1940 """ 1941 implements(IEncodable, IRecord) 1942 TYPE = DS 1943 fmt = '!HBB' 1944 1945 fancybasename = 'DS' 1946 showAttributes = ('key_tag', 'algo', 'digest_type', ('_digest', 'digest', '%s'), 'ttl') 1947 compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 1948 1949 _digest = property(lambda self: self.digest.string) 1950 1951 def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 1952 self.key_tag = key_tag 1953 self.algo = algo 1954 self.digest_type = digest_type 1955 self.digest = Sigstr(digest) 1956 self.ttl = str2time(ttl) 1957 1958 def encode(self, strio, compDict = None): 1959 strio.write(struct.pack(self.fmt, 1960 self.key_tag, 1961 self.algo, 1962 self.digest_type)) 1963 self.digest.encode(strio, None) 1964 1965 def decode(self, strio, length=None): 1966 start = strio.tell() 1967 l = struct.calcsize(self.fmt) 1968 buff = readPrecisely(strio, l) 1969 r = struct.unpack(self.fmt, buff) 1970 self.key_tag, self.algo, self.digest_type = r 1971 here = strio.tell() 1972 self.digest.decode(strio, length + start - here if length else None) 1973 1974 def __hash__(self): 1975 return hash((self.key_tag, self.algo, self.digest_type, self.digest)) 1976 1977 class Record_DNSKey(tputil.FancyEqMixin, tputil.FancyStrMixin): 1978 """ 1979 A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 1980 1981 @type flags: C{int} 1982 @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 1983 DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 1984 the name of a zone. If bit 7 has value 0, then the DNSKEY record 1985 holds some other type of DNS public key and MUST NOT be used to 1986 verify RRSIGs that cover RRsets. 1987 Bit 15 is the Secure Entry Point flag. See RFC 3757.) 1988 All other bits are reserved and must be zero. 1989 1990 @type protocol: C{int} 1991 @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 1992 if this field does not contain 3. 1993 1994 @type algo: C{int} 1995 @ivar algo: Identifies the public key's cryptographic algorithm and determines 1996 the format of the pub_key field. See RFC 4034 App A. 1997 1998 @type pub_key: L{Sigstr} 1999 @ivar pub_key: Holds the public key material. 2000 2001 @type ttl: C{int} 2002 @ivar ttl: The maximum number of seconds which this record should be 2003 cached. 2004 """ 2005 implements(IEncodable, IRecord) 2006 TYPE = DNSKEY 2007 fmt = '!HBB' 2008 2009 fancybasename = 'DNSKEY' 2010 showAttributes = ('flags', 'protocol', 'algo', ('_pub_key', 'pub_key', '%s'), 'ttl') 2011 compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 2012 2013 _pub_key = property(lambda self: self.pub_key.string) 2014 2015 def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 2016 self.flags = flags 2017 self.protocol = protocol 2018 self.algo = algo 2019 self.pub_key = Sigstr(pub_key) 2020 self.ttl = str2time(ttl) 2021 2022 def encode(self, strio, compDict = None): 2023 strio.write(struct.pack(self.fmt, 2024 self.flags, 2025 self.protocol, 2026 self.algo)) 2027 self.pub_key.encode(strio, None) 2028 2029 def decode(self, strio, length=None): 2030 start = strio.tell() 2031 l = struct.calcsize(self.fmt) 2032 buff = readPrecisely(strio, l) 2033 r = struct.unpack(self.fmt, buff) 2034 self.flags, self.protocol, self.algo = r 2035 here = strio.tell() 2036 self.pub_key.decode(strio, length + start - here if length else None) 2037 2038 def __hash__(self): 2039 return hash((self.flags, self.protocol, self.algo, self.pub_key)) 2040 2041 class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 2042 """ 2043 A DNSSEC NSEC record provides authenticated denial of existance for DNS data. 2044 2045 A DNSSEC NSEC record lists: 2046 2047 1) the next owner name in canonical ordering of the zone that contains authoritataive 2048 data or a delegation point NS RRset. 2049 2050 2) the set of RR types present at the NSEC RR's owner name. 2051 2052 @type nxt_name: L{Name} 2053 @ivar nxt_name: The next owner name that has authoritative data or contains a 2054 delegation point NS RRset. 2055 2056 @type type_bitmaps: L{TypeBitmaps} 2057 @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's owner name. 2058 2059 @type ttl: C{int} 2060 @ivar ttl: The maximum number of seconds which this record should be 2061 cached. 2062 """ 2063 implements(IEncodable, IRecord) 2064 TYPE = NSEC 2065 2066 fancybasename = 'NSEC' 2067 showAttributes = (('nxt_name', 'nxt_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 2068 compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 2069 2070 _type_bitmaps = property(lambda self: self.type_bitmaps.string) 2071 2072 def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 2073 self.nxt_name = Name(nxt_name) 2074 self.type_bitmaps = TypeBitmaps(type_bitmaps) 2075 self.ttl = str2time(ttl) 2076 2077 def encode(self, strio, compDict = None): 2078 self.nxt_name.encode(strio, None) 2079 self.type_bitmaps.encode(strio, None) 2080 2081 def decode(self, strio, length=None): 2082 start = strio.tell() 2083 self.nxt_name.decode(strio, None) 2084 here = strio.tell() 2085 self.type_bitmaps.decode(strio, length + start - here if length else None) 2086 2087 def __hash__(self): 2088 return hash((self.nxt_name, self.type_bitmaps)) 2089 2090 class Record_NSEC3(tputil.FancyEqMixin, tputil.FancyStrMixin): 2091 """ 2092 A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of existance 2093 for DNS data and permits a gradual expansion of delegation-centric zones. 2094 2095 A DNSSEC NSEC3 record lists: 2096 2097 1) the set of RR types present at the original owner name of the NSEC RR. 2098 2099 2) the next hashed owner name in the hash order of the zone. 2100 2101 @type hash_algo: C{int} 2102 @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 2103 2104 @type flags: C{int} 2105 @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the 2106 opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 2107 delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 2108 2109 @type iterations: C{int} 2110 @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 2111 2112 @type salt: L{Charset} 2113 @ivar salt: Identifies the salt value provided to the hash. 2114 2115 @type nxt_hash_owner_name: L{Charset} 2116 @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone in hash order. 2117 2118 @type type_bitmaps: L{TypeBitmaps} 2119 @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's original owner name. 2120 2121 @type ttl: C{int} 2122 @ivar ttl: The maximum number of seconds which this record should be 2123 cached. 2124 """ 2125 implements(IEncodable, IRecord) 2126 TYPE = NSEC3 2127 fmt = '!BBH' 2128 2129 fancybasename = 'NSEC3' 2130 showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 2131 compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 2132 2133 _salt = property(lambda self: self.salt.string) 2134 _type_bitmaps = property(lambda self: self.type_bitmaps.string) 2135 2136 def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', nxt_hash_owner='', type_bitmaps=None, ttl=None): 2137 self.hash_algo = hash_algo 2138 self.flags = flags 2139 self.iterations = iterations 2140 self.salt = Charstr(salt) 2141 self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 2142 self.type_bitmaps = TypeBitmaps(type_bitmaps) 2143 self.ttl = str2time(ttl) 2144 2145 def encode(self, strio, compDict = None): 2146 strio.write(struct.pack(self.fmt, 2147 self.hash_algo, 2148 self.flags, 2149 self.iterations)) 2150 self.salt.encode(strio, None) 2151 self.nxt_hash_owner_name.encode(strio, None) 2152 self.type_bitmaps.encode(strio, None) 2153 2154 def decode(self, strio, length=None): 2155 start = strio.tell() 2156 l = struct.calcsize(self.fmt) 2157 buff = readPrecisely(strio, l) 2158 r = struct.unpack(self.fmt, buff) 2159 self.hash_algo, self.flags, self.iterations = r 2160 self.salt.decode(strio) 2161 self.nxt_hash_owner_name.decode(strio) 2162 here = strio.tell() 2163 self.type_bitmaps.decode(strio, length + start - here if length else None) 2164 2165 def __hash__(self): 2166 return hash((self.hash_algo, self.flags, self.iterations, self.salt, 2167 self.nxt_hash_owner_name, self.type_bitmaps)) 2168 1471 2169 # This is a fallback record 1472 2170 class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 1473 2171 """ … … 1544 2242 queries = answers = add = ns = None 1545 2243 1546 2244 def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 1547 auth=0, rCode=OK, trunc=0, maxSize=512):2245 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 1548 2246 self.maxSize = maxSize 1549 2247 self.id = id 1550 2248 self.answer = answer 1551 2249 self.opCode = opCode 1552 self.auth = auth 1553 self.trunc = trunc 1554 self.recDes = recDes 1555 self.recAv = recAv 2250 self.auth = auth #AA - Authoritative Answer 2251 self.trunc = trunc #TC - TrunCated 2252 self.recDes = recDes #RD - Recursion Desired 2253 self.recAv = recAv #RA - Recursion Available 2254 self.authData = authData #AD - Authentic Data 2255 self.chkDis = chkDis #CD - Checking Disabled 1556 2256 self.rCode = rCode 1557 2257 self.queries = [] 1558 2258 self.answers = [] … … 1597 2297 | ((self.auth & 1 ) << 2 ) 1598 2298 | ((self.trunc & 1 ) << 1 ) 1599 2299 | ( self.recDes & 1 ) ) 1600 byte4 = ( ( (self.recAv & 1 ) << 7 ) 2300 byte4 = ( ((self.recAv & 1 ) << 7 ) 2301 |((self.authData & 1 ) << 5 ) 2302 |((self.chkDis & 1 ) << 4 ) 1601 2303 | (self.rCode & 0xf ) ) 1602 2304 1603 2305 strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, … … 1617 2319 self.trunc = ( byte3 >> 1 ) & 1 1618 2320 self.recDes = byte3 & 1 1619 2321 self.recAv = ( byte4 >> 7 ) & 1 2322 self.authData = ( byte4 >> 5 ) & 1 2323 self.chkDis = ( byte4 >> 4 ) & 1 1620 2324 self.rCode = byte4 & 0xf 1621 2325 1622 2326 self.queries = [] … … 1635 2339 1636 2340 def parseRecords(self, list, num, strio): 1637 2341 for i in range(num): 1638 header = RRHeader()1639 2342 try: 1640 header .decode(strio)2343 header = OPTHeader.factory(strio) 1641 2344 except EOFError: 1642 2345 return 1643 2346 t = self.lookupRecordType(header.type) … … 1747 2450 query, or errbacked with any errors that could happen (exceptions 1748 2451 during writing of the query, timeout errors, ...). 1749 2452 """ 1750 m = Message(id, recDes= 1)2453 m = Message(id, recDes=self.controller.dnssecConfig.recDes) 1751 2454 m.queries = queries 2455 if self.controller.dnssecConfig.ednsEnabled: 2456 authData=self.controller.dnssecConfig.authData 2457 chkDis=self.controller.dnssecConfig.chkDis 2458 m.additional = [Record_OPT(payload_size = self.controller.dnssecConfig.maxUdpPktSz, 2459 version = self.controller.dnssecConfig.version, 2460 dnssecOk = self.controller.dnssecConfig.dnssecOk)] 1752 2461 1753 2462 try: 1754 2463 writeMessage(m) … … 1802 2511 self.transport.write(message.toStr(), address) 1803 2512 1804 2513 def startListening(self): 1805 self._reactor.listenUDP(0, self, maxPacketSize=512) 2514 maxPacketSize = 512 2515 if self.controller.dnssecConfig.ednsEnabled: 2516 maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 2517 self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 1806 2518 1807 2519 def datagramReceived(self, data, addr): 1808 2520 """ -
names/serialNumberArithmetic.py
1 #!/usr/bin/env python 2 # 3 # RFC 1982 DNS Serial Number Arithmetic 4 # RFC 4034 DNSSEC Signature Expiration and Inception Fields 5 # 6 # bob.novas@shinkuro.com 7 # 8 9 class SNA(object): 10 """ 11 implements RFC 1982 - DNS Serial Number Arithmetic 12 """ 13 SERIAL_BITS = 32 14 MODULOVAL = 2**SERIAL_BITS 15 HLFRNG = 2**(SERIAL_BITS-1) 16 MAXADD = (2**(SERIAL_BITS-1)-1) 17 18 def __init__(self, number): 19 self._number = int(number)%self.MODULOVAL 20 21 def __repr__(self): 22 return str(self._number) 23 24 def EQ(self, sna2): 25 assert isinstance(sna2, SNA) 26 return sna2._number == self._number 27 28 def LT(self, sna2): 29 assert isinstance(sna2, SNA) 30 return not self.EQ(sna2) and \ 31 ((self._number < sna2._number) and ((sna2._number - self._number) < self.HLFRNG) or \ 32 (self._number > sna2._number) and ((self._number - sna2._number) > self.HLFRNG)) 33 34 def GT(self, sna2): 35 assert isinstance(sna2, SNA) 36 return not self.EQ(sna2) and \ 37 ((self._number < sna2._number) and ((sna2._number - self._number) > self.HLFRNG) or \ 38 (self._number > sna2._number) and ((self._number - sna2._number) < self.HLFRNG)) 39 40 def LE(self, sna2): 41 return self.EQ(sna2) or self.LT(sna2) 42 43 def GE(self, sna2): 44 return self.EQ(sna2) or self.GT(sna2) 45 46 def Add(self, sna2): 47 assert isinstance(sna2, SNA) 48 if sna2.LE(SNA(self.MAXADD)): 49 return SNA( (self._number + sna2._number)%self.MODULOVAL ) 50 else: 51 raise ArithmeticError 52 53 def __hash__(self): 54 return hash(self._number) 55 56 __eq__ = EQ 57 __lt__ = LT 58 __gt__ = GT 59 __le__ = LE 60 __ge__ = GE 61 __add__ = Add 62 63 @staticmethod 64 def Max(snaList): 65 """ 66 this takes a list of sna's from which it will pick the sn with the highest value 67 """ 68 if len(snaList) == 0: 69 return None 70 trialMax = snaList[0] 71 for s in snaList[1:]: 72 if not trialMax: 73 trialMax = s 74 elif s and s.GT(trialMax): 75 trialMax = s 76 return trialMax 77 78 import calendar, time 79 class DateSNA(SNA): 80 """ 81 implements DNS Serial Number Arithmetic 82 for dates 'YYYYMMDDHHMMSS' per RFC 4034 P3.1.5 83 """ 84 fmt = '%Y%m%d%H%M%S' 85 86 def __init__(self, utcDateTime=''): 87 ''' 88 accept a UTC date/time string as YYMMDDHHMMSS 89 and convert it to seconds since the epoch 90 ''' 91 if not utcDateTime: 92 utcDateTime = '19700101000000' 93 dtstruct = time.strptime(utcDateTime, DateSNA.fmt) 94 assert dtstruct.tm_year < 1970+136 95 secondsSinceE = calendar.timegm(dtstruct) 96 super(DateSNA, self).__init__(secondsSinceE) 97 98 def Add(self, sna2): 99 if not isinstance(sna2, SNA): 100 return NotImplemented 101 102 if sna2.LE(SNA(self.MAXADD)) and (self._number + sna2._number < self.MODULOVAL): 103 sna = SNA((self._number + sna2._number)%self.MODULOVAL) 104 return DateSNA.fromSNA(sna) 105 else: 106 raise ArithmeticError 107 108 def asDate(self): 109 dtstruct = time.gmtime(self._number) 110 return time.strftime(DateSNA.fmt, dtstruct) 111 112 def asInt(self): 113 return self._number 114 115 @staticmethod 116 def fromSNA(sna): 117 assert isinstance(sna, SNA) 118 d = DateSNA() 119 d._number = sna._number 120 return d 121 122 @staticmethod 123 def fromInt(i): 124 return DateSNA.fromSNA(SNA(i)) 125 126 def __str__(self): 127 return self.asDate() 128 129 130 if __name__ == "__main__": 131 132 s1 = SNA(1) 133 s1a = SNA(1) 134 s2 = SNA(2) 135 136 assert s1 == s1a 137 assert hash(s1) == hash(s1a) 138 assert s1 <= s1a 139 assert s1 >= s1a 140 assert s1 < s2 141 assert not s1 > s2 142 assert s1 <= s2 143 assert not s1 >= s2 144 145 smaxval = SNA(SNA.HLFRNG+SNA.HLFRNG-1) 146 smaxplus1 = smaxval.Add(s1) 147 smaxadd = SNA(SNA.MAXADD) 148 149 assert smaxplus1 > smaxval 150 assert s1 + smaxadd 151 assert SNA.Max([None, s1]) == s1 152 assert SNA.Max([s1, None]) == s1 153 154 date1 = DateSNA('20120101000000') 155 date2 = DateSNA('20130101000000') 156 assert date1 < date2 157 158 date3 = DateSNA('20370101000000') 159 sna1 = SNA(365*24*60*60) 160 date4 = date3 + sna1 161 assert date4._number == date3._number + sna1._number 162 163 date5 = DateSNA() 164 date6 = date5 + SNA(24*60*60) 165 assert date6._number == date5._number + 24*60*60 166 167 date7 = DateSNA('20370101000000') 168 date8 = date7 + sna1 169 assert date8._number == date7._number + sna1._number 170 171 172 No newline at end of file -
names/test/test_client.py
642 642 d.addCallback(self.checkResult, dns.NAPTR) 643 643 return d 644 644 645 def test_lookupDNSKey(self): 646 """ 647 See L{test_lookupAddress} 648 """ 649 d = client.lookupDNSKey(self.hostname) 650 d.addCallback(self.checkResult, dns.DNSKEY) 651 return d 645 652 653 646 654 class ThreadedResolverTests(unittest.TestCase): 647 655 """ 648 656 Tests for L{client.ThreadedResolver}. -
names/test/test_dns.py
8 8 9 9 from cStringIO import StringIO 10 10 11 import re 11 12 import struct 12 13 13 14 from twisted.python.failure import Failure 14 15 from twisted.internet import address, task 15 16 from twisted.internet.error import CannotListenError, ConnectionDone 16 17 from twisted.trial import unittest 17 from twisted.names import dns 18 from twisted.names import dns, common 18 19 19 20 from twisted.test import proto_helpers 20 21 … … 25 26 dns.Record_WKS, dns.Record_SRV, dns.Record_AFSDB, dns.Record_RP, 26 27 dns.Record_HINFO, dns.Record_MINFO, dns.Record_MX, dns.Record_TXT, 27 28 dns.Record_AAAA, dns.Record_A6, dns.Record_NAPTR, dns.UnknownRecord, 29 dns.Record_OPT, dns.Record_RRSIG, dns.Record_DS, dns.Record_DNSKey, 30 dns.Record_NSEC, dns.Record_NSEC3, 28 31 ] 29 32 30 33 class NameTests(unittest.TestCase): … … 189 192 """Encoding and then decoding various objects.""" 190 193 191 194 names = ["example.org", "go-away.fish.tv", "23strikesback.net"] 192 195 sigs = ["Qm12VZVaZgKS0/DZx35SGECDwPiTTf3ngChb7OkgSv5iupVmJGhPWudm /18qBSXKyv9hxMlEXFFgpBieNqLfSBkP1bwKnlqPfr1Hx7ctDwDUpkT3 cS8u/ms9yo3Fu1ybpO4Hfsb1HbA2N3zzQnjWKnyk26AAQSz8KgjNTFzD tJM=", 196 "ZH2kahMD1g2WOieIotAcBwB0e/o30Zq6YR//M/xwP1ktkYuclmcR56iv XiR3QFWqmN5Xz3YpgmM4tZkjIeSMp2doYa7XYORZ7OpzG7oyfo8IoXxc j1VGDeAn1CeNCpBtoSGapRABG1gjY7oeRj/smPQPp2Gkf79+WZfuzRom /t4=", 197 "AZpaboyNQAmbnBO1K66QmZ0c+VCdY/wu9QpEdRnMpnIOLPD28pNVu6hk GQMz6eg5WYkPYDdJK+1D/oyAQkDmRgn10+O9EdeFDyLqYqq/htEAvDm4 CziMSOpD/mkg1bSWCZ2mdln/GBk8WooCeeM7LEHmRjmHMMj0xb6N4SKa MEc=", 198 "AwEAAbi5VQa3x+R3WQouBDNts+ZX2zIKZNoj9pzl7ew446kI/2omv3j6 c/4RQ6VneYE3mK7r0fFIKhVagmiRroFO1rRUJ8sVidssZ35CldE0sju+ E7wymVg3tV+ZUUO/+5v6Sfj+tw3rlp6eKqm7EGKKM88t+KuXiGYMu0Vw Rm9OUO1n", 199 "AwEAAbmTL+kuV45kAxGN//iBKz93Y6lutgxoptp+I1+PZZMsBkhm/dZj q57040Pz/Hr3f2zQX7z6fFu7/Ml3MHPH1eQDiVXDvOkeNq2x4IbCO7x+ 0p6bGYj4fw/tEfh/8dUzyzvMwfuAMsOvXza8Kh+UP4jvFc95cUuGgYus uEjUOp40PsL7EtYvAks3UssA6/OZP4w/1Z5m/VFx4PzgY0dkEuc=", 200 "VGPxa8A81eV1dtUxVhz9b9Jsp6FF4M5H6J0QhzbNCUTHTHjLNR2VHYfE fM+Akwo3/qKq3D6vzTfzqtyPAXP8CmGfdD8hfv0s7Hae9c7Is8usdlrk ZpoXEFMW+YVG8G9OieYViq6tBIpUvKgMVZ+oXKo63KJ/tC/yBW0H0VQP YwdzZ3ZvYRDmZDvrXoX7T0YNU+0HYHnb7g7nUECIJ/4HHg==", 201 "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFE h9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffp Z9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55 Y1k="] 202 type_bitmaps = ["A MX RRSIG NSEC TYPE1234", 203 "AAAA NS CNAME MX TXT RRSIG NSEC3 DNAME", 204 "NSEC3 A AAAA RRSIG DS NS TYPE5000 TYPE1000 TYPE2000 TYPE3000 TYPE4000", 205 None] 206 193 207 def testName(self): 194 208 for n in self.names: 195 209 # encode the name … … 276 290 self.assertEqual(result.string, n) 277 291 278 292 293 def test_Sigstr(self): 294 """ 295 Test L{dns.Sigstr} encode and decode. 296 """ 297 for s in self.sigs: 298 # encode the signature/key 299 f = StringIO() 300 dns.Sigstr(s).encode(f) 301 l = f.tell() 302 303 # decode the signature/key 304 f.seek(0, 0) 305 result = dns.Sigstr() 306 result.decode(f,l) 307 #spaces are free, and dig sticks them in 308 self.assertEqual(result.string, s.replace(' ', '')) 309 310 311 def test_TypeBitmaps(self): 312 """ 313 Test L{dns.TypeBitmaps} encode and decode. 314 """ 315 typeRegex = re.compile('TYPE(\d+)') 316 317 for b in self.type_bitmaps: 318 # encode the type_bitmaps 319 f = StringIO() 320 dns.TypeBitmaps(b).encode(f) 321 l = f.tell() 322 323 # decode the type_bitmaps 324 f.seek(0, 0) 325 result = dns.TypeBitmaps() 326 result.decode(f,l) 327 328 def mnuVal(mnu): 329 mnuVal = dns.REV_TYPES.get(mnu, None) 330 if not mnuVal: 331 m = typeRegex.match(mnu) 332 if m.groups(): 333 mnuVal = int(m.group(1)) 334 assert mnuVal < 65536 335 else: 336 log.err("can't parse %s in %s" % (mnu, self.string, )) 337 mnuVal = 0 338 return mnuVal 339 340 def sorttok(string): 341 if not string: 342 return '' 343 344 toks = string.split(' ') 345 toks.sort(key = mnuVal) 346 return ' '.join(toks) 347 348 self.assertEqual(result.type_bitmaps, sorttok(b)) 349 350 279 351 def test_NAPTR(self): 280 352 """ 281 353 Test L{dns.Record_NAPTR} encode and decode. … … 386 458 Initialize the controller: create a list of messages. 387 459 """ 388 460 self.messages = [] 461 self.dnssecConfig = common.DnssecConfig() 389 462 390 463 391 464 def messageReceived(self, msg, proto, addr): … … 840 913 repr(dns.UnknownRecord("foo\x1fbar", 12)), 841 914 "<UNKNOWN data='foo\\x1fbar' ttl=12>") 842 915 916 def test_dnskey(self): 917 """ 918 The repr of a L{dns.DNSKEY} instance includes the flags, protocol, 919 algo, pub_key and ttl fields of the record. 920 """ 921 self.assertEqual( 922 repr(dns.Record_DNSKey(10, 20, 30, "foo\x1fbar", ttl=20)), 923 "<DNSKEY flags=10 protocol=20 algo=30 pub_key=foo\x1fbar ttl=20>") 924 925 def test_ds(self): 926 """ 927 The repr of a L{dns.DS} instance includes the key_tag, algo, digest_type, 928 digest and ttl fields of the record. 929 """ 930 self.assertEqual( 931 repr(dns.Record_DS(11, 22, 33, "foo\x1fbar1", ttl=21)), 932 "<DS key_tag=11 algo=22 digest_type=33 digest=foo\x1fbar1 ttl=21>") 933 934 def test_nsec(self): 935 """ 936 The repr of a L{dns.NSEC} instance includes the nxt_name, type_bitmaps and 937 ttl fields of the record. 938 """ 939 self.assertEqual( 940 repr(dns.Record_NSEC('bob', "\x1fabcd", ttl=31)), 941 "<NSEC nxt_name=bob type_bitmaps=\x1fabcd ttl=31>") 942 943 def test_nsec3(self): 944 """ 945 The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, iterations, 946 salt, nxt_hash_owner_name, type_bitmaps and ttl fields of the record. 947 """ 948 self.assertEqual( 949 repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', "\x1fabcd", ttl=31)), 950 "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 nxt_hash_owner_name=bob type_bitmaps=\x1fabcd ttl=31>") 951 952 def test_opt(self): 953 """ 954 The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk flag, 955 and version fields of the record. (The OPT record has no ttl field.) 956 """ 957 self.assertEqual( 958 repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 959 "<OPT payload_size=1492 flags=0x8000 version=0>") 843 960 961 def test_rrsig(self): 962 """ 963 The repr of a L{dns.RRSIG} instance includes the algo, labels, original_ttl 964 sig_expiration, sig_inception, key_tag, signers_name, signature and ttl 965 fields of the record. 966 """ 967 self.assertEqual( 968 repr(dns.Record_RRSIG(type_covered=dns.A, 969 algo=2, 970 labels=3, 971 original_ttl=30, 972 sig_expiration='20110101123456', 973 sig_inception= '20110202112233', 974 key_tag=60, 975 signers_name='bob', 976 signature='\x12\x34sig', 977 ttl=70)), 978 "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 979 + " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 980 + " signers_name=bob signature=\x12\x34sig ttl=70>") 844 981 845 982 class _Equal(object): 846 983 """ … … 908 1045 cls('example.com', 123), 909 1046 cls('example.org', 123)) 910 1047 1048 def test_optheader(self): 1049 """ 1050 Two OptHeader instances comapare equal iff the have the same 1051 (Record_OPT) payload and auth bit. 1052 """ 1053 self._equalityTest( 1054 dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 1055 dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 1056 dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492, dnssecOk=False, version=0, ttl=40), auth=True)) 911 1057 912 1058 def test_rrheader(self): 913 1059 """ … … 1430 1576 dns.UnknownRecord('foo', ttl=10), 1431 1577 dns.UnknownRecord('foo', ttl=10), 1432 1578 dns.UnknownRecord('foo', ttl=100)) 1579 1580 def test_rrsig(self): 1581 """ 1582 L(dns.RRSIG) instances compare equal iff they have the same 1583 type_covered, algo, labels, original_ttl, sig_expiration, sig_inception, 1584 key_tag, signers_name, signature, and ttl 1585 """ 1586 self._equalityTest( 1587 dns.Record_RRSIG(type_covered=dns.A), 1588 dns.Record_RRSIG(type_covered=dns.A), 1589 dns.Record_RRSIG(type_covered=dns.AAAA)) 1590 self._equalityTest( 1591 dns.Record_RRSIG(algo=1), 1592 dns.Record_RRSIG(algo=1), 1593 dns.Record_RRSIG(algo=2)) 1594 self._equalityTest( 1595 dns.Record_RRSIG(labels=3), 1596 dns.Record_RRSIG(labels=3), 1597 dns.Record_RRSIG(labels=4)) 1598 self._equalityTest( 1599 dns.Record_RRSIG(original_ttl=5), 1600 dns.Record_RRSIG(original_ttl=5), 1601 dns.Record_RRSIG(original_ttl=6)) 1602 self._equalityTest( 1603 dns.Record_RRSIG(sig_expiration='20110101000000'), 1604 dns.Record_RRSIG(sig_expiration='20110101000000'), 1605 dns.Record_RRSIG(sig_expiration='20110101000001')) 1606 self._equalityTest( 1607 dns.Record_RRSIG(sig_inception='20120101000000'), 1608 dns.Record_RRSIG(sig_inception='20120101000000'), 1609 dns.Record_RRSIG(sig_inception='20120101000001')) 1610 self._equalityTest( 1611 dns.Record_RRSIG(key_tag=11), 1612 dns.Record_RRSIG(key_tag=11), 1613 dns.Record_RRSIG(key_tag=12)) 1614 self._equalityTest( 1615 dns.Record_RRSIG(signers_name='bob'), 1616 dns.Record_RRSIG(signers_name='bob'), 1617 dns.Record_RRSIG(signers_name='joe')) 1618 self._equalityTest( 1619 dns.Record_RRSIG(signature='abcdef'), 1620 dns.Record_RRSIG(signature='abcdef'), 1621 dns.Record_RRSIG(signature='abcdefg')) 1622 self._equalityTest( 1623 dns.Record_RRSIG(ttl=10), 1624 dns.Record_RRSIG(ttl=10), 1625 dns.Record_RRSIG(ttl=20)) 1626 1627 def test_ds(self): 1628 """ 1629 L(dns.DS) instances compare equal iff they have the same 1630 key_tag, algo, digest_type, digest and ttl 1631 """ 1632 self._equalityTest( 1633 dns.Record_DS(key_tag=1), 1634 dns.Record_DS(key_tag=1), 1635 dns.Record_DS(key_tag=2)) 1636 self._equalityTest( 1637 dns.Record_DS(algo=3), 1638 dns.Record_DS(algo=3), 1639 dns.Record_DS(algo=4)) 1640 self._equalityTest( 1641 dns.Record_DS(digest_type=5), 1642 dns.Record_DS(digest_type=5), 1643 dns.Record_DS(digest_type=6)) 1644 self._equalityTest( 1645 dns.Record_DS(digest='abcdef-digest'), 1646 dns.Record_DS(digest='abcdef-digest'), 1647 dns.Record_DS(digest='abcdef-digest-f')) 1648 self._equalityTest( 1649 dns.Record_DS(ttl=10), 1650 dns.Record_DS(ttl=10), 1651 dns.Record_DS(ttl=20)) 1652 1653 def test_dnskey(self): 1654 """ 1655 L(dns.DNSKEY) instances compare equal iff they have the same 1656 flags, protocol, algo, pub_key and ttl 1657 """ 1658 self._equalityTest( 1659 dns.Record_DNSKey(flags=1), 1660 dns.Record_DNSKey(flags=1), 1661 dns.Record_DNSKey(flags=2)) 1662 self._equalityTest( 1663 dns.Record_DNSKey(protocol=3), 1664 dns.Record_DNSKey(protocol=3), 1665 dns.Record_DNSKey(protocol=4)) 1666 self._equalityTest( 1667 dns.Record_DNSKey(algo=5), 1668 dns.Record_DNSKey(algo=5), 1669 dns.Record_DNSKey(algo=6)) 1670 self._equalityTest( 1671 dns.Record_DNSKey(pub_key='abcdef-digest'), 1672 dns.Record_DNSKey(pub_key='abcdef-digest'), 1673 dns.Record_DNSKey(pub_key='abcdef-digest-f')) 1674 self._equalityTest( 1675 dns.Record_DNSKey(ttl=10), 1676 dns.Record_DNSKey(ttl=10), 1677 dns.Record_DNSKey(ttl=20)) 1678 1679 def test_nsec(self): 1680 """ 1681 L(dns.DNSKEY) instances compare equal iff they have the same 1682 nxt_name, type_bitmaps and ttl 1683 """ 1684 self._equalityTest( 1685 dns.Record_NSEC(nxt_name="example.com"), 1686 dns.Record_NSEC(nxt_name="example.com"), 1687 dns.Record_NSEC(nxt_name="a.example.com")) 1688 self._equalityTest( 1689 dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 1690 dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 1691 dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 1692 self._equalityTest( 1693 dns.Record_NSEC(ttl=5), 1694 dns.Record_NSEC(ttl=5), 1695 dns.Record_NSEC(ttl=6)) 1696 1697 def test_nsec3(self): 1698 """ 1699 L(dns.DNSKEY) instances compare equal iff they have the same 1700 hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 1701 """ 1702 self._equalityTest( 1703 dns.Record_NSEC3(hash_algo=1), 1704 dns.Record_NSEC3(hash_algo=1), 1705 dns.Record_NSEC3(hash_algo=2)) 1706 self._equalityTest( 1707 dns.Record_NSEC3(flags=1), 1708 dns.Record_NSEC3(flags=1), 1709 dns.Record_NSEC3(flags=2)) 1710 self._equalityTest( 1711 dns.Record_NSEC3(iterations=5), 1712 dns.Record_NSEC3(iterations=5), 1713 dns.Record_NSEC3(iterations=6)) 1714 self._equalityTest( 1715 dns.Record_NSEC3(salt="abcdef"), 1716 dns.Record_NSEC3(salt="abcdef"), 1717 dns.Record_NSEC3(salt="abcdefg")) 1718 self._equalityTest( 1719 dns.Record_NSEC3(nxt_hash_owner="example.com"), 1720 dns.Record_NSEC3(nxt_hash_owner="example.com"), 1721 dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 1722 self._equalityTest( 1723 dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 1724 dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 1725 dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 1726 self._equalityTest( 1727 dns.Record_NSEC3(ttl=5), 1728 dns.Record_NSEC3(ttl=5), 1729 dns.Record_NSEC3(ttl=6)) 1730 1731 1732 1733 No newline at end of file -
names/test/test_names.py
93 93 '\x12\x01\x16\xfe\xc1\x00\x01'), 94 94 dns.Record_NAPTR(100, 10, "u", "sip+E2U", 95 95 "!^.*$!sip:information@domain.tld!"), 96 dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF')], 96 dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF'), 97 dns.Record_DNSKey(0x10, 3, 5, 98 "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=" 99 )], 97 100 'http.tcp.test-domain.com': [ 98 101 dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') 99 102 ], 100 103 'host.test-domain.com': [ 101 104 dns.Record_A('123.242.1.5'), 102 105 dns.Record_A('0.255.0.255'), 106 dns.Record_RRSIG(dns.A, 5, 3, 86400, '20120101000000', '20120201000000', 2642, 'test-domain.com', 107 "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=") 103 108 ], 104 109 'host-two.test-domain.com': [ 105 110 # … … 429 434 [dns.Record_NAPTR(100, 10, "u", "sip+E2U", 430 435 "!^.*$!sip:information@domain.tld!", 431 436 ttl=19283784)]) 437 438 def test_DNSKEY(self): 439 """Test DNS 'DNSKEY' record queries.""" 440 return self.namesTest( 441 self.resolver.lookupDNSKey('test-domain.com'), 442 [dns.Record_DNSKey(0x10, 3, 5, 443 "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=", 444 ttl=19283784)]) 432 445 433 434 435 446 class DNSServerFactoryTests(unittest.TestCase): 436 447 """ 437 448 Tests for L{server.DNSServerFactory}.