Ticket #5454: addEdsn0AndDnssec5454V02.patch
| File addEdsn0AndDnssec5454V02.patch, 95.3 KB (added by BobNovas, 15 months ago) |
|---|
-
doc/names/examples/dnssecTest.py
1 import sys 2 from twisted.names.common import DnssecConfig 3 from twisted.names.client import Resolver 4 from twisted.names import client 5 from twisted.internet import reactor 6 7 def deferredAnswer(result): 8 #expect - a 4-tuple with a couple of DS RR's and an RRSIG RR in the answer. 9 print " Answer: %s\n Authority: %s\n Additional: %s\n Message: %s" % result 10 11 #expect - the AD bit to be set 12 message = result[3] 13 authData = not not message.authData 14 print "expect authData to be True: %s" % authData 15 16 reactor.stop() 17 18 def errAnswer(error): 19 print "Error: %s" % error 20 reactor.stop() 21 22 def main(): 23 24 reactor.callWhenRunning(doLookup) 25 reactor.run() 26 27 def doLookup(): 28 29 #DnssecConfig - set ednsEnabled True if dnssecOk is True or you won't get 30 # a DNSSEC result - since DO is in the EDNS OPT record. 31 #For efficiency, set maxUdpPktSz large enough to get a DNSSEC message without 32 # falling back to TCP but not so large that a network with small MTU fragments packets. 33 # 1492 is generally absolutely safe. 4096 usually works. It depends on the network. 34 dsc = DnssecConfig(ednsEnabled=True, maxUdpPktSz=4096, dnssecOk=True, chkDis=False) 35 36 #setup a DNSSEC resolver using a public validating resolver 37 # and set it as the client's theResolver 38 resolver = Resolver(servers=[('149.20.64.20', 53)], dnssecConfig=dsc) 39 client.theResolver = resolver 40 41 #query for DS records for comcast.net 42 client.lookupDS('comcast.net')\ 43 .addCallback(deferredAnswer)\ 44 .addErrback(errAnswer) 45 46 if __name__ == '__main__': 47 main() 48 No newline at end of file -
doc/names/examples/index.xhtml
15 15 <li><a href="testdns.py">testdns.py</a></li> 16 16 <li><a href="dns-service.py">dns-service.py</a></li> 17 17 <li><a href="gethostbyname.py">gethostbyname.py</a></li> 18 <li><a href="dnssecTest.py">dnssecTest.py</a></li> 18 19 </ul> 19 20 </body> 20 21 </html> -
doc/names/howto/names.xhtml
49 49 directives are not yet supported. 50 50 </p> 51 51 52 <h2>Using DNS Security Extensions (DNSSEC)</h2> 53 54 <p>DNSSEC adds data origin authentication and data integrity to the Domain Name System (see RFC4033.) To use DNSSEC requires EDNS0, because to enable DNSSEC requires setting the DNSSEC OK (DO) bit which is in the EDNS0 OPT Record. RFC4035 discusses how a non-validating security aware resolver (which is what twisted.names is with the DNSSEC change) should handle the DO, CD and AD bits. 55 </p> 56 57 <p><a href="../../../doc/names/examples/dnssecTest.py" class="py-listings">dnssecTest.py</a> is an example of using DNSSEC to check the AD bit of a domain that should validate. 58 </p> 59 52 60 </body></html> -
NEWS
1 1 Ticket numbers in this file can be looked up by visiting 2 2 http://twistedmatrix.com/trac/ticket/<number> 3 3 4 5 Twisted Names 12.1.0 (2012-03-13) 6 ================================= 7 8 Features 9 -------- 10 - The main features introduced by this change are EDNS0 and support 11 for DNSSEC. Enabling EDNS0 adds to a query an OPT record that carries 12 two pieces of information. The first is the maximum size UDP packet 13 that the network can handle (see RFC2671.) The second is the DNSSEC 14 OK (DO) bit which tells an upstream resolver that the querying resolver 15 is able to accept DNSSEC security data (See RFC3225.) Although this 16 change fully implements EDNS0, it only enables twisted.names to 17 ask for DNSSEC data and pass that data to the user. The user may 18 check the Authentic Data (AD) bit in the message header to determine 19 if the upstream resolver validates the data. (See RFC 4035, Section 20 4.9.3 regarding only using the AD bit from a trusted resolver 21 on a secure channel.) 22 - Processing DNSSEC data and validating DNS answers requires doing 23 cryptographic processing using a library such as openssl. This may 24 be part of a future feature set but is not in the current feature. 25 - The new class twisted.names.common.DnssecConfig allows configuring 26 DNSSEC and EDNS0 parameters, as well as the recursion desired DNS 27 parameter, for a resolver. DnssecConfig is an optional input argument 28 to ResolverBase and is implemented for client.Resolver and 29 secondaryAuthority.Resolver 30 - ResolverBase has new lookup methods for lookupDNSKey, lookupDS, 31 lookupNSEC, lookupNSEC3, lookupNSEC3Param and lookupRRSIG records. 32 - twisted.names.client.Resolver returns a 4-tuple to a query when 33 configured with dnssecOk. The 4-tuple includes a new reference 34 to the message so that the caller can obtain the AD flag (and 35 any of the other flags) in the message. 36 - twisted.names.client has new lookup methods for the six new 37 DNSSEC record types. 38 - twisted.names.dns supports six new DNS record types - DNSKey, 39 DS, NSEC, NSEC3, NSEC3Param and RRSIG. 40 - Class twisted.names.dns.Sigstr encodes/decodes signatures and keys. 41 - Class twisted.names.dns.TypeBitmaps encodes/decoes the type bitmap 42 field in an NSEC3 resource record. 43 - Class OptHeader and class Record_OPT supports the EDNS and DNSSEC 44 options. 45 - twisted.names.dns has new classes added for the six DNSSEC record types. 46 - AD and CD flags are added to the dns.Message class. 47 - twisted.names.dns adds the OPT record to EDNS queries. 48 - twisted.names.dns.Message.startListening listens for larger UDP 49 packets, as set by maxUdpPktSz. 50 - Class twisted.names.ser_num_arith implements DNS Serial Number 51 Arithmetic (SNA) and Date SNA for handling numbers and dates that 52 roll through a 32-bit integer. 53 - new tests are added for all new features. 54 55 4 56 Twisted Core 12.0.0 (2012-02-10) 5 57 ================================ 6 58 -
twisted/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: An L{DnssecConfig} - 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 … … 381 388 return self.queryTCP(message.queries).addCallback(self.filterAnswers) 382 389 if message.rCode != dns.OK: 383 390 return failure.Failure(self.exceptionForCode(message.rCode)(message)) 384 return (message.answers, message.authority, message.additional) 391 392 #if dnssecOk is enabled, return a reference to the message as the 393 #4th member of the tuple, so the caller can access the message header 394 #flags. There are more flags than just AD (authentic Data) that are 395 #set in a response that may be of interest (e.g., Truncate-TC). 396 if self.dnssecConfig.dnssecOk: 397 return (message.answers, message.authority, message.additional, message) 398 else: 399 #dnssecOk was not requested - return a legacy 3-tuple 400 return (message.answers, message.authority, message.additional) 385 401 386 402 387 403 def _lookup(self, name, cls, type, timeout): … … 953 969 @rtype: C{Deferred} 954 970 """ 955 971 return getResolver().lookupNamingAuthorityPointer(name, timeout) 972 973 974 def lookupDNSKey(name, timeout=None): 975 """ 976 DNSKEY lookup. 977 978 @type name: C{str} 979 @param name: DNS name to resolve. 980 981 @type timeout: Sequence of C{int} 982 @param timeout: Number of seconds after which to reissue the query. 983 When the last timeout expires, the query is considered failed. 984 985 @rtype: C{Deferred} 986 """ 987 return getResolver().lookupDNSKey(name, timeout) 988 989 990 def lookupDS(name, timeout=None): 991 """ 992 DS lookup. 993 994 @type name: C{str} 995 @param name: DNS name to resolve. 996 997 @type timeout: Sequence of C{int} 998 @param timeout: Number of seconds after which to reissue the query. 999 When the last timeout expires, the query is considered failed. 1000 1001 @rtype: C{Deferred} 1002 """ 1003 return getResolver().lookupDS(name, timeout) 1004 1005 1006 def lookupNSEC(name, timeout=None): 1007 """ 1008 NSEC lookup. 1009 1010 @type name: C{str} 1011 @param name: DNS name to resolve. 1012 1013 @type timeout: Sequence of C{int} 1014 @param timeout: Number of seconds after which to reissue the query. 1015 When the last timeout expires, the query is considered failed. 1016 1017 @rtype: C{Deferred} 1018 """ 1019 return getResolver().lookupNSEC(name, timeout) 1020 1021 1022 def lookupNSEC3(name, timeout=None): 1023 """ 1024 NSEC3 lookup. 1025 1026 @type name: C{str} 1027 @param name: DNS name to resolve. 1028 1029 @type timeout: Sequence of C{int} 1030 @param timeout: Number of seconds after which to reissue the query. 1031 When the last timeout expires, the query is considered failed. 1032 1033 @rtype: C{Deferred} 1034 """ 1035 return getResolver().lookupNSEC3(name, timeout) 1036 1037 1038 def lookupNSEC3Param(name, timeout=None): 1039 """ 1040 NSEC3 Param lookup. 1041 1042 @type name: C{str} 1043 @param name: DNS name to resolve. 1044 1045 @type timeout: Sequence of C{int} 1046 @param timeout: Number of seconds after which to reissue the query. 1047 When the last timeout expires, the query is considered failed. 1048 1049 @rtype: C{Deferred} 1050 """ 1051 return getResolver().lookupNSEC3Param(name, timeout) 1052 1053 1054 def lookupRRSIG(name, timeout=None): 1055 """ 1056 RRSIG lookup. 1057 1058 @type name: C{str} 1059 @param name: DNS name to resolve. 1060 1061 @type timeout: Sequence of C{int} 1062 @param timeout: Number of seconds after which to reissue the query. 1063 When the last timeout expires, the query is considered failed. 1064 1065 @rtype: C{Deferred} 1066 """ 1067 return getResolver().lookupRRSIG(name, timeout) -
twisted/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 26 require ednsEnabled, but still nice to be able to control 27 whether or not you're asking for recursion. 28 (bool) 29 30 ednsEnabled - EDNS Enabled adds an OPT record to the query. The OPT record 31 contains a version field that indicates the version of EDNS 32 that you can handle. 33 (bool) 34 35 maxUdpPktSz - The max size UDP packet (bytes) that your end-to-end network 36 can handle (on a modern network a reliable size is 1492, 37 although up to 65535 is possible). Requires ednsEnabled. 38 (int) 39 40 dnssecOK (DO) - Dnssec Ok. A bit that indicates you want DNSSEC RR's and 41 validation if the resolver validates. If DO is set, AD 42 will be set in the response if the answer validates. 43 Requires ednsEnabled. 44 (bool) 45 46 chkDis (CD) - Checking Disabled. If DO and CD are set, a validating 47 resolver won't do validation but will return the DNSSEC 48 RR's so that YOU can. 49 (bool) 50 51 version - sets the edns version level. Currently, only version 0 is 52 defined and supported by RFC2671. 53 (int) 54 """ 55 def __init__(self, 56 recDes=True, 57 ednsEnabled=False, 58 maxUdpPktSz=512, 59 dnssecOk=False, 60 chkDis=False, 61 version=0): 62 63 self.recDes = recDes 64 self.ednsEnabled = ednsEnabled 65 self.maxUdpPktSz = maxUdpPktSz 66 self.dnssecOk = dnssecOk 67 self.chkDis = chkDis 68 self.version = version 69 70 assert not self.ednsEnabled or 512 <= self.maxUdpPktSz <= 65535 71 assert version == 0 72 21 73 class ResolverBase: 22 74 """ 23 75 L{ResolverBase} is a base class for L{IResolver} implementations which … … 36 88 37 89 typeToMethod = None 38 90 39 def __init__(self ):91 def __init__(self, dnssecConfig=None): 40 92 self.typeToMethod = {} 41 93 for (k, v) in typeToMethod.items(): 42 94 self.typeToMethod[k] = getattr(self, v) 95 self.dnssecConfig = dnssecConfig 96 if self.dnssecConfig == None: 97 self.dnssecConfig = DnssecConfig() 43 98 44 45 99 def exceptionForCode(self, responseCode): 46 100 """ 47 101 Convert a response code (one of the possible values of … … 200 254 @see: twisted.names.client.lookupAllRecords 201 255 """ 202 256 return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) 257 203 258 259 def lookupDNSKey(self, name, timeout=None): 260 """ 261 @see: twisted.names.client.lookupDNSKey 262 """ 263 return self._lookup(name, dns.IN, dns.DNSKEY, timeout) 264 265 266 def lookupDS(self, name, timeout=None): 267 """ 268 @see: twisted.names.client.lookupDS 269 """ 270 return self._lookup(name, dns.IN, dns.DS, timeout) 271 272 273 def lookupNSEC(self, name, timeout=None): 274 """ 275 @see: twisted.names.client.lookupNSEC 276 """ 277 return self._lookup(name, dns.IN, dns.NSEC, timeout) 278 279 280 def lookupNSEC3(self, name, timeout=None): 281 """ 282 @see: twisted.names.client.lookupNSEC3 283 """ 284 return self._lookup(name, dns.IN, dns.NSEC3, timeout) 285 286 287 def lookupNSEC3Param(self, name, timeout=None): 288 """ 289 @see: twisted.names.client.lookupNSEC3Param 290 """ 291 return self._lookup(name, dns.IN, dns.NSEC3PARAM, timeout) 292 293 294 def lookupRRSIG(self, name, timeout=None): 295 """ 296 @see: twisted.names.client.lookupRRSIG 297 """ 298 return self._lookup(name, dns.IN, dns.RRSIG, timeout) 299 300 204 301 def getHostByName(self, name, timeout = None, effort = 10): 205 302 """ 206 303 @see: twisted.names.client.getHostByName … … 268 365 dns.MX: 'lookupMailExchange', 269 366 dns.TXT: 'lookupText', 270 367 dns.SPF: 'lookupSenderPolicy', 368 dns.DNSKEY:'lookupDNSKey', 369 dns.DS: 'lookupDS', 370 dns.NSEC: 'lookupNSEC', 371 dns.NSEC3: 'lookupNSEC3', 372 dns.NSEC3PARAM: 'lookupNSEC3Param', 373 dns.RRSIG: 'lookupRRSIG', 271 374 272 375 dns.RP: 'lookupResponsibility', 273 376 dns.AFSDB: 'lookupAFSDatabase', -
twisted/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', 'NSEC3PARAM', 'NULL', 'OPT', 'PTR', 21 'RP', 'RRSIG', 'SOA', 'SPF', '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 49 52 import struct, random, types, socket 50 53 51 54 import cStringIO as StringIO … … 54 57 55 58 from zope.interface import implements, Interface, Attribute 56 59 60 from base64 import b64decode, b64encode 57 61 58 62 # Twisted imports 59 63 from twisted.internet import protocol, defer … … 61 65 from twisted.python import log, failure 62 66 from twisted.python import util as tputil 63 67 from twisted.python import randbytes 68 from twisted.names.ser_num_arith import SNA, DateSNA 64 69 65 70 66 71 def randomSource(): … … 79 84 NAPTR = 35 80 85 A6 = 38 81 86 DNAME = 39 87 OPT = 41 88 DS = 43 89 RRSIG = 46 90 NSEC = 47 91 DNSKEY = 48 92 NSEC3 = 50 93 NSEC3PARAM = 51 82 94 SPF = 99 83 95 84 96 QUERY_TYPES = { … … 108 120 NAPTR: 'NAPTR', 109 121 A6: 'A6', 110 122 DNAME: 'DNAME', 111 SPF: 'SPF' 123 OPT: 'OPT', 124 DS: 'DS', 125 RRSIG: 'RRSIG', 126 NSEC: 'NSEC', 127 DNSKEY: 'DNSKEY', 128 NSEC3: 'NSEC3', 129 NSEC3PARAM: 'NSEC3PARAM', 130 SPF: 'SPF', 112 131 } 113 132 114 133 IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) … … 370 389 371 390 def __str__(self): 372 391 return self.name 392 393 class Sigstr(object): 394 ''' 395 for signatures and keys. display as b64 encoded 396 ''' 397 implements(IEncodable) 398 399 def __init__(self, string=''): 400 if not isinstance(string, str): 401 raise ValueError("%r is not a string" % (string, )) 402 self.string = string #b64encoded string 403 404 def encode(self, strio, compDict=None): 405 ''' 406 Write the byte representation (the un-b64-encoded string) 407 to the file. 408 409 @type strio: file 410 @param srio: The byte representation of this signature or key 411 will be written to this file 412 413 @type compDict: dict 414 @param compDict: not used. 415 ''' 416 strio.write(b64decode(self.string)) 417 418 def decode(self, strio, length=None): 419 ''' 420 Decode a signature or a key. 373 421 422 @type strio: file 423 @param strio: Exactly length bytes will be read from this file 424 to decode the full signature or key 425 426 @type length: int 427 @param lenth: length must always be given. A signature or key 428 is always the last thing in an RR and so you can always determine 429 its length. 430 ''' 431 self.string = '' 432 if length == None: 433 return 434 435 assert isinstance(length, int) 436 buff = readPrecisely(strio, length) 437 self.string = b64encode(buff) 438 439 def __eq__(self, other): 440 if isinstance(other, Sigstr): 441 return self.string == other.string 442 return False 443 444 def __hash__(self): 445 return hash(self.string) 446 447 def __str__(self): 448 return self.string 449 450 451 class TypeBitmaps(object): 452 ''' 453 bitmap encoding scheme used by NSEC and NSEC3 RR's 454 to indicate the RRset types that exist at the 455 NSEC/NSEC3 RR's original owner name or hashed name. 456 See RFC 4034 and RFC 5155. 457 ''' 458 fmt = 'BB' 459 typeRegex = re.compile('TYPE(\d+)') 460 461 def __init__(self, string=''): 462 self.string = string 463 464 def encode(self, strio, compDict=None): 465 """ 466 Encode the string field, which consists of a set 467 of type names, into an NSEC/NSEC3 type bitmap. 468 469 @type strio: file 470 @param strio: the byte representation of the type bitmap 471 will be written to this file. 472 473 @type compDict: dict 474 @param compDict: not used. 475 """ 476 if not self.string: 477 return; 478 479 #get a sorted list of RR Type Values 480 mnus = self.string.split(' ') 481 mnuVals = [] 482 for mnu in mnus: 483 mnuVal = REV_TYPES.get(mnu, None) 484 if not mnuVal: 485 m = self.typeRegex.match(mnu) 486 if m.groups(): 487 mnuVal = int(m.group(1)) 488 assert mnuVal < 65536 489 else: 490 log.err("can't parse %s in %s" % (mnu, self.string, )) 491 continue; 492 mnuVals.append(mnuVal) 493 mnuVals.sort() 494 495 #convert that to a dict of windows and lists 496 windDict = {} 497 for v in mnuVals: 498 window = (v >> 8) & 0xFF 499 if window not in windDict: 500 windDict[window] = [] 501 windDict[window].append(v & 0xFF) 502 503 #have to sort the keys - they're not in order! 504 windows = windDict.keys() 505 windows.sort() 506 507 #create the bitmaps 508 bmap = bytearray() 509 for w in windows: 510 bmapseg = bytearray(32) 511 maxoff = 0 512 for v in windDict[w]: 513 vm1 = v - 1 514 off = vm1 >> 3 515 bit = vm1 & 0x7 516 msk = 1 << bit 517 bmapseg[off] |= msk 518 maxoff = max(off, maxoff) 519 bmapseg = bmapseg[0:maxoff+1] 520 bmap += chr(w) + chr(maxoff+1) + bmapseg 521 522 strio.write(str(bmap)) 523 524 def decode(self, strio, length=None): 525 """ 526 Decode an NSEC/NSEC3 type bitmap into a string 527 representation of type names. 528 """ 529 self.type_bitmaps = "" 530 if length == None: 531 return 532 533 type_bitmaps = bytearray() 534 l = struct.calcsize(self.fmt) 535 parsed_length = 0 536 while parsed_length < length: 537 buff = readPrecisely(strio, l) 538 wb_num, bm_len = struct.unpack(self.fmt, buff) 539 assert parsed_length + 2 + bm_len <= length 540 bm = readPrecisely(strio, bm_len) 541 byteNum = -1 542 for b in bm: 543 byteNum += 1 544 ob = ord(b) 545 if ob == 0: 546 continue 547 548 for v in range(8): 549 msk = 1<<v 550 if ob & msk: 551 val = wb_num*256 + byteNum*8 + v + 1 552 mnu = QUERY_TYPES.get(val, None) 553 if not mnu: 554 mnu = 'TYPE' + str(val) 555 type_bitmaps += (mnu + ' ') 556 557 parsed_length += 2 + bm_len 558 559 self.type_bitmaps = str(type_bitmaps[0:-1]) 560 561 def __eq__(self, other): 562 if isinstance(other, TypeBitmaps): 563 return self.string == other.string 564 return False 565 566 def __hash__(self): 567 return hash(self.string) 568 569 def __str__(self): 570 return self.string 571 374 572 class Query: 375 573 """ 376 574 Represent a single DNS query. … … 434 632 return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 435 633 436 634 437 class RRHeader(tputil.FancyEqMixin): 635 636 class OPTHeader(tputil.FancyEqMixin): 438 637 """ 638 A OPT record header. 639 640 @cvar fmt: C{str} specifying the byte format of an OPT Header. 641 642 @ivar name: Root (0, 8-bits) 643 @ivar type: 41 (OPT Record) 644 @ivar payload: An object that implements the IEncodable interface 645 @ivar auth: Whether this header is authoritative or not. 646 """ 647 648 implements(IEncodable) 649 650 compareAttributes = ('name', 'type', 'payload', 'auth') 651 652 fmt = "!H" 653 654 name = None 655 type = None 656 payload = None 657 658 #OPTHeader _really_ has no ttl or rdlength, but the 659 #existence of the attributes is required. 660 ttl = None 661 rdlength = None 662 663 cachedResponse = None 664 665 def __init__(self, payload=None, auth=False): 666 """ 667 @type name: C{str} 668 @param name: Root (0) 669 670 @type type: C{int} 671 @param type: Query type 41. 672 673 @type payload: An object implementing C{IEncodable} 674 @param payload: The OPT payload 675 """ 676 assert (payload is None) or (payload.TYPE == OPT) 677 678 self.name = 0 679 self.type = OPT 680 self.payload = payload 681 self.auth = auth 682 683 def encode(self, strio, compDict=None): 684 strio.write(struct.pack('!B', 0)) 685 strio.write(struct.pack(self.fmt, self.type)) 686 if self.payload: 687 prefix = strio.tell() 688 self.payload.encode(strio, compDict) 689 aft = strio.tell() 690 strio.seek(prefix - 2, 0) 691 strio.write(struct.pack('!H', aft - prefix)) 692 strio.seek(aft, 0) 693 694 def decode(self, strio, length = None): 695 self.name.decode(strio) 696 l = struct.calcsize(self.fmt) 697 buff = readPrecisely(strio, l) 698 r = struct.unpack(self.fmt, buff) 699 self.type = r[0] 700 701 def isAuthoritative(self): 702 return self.auth 703 704 def __str__(self): 705 return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 706 707 @staticmethod 708 def factory(strio, auth=False): 709 ''' 710 reads enough of the stream to figure out if what is there is 711 an OPTHeader or an RRHeader 712 ''' 713 beginPos = strio.tell() 714 name = Name() 715 name.decode(strio) 716 type = struct.unpack(OPTHeader.fmt, readPrecisely(strio, 2))[0] 717 718 if len(name.name) == 0 and type == OPT: 719 return OPTHeader() 720 else: 721 #back up to the beginning and try again 722 strio.seek(beginPos, 0) 723 rrh = RRHeader(auth=auth) 724 rrh.decode(strio) 725 return rrh 726 727 __repr__ = __str__ 728 729 730 class RRHeader(OPTHeader): 731 """ 439 732 A resource record header. 440 733 441 734 @cvar fmt: C{str} specifying the byte format of an RR. … … 445 738 @ivar cls: The query class of the original request. 446 739 @ivar ttl: The time-to-live for this record. 447 740 @ivar payload: An object that implements the IEncodable interface 448 449 @ivar auth: A C{bool} indicating whether this C{RRHeader} was parsed from an 450 authoritative message. 741 @ivar auth: Whether this header is authoritative or not. 451 742 """ 452 743 453 744 implements(IEncodable) … … 1050 1341 1051 1342 fancybasename = 'SRV' 1052 1343 compareAttributes = ('priority', 'weight', 'target', 'port', 'ttl') 1053 showAttributes = ('priority', 'weight', ('target', 'target', '%s'), 'port', 'ttl') 1344 showAttributes = ('priority', 'weight', 1345 ('target', 'target', '%s'), 'port', 'ttl') 1054 1346 1055 1347 def __init__(self, priority=0, weight=0, port=0, target='', ttl=None): 1056 1348 self.priority = int(priority) … … 1469 1761 return hash(tuple(self.data)) 1470 1762 1471 1763 1764 class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 1765 """ 1766 EDNS0 Option record. 1767 1768 @type payload_size: C{int} 1769 @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 1770 network can handle. 1771 1772 @type dnssecOk: C{bool} 1773 @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 1774 validation (and set the AD bit if the response validates). 1775 1776 @type version: C{int} 1777 @ivar version: The version of DNSSEC used. Currently only version 0 1778 is defined. 1779 """ 1780 implements(IEncodable, IRecord) 1781 TYPE = OPT 1782 fmt = '!HBBHH' 1783 1784 fancybasename = 'OPT' 1785 showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 1786 compareAttributes = ('payload_size', 'flags', 'version') 1787 1788 def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 1789 self.payload_size = payload_size 1790 self.version = version 1791 self.flags = (dnssecOk & 1) << 15 1792 1793 def encode(self, strio, compDict = None): 1794 OPTHeader().encode(strio) 1795 strio.write(struct.pack('!H', self.payload_size)) 1796 strio.write(struct.pack('!B', 0)) # high order 0 1797 strio.write(struct.pack('!B', self.version)) 1798 strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 1799 strio.write(struct.pack('!H', 0)) # Data length: 0 1800 1801 def decode(self, strio, length=None): 1802 ''' 1803 are OPT Records always 0 rdlength? 1804 ''' 1805 l = struct.calcsize(self.fmt) 1806 buff = readPrecisely(strio, l) 1807 r = struct.unpack(self.fmt, buff) 1808 self.payload_size, z, self.version, self.flags, length = r 1809 assert length == 0 1810 1811 def __hash__(self): 1812 return hash((self.payload_size, self.version, self.flags)) 1472 1813 1814 class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 1815 """ 1816 DNSSEC RRSIG record. See RFC 4034 for details. 1817 1818 @type type_covered: C{int} 1819 @ivar type_covered: Identifies the type of the RRset that this RRSIG covers. 1820 1821 @type algo: C{int} 1822 @ivar algo: Identifies the crypto algorithm type used to create the signature. 1823 (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 1824 1825 @type labels: C{int} 1826 @ivar labels: Specifies the number of labels in the original RRSIG RR 1827 owner name. A validator can use this to determine whether the answer 1828 was synthesized from a wildcard. 1829 1830 @type original_ttl: C{int} 1831 @ivar original_ttl: Specifies the TTL of the covered RRset as it appears 1832 in the authoritative zone. 1833 1834 @type sig_expiration: C{int} 1835 @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 1836 since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 1837 1838 @type sig_inception: C{int} 1839 @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 1840 since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 1841 1842 @type key_tag: C{int} 1843 @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates 1844 this signature, in network byte order. See RFC 4034 App B. 1845 1846 @type signers_name: L{Name} 1847 @ivar signers_name: Identifies the owner name of the DNSKEY RR that a 1848 validator should use to validate this signature. Must not use DNS 1849 name compression. 1850 1851 @type signature: L{Sigstr} 1852 @ivar signature: Contains the cryptographic signature that covers the RRSIG 1853 RDATA (excluding the Signature field and the RRset specified by the 1854 RRSIG owner name, RRSIG class and RRSIG Type Covered fields. 1855 1856 @type ttl: C{int} 1857 @ivar ttl: The maximum number of seconds which this record should be 1858 cached. 1859 """ 1860 implements(IEncodable, IRecord) 1861 TYPE = RRSIG 1862 fmt = '!HBBIIIH' 1863 1864 fancybasename = 'RRSIG' 1865 showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 1866 ('_sig_expiration', 'sig_expiration', '%s'), 1867 ('_sig_inception', 'sig_inception', '%s'), 1868 'key_tag', 1869 ('signers_name', 'signers_name', '%s'), 1870 ('_signature', 'signature', '%s'), 'ttl') 1871 compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 1872 'sig_expiration', 'sig_inception', 'key_tag', 1873 'signers_name', 'signature', 'ttl') 1874 1875 _sig_expiration = property(lambda self: str(self.sig_expiration)) 1876 _sig_inception = property(lambda self: str(self.sig_inception)) 1877 _signature = property(lambda self: self.signature.string) 1878 1879 def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0, 1880 sig_expiration='', sig_inception='', key_tag=0, 1881 signers_name='', signature='', ttl=None): 1882 self.type_covered = type_covered 1883 self.algo = algo 1884 self.labels = labels 1885 self.original_ttl = original_ttl 1886 self.sig_expiration = DateSNA(sig_expiration) 1887 self.sig_inception = DateSNA(sig_inception) 1888 self.key_tag = key_tag 1889 self.signers_name = Name(signers_name) 1890 self.signature = Sigstr(signature) 1891 self.ttl = str2time(ttl) 1892 1893 def encode(self, strio, compDict = None): 1894 strio.write(struct.pack(self.fmt, 1895 self.type_covered, 1896 self.algo, 1897 self.labels, 1898 self.original_ttl, 1899 self.sig_expiration.asInt(), 1900 self.sig_inception.asInt(), 1901 self.key_tag)) 1902 self.signers_name.encode(strio, None) 1903 self.signature.encode(strio, compDict) 1904 1905 def decode(self, strio, length=None): 1906 start = strio.tell() 1907 l = struct.calcsize(self.fmt) 1908 buff = readPrecisely(strio, l) 1909 r = struct.unpack(self.fmt, buff) 1910 self.type_covered, self.algo, self.labels, self.original_ttl, \ 1911 sig_expiration, sig_inception, self.key_tag = r 1912 self.sig_expiration = DateSNA.fromInt(sig_expiration) 1913 self.sig_inception = DateSNA.fromInt(sig_inception) 1914 self.signers_name.decode(strio) 1915 here = strio.tell() 1916 self.signature.decode(strio, length + start - here if length else None) 1917 1918 def __hash__(self): 1919 return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 1920 self.sig_expiration, self.sig_inception, self.key_tag, 1921 self.signers_name, self.signature)) 1922 1923 class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 1924 """ 1925 A DNSSEC DS record. 1926 1927 @type key_tag: C{int} 1928 @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS 1929 record. 1930 1931 @type algo: C{int} 1932 @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this 1933 DS record. 1934 1935 @type digest_type: C{int} 1936 @ivar digest_type: Identifies the algorithm used to construct the digest 1937 field. 1938 1939 @type digest: L{Sigstr} 1940 @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by 1941 the algorithm identified by the digest_type field. 1942 1943 @type ttl: C{int} 1944 @ivar ttl: The maximum number of seconds which this record should be 1945 cached. 1946 """ 1947 implements(IEncodable, IRecord) 1948 TYPE = DS 1949 fmt = '!HBB' 1950 1951 fancybasename = 'DS' 1952 showAttributes = ('key_tag', 'algo', 'digest_type', ('_digest', 'digest', '%s'), 'ttl') 1953 compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 1954 1955 _digest = property(lambda self: self.digest.string) 1956 1957 def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 1958 self.key_tag = key_tag 1959 self.algo = algo 1960 self.digest_type = digest_type 1961 self.digest = Sigstr(digest) 1962 self.ttl = str2time(ttl) 1963 1964 def encode(self, strio, compDict = None): 1965 strio.write(struct.pack(self.fmt, 1966 self.key_tag, 1967 self.algo, 1968 self.digest_type)) 1969 self.digest.encode(strio, None) 1970 1971 def decode(self, strio, length=None): 1972 start = strio.tell() 1973 l = struct.calcsize(self.fmt) 1974 buff = readPrecisely(strio, l) 1975 r = struct.unpack(self.fmt, buff) 1976 self.key_tag, self.algo, self.digest_type = r 1977 here = strio.tell() 1978 self.digest.decode(strio, length + start - here if length else None) 1979 1980 def __hash__(self): 1981 return hash((self.key_tag, self.algo, self.digest_type, self.digest)) 1982 1983 class Record_DNSKEY(tputil.FancyEqMixin, tputil.FancyStrMixin): 1984 """ 1985 A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 1986 1987 @type flags: C{int} 1988 @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 1989 DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 1990 the name of a zone. If bit 7 has value 0, then the DNSKEY record 1991 holds some other type of DNS public key and MUST NOT be used to 1992 verify RRSIGs that cover RRsets. 1993 Bit 15 is the Secure Entry Point flag. See RFC 3757.) 1994 All other bits are reserved and must be zero. 1995 1996 @type protocol: C{int} 1997 @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 1998 if this field does not contain 3. 1999 2000 @type algo: C{int} 2001 @ivar algo: Identifies the public key's cryptographic algorithm and determines 2002 the format of the pub_key field. See RFC 4034 App A. 2003 2004 @type pub_key: L{Sigstr} 2005 @ivar pub_key: Holds the public key material. 2006 2007 @type ttl: C{int} 2008 @ivar ttl: The maximum number of seconds which this record should be 2009 cached. 2010 """ 2011 implements(IEncodable, IRecord) 2012 TYPE = DNSKEY 2013 fmt = '!HBB' 2014 2015 fancybasename = 'DNSKEY' 2016 showAttributes = ('flags', 'protocol', 'algo', ('_pub_key', 'pub_key', '%s'), 'ttl') 2017 compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 2018 2019 _pub_key = property(lambda self: self.pub_key.string) 2020 2021 def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 2022 self.flags = flags 2023 self.protocol = protocol 2024 self.algo = algo 2025 self.pub_key = Sigstr(pub_key) 2026 self.ttl = str2time(ttl) 2027 2028 def encode(self, strio, compDict = None): 2029 strio.write(struct.pack(self.fmt, 2030 self.flags, 2031 self.protocol, 2032 self.algo)) 2033 self.pub_key.encode(strio, None) 2034 2035 def decode(self, strio, length=None): 2036 start = strio.tell() 2037 l = struct.calcsize(self.fmt) 2038 buff = readPrecisely(strio, l) 2039 r = struct.unpack(self.fmt, buff) 2040 self.flags, self.protocol, self.algo = r 2041 here = strio.tell() 2042 self.pub_key.decode(strio, length + start - here if length else None) 2043 2044 def __hash__(self): 2045 return hash((self.flags, self.protocol, self.algo, self.pub_key)) 2046 2047 class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 2048 """ 2049 A DNSSEC NSEC record provides authenticated denial of existance for DNS data. 2050 2051 A DNSSEC NSEC record lists: 2052 2053 1) the next owner name in canonical ordering of the zone that contains 2054 authoritative data or a delegation point NS RRset. 2055 2056 2) the set of RR types present at the NSEC RR's owner name. 2057 2058 @type nxt_name: L{Name} 2059 @ivar nxt_name: The next owner name that has authoritative data or contains 2060 a delegation point NS RRset. 2061 2062 @type type_bitmaps: L{TypeBitmaps} 2063 @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's 2064 owner name. 2065 2066 @type ttl: C{int} 2067 @ivar ttl: The maximum number of seconds which this record should be 2068 cached. 2069 """ 2070 implements(IEncodable, IRecord) 2071 TYPE = NSEC 2072 2073 fancybasename = 'NSEC' 2074 showAttributes = (('nxt_name', 'nxt_name', '%s'), 2075 ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 2076 compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 2077 2078 _type_bitmaps = property(lambda self: self.type_bitmaps.string) 2079 2080 def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 2081 self.nxt_name = Name(nxt_name) 2082 self.type_bitmaps = TypeBitmaps(type_bitmaps) 2083 self.ttl = str2time(ttl) 2084 2085 def encode(self, strio, compDict = None): 2086 self.nxt_name.encode(strio, None) 2087 self.type_bitmaps.encode(strio, None) 2088 2089 def decode(self, strio, length=None): 2090 start = strio.tell() 2091 self.nxt_name.decode(strio, None) 2092 here = strio.tell() 2093 self.type_bitmaps.decode(strio, length + start - here if length else None) 2094 2095 def __hash__(self): 2096 return hash((self.nxt_name, self.type_bitmaps)) 2097 2098 class Record_NSEC3PARAM(tputil.FancyEqMixin, tputil.FancyStrMixin): 2099 """ 2100 A DNSSEC NSEC3PARAM record contains the NSEC3 parameters (hash algorithm, 2101 flags, iterations and salt) needed by authoritative servers to calculate 2102 hashed owner names. The presence of an NSEC3PARAM RR at a zone apex 2103 indicates that the specified parameters may be used by authoritative 2104 servers to choose an appropriate set of NSEC3 RRs for negative responses. 2105 2106 @type hash_algo: C{int} 2107 @ivar hash_algo: Identifies the cryptographic hash algorithm used to 2108 construct the hash value. 2109 2110 @type flags: C{int} 2111 @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is 2112 the opt-out flag. If the opt-out flag is set, the NSEC3 record covers 2113 zero or more unsigned delegations. If the opt-out flag is clear, the 2114 NSEC3 record covers zero unsigned delegations. 2115 2116 @type iterations: C{int} 2117 @ivar iterations: Defines the nubmer of additional times the hash algorithm 2118 has been performed. 2119 2120 @type salt: L{Charset} 2121 @ivar salt: Identifies the salt value provided to the hash. 2122 2123 @type ttl: C{int} 2124 @ivar ttl: The maximum number of seconds which this record should be 2125 cached. 2126 """ 2127 implements(IEncodable, IRecord) 2128 TYPE = NSEC3 2129 fmt = '!BBH' 2130 2131 fancybasename = 'NSEC3' 2132 showAttributes = ('hash_algo', 'flags', 'iterations', 2133 ('_salt', 'salt', '%s'), 'ttl') 2134 compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'ttl') 2135 2136 _salt = property(lambda self: self.salt.string) 2137 2138 def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', ttl=None): 2139 self.hash_algo = hash_algo 2140 self.flags = flags 2141 self.iterations = iterations 2142 self.salt = Charstr(salt) 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 2152 def decode(self, strio, length=None): 2153 start = strio.tell() 2154 l = struct.calcsize(self.fmt) 2155 buff = readPrecisely(strio, l) 2156 r = struct.unpack(self.fmt, buff) 2157 self.hash_algo, self.flags, self.iterations = r 2158 self.salt.decode(strio) 2159 here = strio.tell() 2160 2161 def __hash__(self): 2162 return hash((self.hash_algo, self.flags, self.iterations, self.salt)) 2163 2164 class Record_NSEC3(Record_NSEC3PARAM): 2165 """ 2166 A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of 2167 existence for DNS data and permits a gradual expansion of delegation-centric 2168 zones. 2169 2170 A DNSSEC NSEC3 record lists: 2171 2172 1) the set of RR types present at the original owner name of the NSEC RR. 2173 2174 2) the next hashed owner name in the hash order of the zone. 2175 2176 @type hash_algo: C{int} 2177 @ivar hash_algo: Identifies the cryptographic hash algorithm used to 2178 construct the hash value. 2179 2180 @type flags: C{int} 2181 @ivar flags: Identifies 8 1-bit flags. The only flag presently defined 2182 is the opt-out flag. If the opt-out flag is set, the NSEC3 record 2183 covers zero or more unsigned delegations. If the opt-out flag is 2184 clear, the NSEC3 record covers zero unsigned delegations. 2185 2186 @type iterations: C{int} 2187 @ivar iterations: Defines the nubmer of additional times the hash algorithm 2188 has been performed. 2189 2190 @type salt: L{Charset} 2191 @ivar salt: Identifies the salt value provided to the hash. 2192 2193 @type nxt_hash_owner_name: L{Charset} 2194 @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone 2195 in hash order. 2196 2197 @type type_bitmaps: L{TypeBitmaps} 2198 @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's 2199 original owner name. 2200 2201 @type ttl: C{int} 2202 @ivar ttl: The maximum number of seconds which this record should be 2203 cached. 2204 """ 2205 implements(IEncodable, IRecord) 2206 TYPE = NSEC3 2207 fmt = '!BBH' 2208 2209 fancybasename = 'NSEC3' 2210 showAttributes = ('hash_algo', 'flags', 'iterations', 2211 ('_salt', 'salt', '%s'), 2212 ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), 2213 ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 2214 compareAttributes = ('hash_algo', 'flags', 'iterations', 2215 'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 2216 2217 _salt = property(lambda self: self.salt.string) 2218 _type_bitmaps = property(lambda self: self.type_bitmaps.string) 2219 2220 def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', 2221 nxt_hash_owner='', type_bitmaps=None, ttl=None): 2222 Record_NSEC3PARAM.__init__(self, hash_algo, flags, iterations, salt, ttl) 2223 self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 2224 self.type_bitmaps = TypeBitmaps(type_bitmaps) 2225 2226 def encode(self, strio, compDict = None): 2227 Record_NSEC3PARAM.encode(self, strio, compDict) 2228 self.nxt_hash_owner_name.encode(strio, None) 2229 self.type_bitmaps.encode(strio, None) 2230 2231 def decode(self, strio, length=None): 2232 start = strio.tell() 2233 Record_NSEC3PARAM.decode(self, strio, compDict) 2234 self.nxt_hash_owner_name.decode(strio) 2235 here = strio.tell() 2236 self.type_bitmaps.decode(strio, length + start - here if length else None) 2237 2238 def __hash__(self): 2239 return hash((self.hash_algo, self.flags, self.iterations, self.salt, 2240 self.nxt_hash_owner_name, self.type_bitmaps)) 2241 1473 2242 # This is a fallback record 1474 2243 class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 1475 2244 """ … … 1546 2315 queries = answers = add = ns = None 1547 2316 1548 2317 def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 1549 auth=0, rCode=OK, trunc=0, maxSize=512):2318 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 1550 2319 self.maxSize = maxSize 1551 2320 self.id = id 1552 2321 self.answer = answer 1553 2322 self.opCode = opCode 1554 self.auth = auth 1555 self.trunc = trunc 1556 self.recDes = recDes 1557 self.recAv = recAv 2323 self.auth = auth #AA - Authoritative Answer 2324 self.trunc = trunc #TC - TrunCated 2325 self.recDes = recDes #RD - Recursion Desired 2326 self.recAv = recAv #RA - Recursion Available 2327 self.authData = authData #AD - Authentic Data 2328 self.chkDis = chkDis #CD - Checking Disabled 1558 2329 self.rCode = rCode 1559 2330 self.queries = [] 1560 2331 self.answers = [] … … 1599 2370 | ((self.auth & 1 ) << 2 ) 1600 2371 | ((self.trunc & 1 ) << 1 ) 1601 2372 | ( self.recDes & 1 ) ) 1602 byte4 = ( ( (self.recAv & 1 ) << 7 ) 2373 byte4 = ( ((self.recAv & 1 ) << 7 ) 2374 |((self.authData & 1 ) << 5 ) 2375 |((self.chkDis & 1 ) << 4 ) 1603 2376 | (self.rCode & 0xf ) ) 1604 2377 1605 2378 strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, … … 1619 2392 self.trunc = ( byte3 >> 1 ) & 1 1620 2393 self.recDes = byte3 & 1 1621 2394 self.recAv = ( byte4 >> 7 ) & 1 2395 self.authData = ( byte4 >> 5 ) & 1 2396 self.chkDis = ( byte4 >> 4 ) & 1 1622 2397 self.rCode = byte4 & 0xf 1623 2398 1624 2399 self.queries = [] … … 1637 2412 1638 2413 def parseRecords(self, list, num, strio): 1639 2414 for i in range(num): 1640 header = RRHeader(auth=self.auth)1641 2415 try: 1642 header .decode(strio)2416 header = OPTHeader.factory(strio, auth=self.auth) 1643 2417 except EOFError: 1644 2418 return 1645 2419 t = self.lookupRecordType(header.type) … … 1749 2523 query, or errbacked with any errors that could happen (exceptions 1750 2524 during writing of the query, timeout errors, ...). 1751 2525 """ 1752 m = Message(id, recDes=1) 2526 dnssecConfig = self.controller.dnssecConfig 2527 chkDis = dnssecConfig.chkDis 2528 m = Message(id, recDes=dnssecConfig.recDes, chkDis=chkDis) 1753 2529 m.queries = queries 2530 if dnssecConfig.ednsEnabled: 2531 m.additional = [Record_OPT(payload_size = dnssecConfig.maxUdpPktSz, 2532 version = dnssecConfig.version, 2533 dnssecOk = dnssecConfig.dnssecOk)] 1754 2534 1755 2535 try: 1756 2536 writeMessage(m) … … 1804 2584 self.transport.write(message.toStr(), address) 1805 2585 1806 2586 def startListening(self): 1807 self._reactor.listenUDP(0, self, maxPacketSize=512) 2587 maxPacketSize = 512 2588 if self.controller.dnssecConfig.ednsEnabled: 2589 maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 2590 self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 1808 2591 1809 2592 def datagramReceived(self, data, addr): 1810 2593 """ -
twisted/names/secondary.py
90 90 91 91 @ivar _reactor: The reactor to use to perform the zone transfers, or C{None} 92 92 to use the global reactor. 93 94 #ivar dnssecConfig a L{DnssecConfig} giving the DNSSEC configuration to set 95 on the resolver. 93 96 """ 94 97 95 98 transferring = False … … 97 100 _port = 53 98 101 _reactor = None 99 102 100 def __init__(self, primaryIP, domain ):101 common.ResolverBase.__init__(self )103 def __init__(self, primaryIP, domain, dnssecConfig=None): 104 common.ResolverBase.__init__(self, dnssecConfig) 102 105 self.primary = primaryIP 103 106 self.domain = domain 104 107 -
twisted/names/ser_num_arith.py
1 # -*- test-case-name: twisted.names.test.test_ser_num_arith -*- 2 # Copyright (c) Twisted Matrix Laboratories. 3 # See LICENSE for details. 4 5 """ 6 Serial Number Arithmetic 7 8 This module implements RFC 1982 DNS Serial Number Arithmetic 9 (see http://tools.ietf.org/pdf/rfc1982.pdf). 10 SNA is used in DNS and specifically in DNSSEC as defined in 11 RFC 4034 in the DNSSEC Signature Expiration and Inception Fields. 12 13 bob.novas@shinkuro.com 14 """ 15 16 import calendar, time 17 18 class SNA(object): 19 """ 20 implements RFC 1982 - DNS Serial Number Arithmetic 21 """ 22 SERIAL_BITS = 32 23 MODULOVAL = 2**SERIAL_BITS 24 HLFRNG = 2**(SERIAL_BITS-1) 25 MAXADD = (2**(SERIAL_BITS-1)-1) 26 27 def __init__(self, number): 28 self._number = int(number)%self.MODULOVAL 29 30 def __repr__(self): 31 return str(self._number) 32 33 def asInt(self): 34 return self._number 35 36 def eq(self, sna2): 37 assert isinstance(sna2, SNA) 38 return sna2._number == self._number 39 40 def lt(self, sna2): 41 assert isinstance(sna2, SNA) 42 return (not self.eq(sna2) and 43 ((self._number < sna2._number) and 44 ((sna2._number - self._number) < self.HLFRNG) or 45 (self._number > sna2._number) and 46 ((self._number - sna2._number) > self.HLFRNG))) 47 48 def gt(self, sna2): 49 assert isinstance(sna2, SNA) 50 return (not self.eq(sna2) and 51 ((self._number < sna2._number) and 52 ((sna2._number - self._number) > self.HLFRNG) or 53 (self._number > sna2._number) and 54 ((self._number - sna2._number) < self.HLFRNG))) 55 56 def le(self, sna2): 57 return self.eq(sna2) or self.lt(sna2) 58 59 def ge(self, sna2): 60 return self.eq(sna2) or self.gt(sna2) 61 62 def add(self, sna2): 63 assert isinstance(sna2, SNA) 64 if sna2.le(SNA(self.MAXADD)): 65 return SNA( (self._number + sna2._number)%self.MODULOVAL ) 66 else: 67 raise ArithmeticError 68 69 def __hash__(self): 70 return hash(self._number) 71 72 __eq__ = eq 73 __lt__ = lt 74 __gt__ = gt 75 __le__ = le 76 __ge__ = ge 77 __add__ = add 78 79 @staticmethod 80 def max(snaList): 81 """ 82 this takes a list of sna's from which it will pick the sn 83 with the highest value 84 """ 85 if len(snaList) == 0: 86 return None 87 trialMax = snaList[0] 88 for s in snaList[1:]: 89 if not trialMax: 90 trialMax = s 91 elif s and s > trialMax: 92 trialMax = s 93 return trialMax 94 95 class DateSNA(SNA): 96 """ 97 implements DNS Serial Number Arithmetic 98 for dates 'YYYYMMDDHHMMSS' per RFC 4034 P3.1.5 99 """ 100 fmt = '%Y%m%d%H%M%S' 101 102 def __init__(self, utcDateTime=''): 103 ''' 104 accept a UTC date/time string as YYMMDDHHMMSS 105 and convert it to seconds since the epoch 106 ''' 107 if not utcDateTime: 108 utcDateTime = '19700101000000' 109 dtstruct = time.strptime(utcDateTime, DateSNA.fmt) 110 assert dtstruct.tm_year < 1970+136 111 secondsSinceE = calendar.timegm(dtstruct) 112 super(DateSNA, self).__init__(secondsSinceE) 113 114 def add(self, sna2): 115 if not isinstance(sna2, SNA): 116 return NotImplemented 117 118 if (sna2.le(SNA(self.MAXADD)) and 119 (self._number + sna2._number < self.MODULOVAL)): 120 sna = SNA((self._number + sna2._number)%self.MODULOVAL) 121 return DateSNA.fromSNA(sna) 122 else: 123 raise ArithmeticError 124 125 def asDate(self): 126 dtstruct = time.gmtime(self._number) 127 return time.strftime(DateSNA.fmt, dtstruct) 128 129 @staticmethod 130 def fromSNA(sna): 131 assert isinstance(sna, SNA) 132 d = DateSNA() 133 d._number = sna._number 134 return d 135 136 @staticmethod 137 def fromInt(i): 138 return DateSNA.fromSNA(SNA(i)) 139 140 def __str__(self): 141 return self.asDate() 142 -
twisted/names/test/test_client.py
8 8 from twisted.names import client, dns 9 9 from twisted.names.error import DNSQueryTimeoutError 10 10 from twisted.trial import unittest 11 from twisted.names.common import ResolverBase 11 from twisted.names.common import ResolverBase, DnssecConfig 12 from twisted.names.dns import Query, Message 12 13 from twisted.internet import defer, error 13 14 from twisted.python import failure 14 15 from twisted.python.deprecate import getWarningMethod, setWarningMethod 15 16 from twisted.python.compat import set 17 from twisted.names.test.test_rootresolve import MemoryReactor 16 18 17 19 18 20 class FakeResolver(ResolverBase): … … 428 430 # Disconnecting should remove the protocol from the connection list: 429 431 protocol.connectionLost(None) 430 432 self.assertNotIn(protocol, resolver.connections) 433 434 435 def _edns0ConfigurationTest(self, reactor, resolver): 436 """ 437 A Resolver created with edns0 sends an OPT record as part of the 438 query indicating the maxUdpPktSz and EDNS version supported 439 (only EDNS version 0 - the default - is defined by spec). 440 441 In addition, check that the message flag bits (DO, CD, RC) agree 442 with the flags set in the resolver. 443 """ 444 #make sure EDNS is enabled 445 self.assertTrue(resolver.dnssecConfig.ednsEnabled) 446 447 d = resolver._query(('example.com', 53), 448 [Query('foo.example.com',dns.A, dns.IN)], 449 30) 450 451 # A UDP port should have been started 452 portNumber, transport = reactor.udpPorts.popitem() 453 454 # and a DNS packet sent 455 [(packet, address)] = transport._sentPackets 456 457 msg = Message() 458 msg.fromStr(packet) 459 460 # the query should have an additional OPT Header with 461 # version == 0 and payload_size as defined by the resolver's 462 # dnssecConfig and DO should be set 463 self.assertEqual(len(msg.additional), 1) 464 additional = msg.additional[0] 465 payload = additional.payload 466 dnssecConfig = resolver.dnssecConfig 467 self.assertEqual(additional.type, dns.OPT) 468 self.assertEqual(payload.version, dnssecConfig.version) 469 self.assertEqual(payload.payload_size, dnssecConfig.maxUdpPktSz) 470 #payload.flags bit 15 is DO, should equal resolver.dnssecOk 471 self.assertEqual(not not(payload.flags & 0x8000), dnssecConfig.dnssecOk) 472 473 # the rest of the query should be as above also 474 self.assertEqual(msg.queries, [Query('foo.example.com', dns.A, dns.IN)]) 475 self.assertEqual(msg.answers, []) 476 self.assertEqual(msg.authority, []) 431 477 478 # the message header flags should be set as per the resolver's 479 # dnssecConfig settings 480 self.assertEqual(msg.chkDis, dnssecConfig.chkDis) 481 self.assertEqual(msg.recDes, dnssecConfig.recDes) 482 483 response = [] 484 d.addCallback(response.append) 485 self.assertEqual(response, []) 486 487 # Once a reply is received, the Deferred should fire. 488 # Make the flag bits in the message agree with what you asked for 489 del msg.queries[:] 490 msg.answer = 1 491 msg.answers.append(dns.RRHeader('foo.example.com', 492 payload=dns.Record_A('5.8.13.21'))) 493 #if you requested DO, say you got AD 494 msg.authData = dnssecConfig.dnssecOk 495 msg.chkDis = dnssecConfig.chkDis 496 msg.recDes = dnssecConfig.recDes 497 transport._protocol.datagramReceived(msg.toStr(), ('1.1.2.4', 1053)) 498 return response[0] 432 499 500 501 def test_dnssecEnabled(self): 502 """ 503 A query sent with DNSSEC Enabled has an additional OPT record with 504 DO set. Such a query returns a 4-tuple as a result, with the 4th 505 member of the tuple being the message with the header bits set as 506 set in the original query. 507 """ 508 # Create a resolver with EDNS0, max packet size = 4096, 509 # and dnssecOk, chkDis and recDes = True 510 maxPacketSize = 4096 511 dsc = DnssecConfig(ednsEnabled=True, 512 maxUdpPktSz=maxPacketSize, 513 dnssecOk=True, # DO 514 chkDis=True, # CD 515 recDes=True) # RC 433 516 517 reactor = MemoryReactor() 518 resolver = client.Resolver(servers=[('example.com', 53)], 519 reactor=reactor, 520 dnssecConfig=dsc) 521 522 message = self._edns0ConfigurationTest(reactor, resolver) 523 524 #check that a resolver with dnssecOk returns a 4-tuple with the 525 #header set as in the query 526 answer, authority, additional, message = resolver.filterAnswers(message) 527 self.assertEqual(answer, [dns.RRHeader('foo.example.com', 528 payload=dns.Record_A('5.8.13.21', ttl=0))]) 529 self.assertEqual(authority, []) 530 self.assertEqual(additional, []) 531 self.assertIsInstance(message, dns.Message) 532 self.assertTrue(message.authData) 533 self.assertTrue(message.chkDis) 534 self.assertTrue(message.recDes) 535 536 537 def test_dnssecDisabled(self): 538 """ 539 A query sent with DNSSEC Disabled but EDNS enabled has an additional 540 OPT record with DO clear. Such a query returns a 3-tuple as a result. 541 """ 542 543 # Create a resolver with EDNS0, max packet size = 4096, 544 # and dnssecOk = False, but recDes = True 545 maxPacketSize = 4096 546 dsc = DnssecConfig(ednsEnabled=True, 547 maxUdpPktSz=maxPacketSize, 548 dnssecOk=False, # not DO 549 recDes=True) # RC 550 551 reactor = MemoryReactor() 552 resolver = client.Resolver(servers=[('example.com', 53)], 553 reactor=reactor, 554 dnssecConfig=dsc) 555 556 message = self._edns0ConfigurationTest(reactor, resolver) 557 558 #check that a resolver with dnssecOk == False returns a 3-tuple 559 #containing the right stuff. Note - no access to header info in this case 560 answer, authority, additional = resolver.filterAnswers(message) 561 self.assertEqual(answer, 562 [dns.RRHeader('foo.example.com', 563 payload=dns.Record_A('5.8.13.21', ttl=0))]) 564 self.assertEqual(authority, []) 565 self.assertEqual(additional, []) 566 567 434 568 class ClientTestCase(unittest.TestCase): 435 569 436 570 def setUp(self): … … 658 792 return d 659 793 660 794 795 def test_lookupDNSKey(self): 796 """ 797 See L{test_lookupAddress} 798 """ 799 d = client.lookupDNSKey(self.hostname) 800 d.addCallback(self.checkResult, dns.DNSKEY) 801 return d 802 803 804 def test_lookupDS(self): 805 """ 806 See L{test_lookupAddress} 807 """ 808 d = client.lookupDS(self.hostname) 809 d.addCallback(self.checkResult, dns.DS) 810 return d 811 812 813 def test_lookupNSEC(self): 814 """ 815 See L{test_lookupAddress} 816 """ 817 d = client.lookupNSEC(self.hostname) 818 d.addCallback(self.checkResult, dns.NSEC) 819 return d 820 821 822 def test_lookupNSEC3(self): 823 """ 824 See L{test_lookupAddress} 825 """ 826 d = client.lookupNSEC3(self.hostname) 827 d.addCallback(self.checkResult, dns.NSEC3) 828 return d 829 830 831 def test_lookupNSEC3Param(self): 832 """ 833 See L{test_lookupAddress} 834 """ 835 d = client.lookupNSEC3Param(self.hostname) 836 d.addCallback(self.checkResult, dns.NSEC3PARAM) 837 return d 838 839 840 def test_lookupRRSIG(self): 841 """ 842 See L{test_lookupAddress} 843 """ 844 d = client.lookupRRSIG(self.hostname) 845 d.addCallback(self.checkResult, dns.RRSIG) 846 return d 847 848 661 849 class ThreadedResolverTests(unittest.TestCase): 662 850 """ 663 851 Tests for L{client.ThreadedResolver}. -
twisted/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_NSEC3PARAM, 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. … … 439 511 Initialize the controller: create a list of messages. 440 512 """ 441 513 self.messages = [] 514 self.dnssecConfig = common.DnssecConfig() 442 515 443 516 444 517 def messageReceived(self, msg, proto, addr): … … 893 966 repr(dns.UnknownRecord("foo\x1fbar", 12)), 894 967 "<UNKNOWN data='foo\\x1fbar' ttl=12>") 895 968 969 def test_dnskey(self): 970 """ 971 The repr of a L{dns.DNSKEY} instance includes the flags, protocol, 972 algo, pub_key and ttl fields of the record. 973 """ 974 self.assertEqual( 975 repr(dns.Record_DNSKEY(10, 20, 30, "foo\x1fbar", ttl=20)), 976 "<DNSKEY flags=10 protocol=20 algo=30 pub_key=foo\x1fbar ttl=20>") 977 978 def test_ds(self): 979 """ 980 The repr of a L{dns.DS} instance includes the key_tag, algo, digest_type, 981 digest and ttl fields of the record. 982 """ 983 self.assertEqual( 984 repr(dns.Record_DS(11, 22, 33, "foo\x1fbar1", ttl=21)), 985 "<DS key_tag=11 algo=22 digest_type=33 digest=foo\x1fbar1 ttl=21>") 986 987 def test_nsec(self): 988 """ 989 The repr of a L{dns.NSEC} instance includes the nxt_name, type_bitmaps 990 and ttl fields of the record. 991 """ 992 self.assertEqual( 993 repr(dns.Record_NSEC('bob', "\x1fabcd", ttl=31)), 994 "<NSEC nxt_name=bob type_bitmaps=\x1fabcd ttl=31>") 995 996 def test_nsec3param(self): 997 """ 998 The repr of a L{dns.NSEC3PARAM} instance includes the hash_algo, flags, 999 iterations, salt and ttl fields of the record. 1000 """ 1001 self.assertEqual( 1002 repr(dns.Record_NSEC3PARAM(1, 2, 3, '\x12\x34', ttl=31)), 1003 "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 ttl=31>") 1004 1005 def test_nsec3(self): 1006 """ 1007 The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, iterations, 1008 salt, nxt_hash_owner_name, type_bitmaps and ttl fields of the record. 1009 """ 1010 self.assertEqual( 1011 repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', "\x1fabcd", ttl=31)), 1012 "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 nxt_hash_owner_name=bob type_bitmaps=\x1fabcd ttl=31>") 1013 1014 def test_opt(self): 1015 """ 1016 The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk flag, 1017 and version fields of the record. (The OPT record has no ttl field.) 1018 """ 1019 self.assertEqual( 1020 repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 1021 "<OPT payload_size=1492 flags=0x8000 version=0>") 896 1022 1023 def test_rrsig(self): 1024 """ 1025 The repr of a L{dns.RRSIG} instance includes the algo, labels, original_ttl 1026 sig_expiration, sig_inception, key_tag, signers_name, signature and ttl 1027 fields of the record. 1028 """ 1029 self.assertEqual( 1030 repr(dns.Record_RRSIG(type_covered=dns.A, 1031 algo=2, 1032 labels=3, 1033 original_ttl=30, 1034 sig_expiration='20110101123456', 1035 sig_inception= '20110202112233', 1036 key_tag=60, 1037 signers_name='bob', 1038 signature='\x12\x34sig', 1039 ttl=70)), 1040 "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 1041 + " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 1042 + " signers_name=bob signature=\x12\x34sig ttl=70>") 897 1043 898 1044 class _Equal(object): 899 1045 """ … … 961 1107 cls('example.com', 123), 962 1108 cls('example.org', 123)) 963 1109 1110 def test_optheader(self): 1111 """ 1112 Two OptHeader instances comapare equal iff the have the same 1113 (Record_OPT) payload and auth bit. 1114 """ 1115 self._equalityTest( 1116 dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, 1117 dnssecOk=True, 1118 version=0, 1119 ttl=30)), 1120 dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, 1121 dnssecOk=True, 1122 version=0, 1123 ttl=30)), 1124 dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492, 1125 dnssecOk=False, 1126 version=0, 1127 ttl=40), auth=True)) 964 1128 965 1129 def test_rrheader(self): 966 1130 """ … … 1483 1647 dns.UnknownRecord('foo', ttl=10), 1484 1648 dns.UnknownRecord('foo', ttl=10), 1485 1649 dns.UnknownRecord('foo', ttl=100)) 1650 1651 def test_rrsig(self): 1652 """ 1653 L(dns.RRSIG) instances compare equal iff they have the same 1654 type_covered, algo, labels, original_ttl, sig_expiration, sig_inception, 1655 key_tag, signers_name, signature, and ttl 1656 """ 1657 self._equalityTest( 1658 dns.Record_RRSIG(type_covered=dns.A), 1659 dns.Record_RRSIG(type_covered=dns.A), 1660 dns.Record_RRSIG(type_covered=dns.AAAA)) 1661 self._equalityTest( 1662 dns.Record_RRSIG(algo=1), 1663 dns.Record_RRSIG(algo=1), 1664 dns.Record_RRSIG(algo=2)) 1665 self._equalityTest( 1666 dns.Record_RRSIG(labels=3), 1667 dns.Record_RRSIG(labels=3), 1668 dns.Record_RRSIG(labels=4)) 1669 self._equalityTest( 1670 dns.Record_RRSIG(original_ttl=5), 1671 dns.Record_RRSIG(original_ttl=5), 1672 dns.Record_RRSIG(original_ttl=6)) 1673 self._equalityTest( 1674 dns.Record_RRSIG(sig_expiration='20110101000000'), 1675 dns.Record_RRSIG(sig_expiration='20110101000000'), 1676 dns.Record_RRSIG(sig_expiration='20110101000001')) 1677 self._equalityTest( 1678 dns.Record_RRSIG(sig_inception='20120101000000'), 1679 dns.Record_RRSIG(sig_inception='20120101000000'), 1680 dns.Record_RRSIG(sig_inception='20120101000001')) 1681 self._equalityTest( 1682 dns.Record_RRSIG(key_tag=11), 1683 dns.Record_RRSIG(key_tag=11), 1684 dns.Record_RRSIG(key_tag=12)) 1685 self._equalityTest( 1686 dns.Record_RRSIG(signers_name='bob'), 1687 dns.Record_RRSIG(signers_name='bob'), 1688 dns.Record_RRSIG(signers_name='joe')) 1689 self._equalityTest( 1690 dns.Record_RRSIG(signature='abcdef'), 1691 dns.Record_RRSIG(signature='abcdef'), 1692 dns.Record_RRSIG(signature='abcdefg')) 1693 self._equalityTest( 1694 dns.Record_RRSIG(ttl=10), 1695 dns.Record_RRSIG(ttl=10), 1696 dns.Record_RRSIG(ttl=20)) 1697 1698 def test_ds(self): 1699 """ 1700 L(dns.DS) instances compare equal iff they have the same 1701 key_tag, algo, digest_type, digest and ttl 1702 """ 1703 self._equalityTest( 1704 dns.Record_DS(key_tag=1), 1705 dns.Record_DS(key_tag=1), 1706 dns.Record_DS(key_tag=2)) 1707 self._equalityTest( 1708 dns.Record_DS(algo=3), 1709 dns.Record_DS(algo=3), 1710 dns.Record_DS(algo=4)) 1711 self._equalityTest( 1712 dns.Record_DS(digest_type=5), 1713 dns.Record_DS(digest_type=5), 1714 dns.Record_DS(digest_type=6)) 1715 self._equalityTest( 1716 dns.Record_DS(digest='abcdef-digest'), 1717 dns.Record_DS(digest='abcdef-digest'), 1718 dns.Record_DS(digest='abcdef-digest-f')) 1719 self._equalityTest( 1720 dns.Record_DS(ttl=10), 1721 dns.Record_DS(ttl=10), 1722 dns.Record_DS(ttl=20)) 1723 1724 def test_dnskey(self): 1725 """ 1726 L(dns.DNSKEY) instances compare equal iff they have the same 1727 flags, protocol, algo, pub_key and ttl 1728 """ 1729 self._equalityTest( 1730 dns.Record_DNSKEY(flags=1), 1731 dns.Record_DNSKEY(flags=1), 1732 dns.Record_DNSKEY(flags=2)) 1733 self._equalityTest( 1734 dns.Record_DNSKEY(protocol=3), 1735 dns.Record_DNSKEY(protocol=3), 1736 dns.Record_DNSKEY(protocol=4)) 1737 self._equalityTest( 1738 dns.Record_DNSKEY(algo=5), 1739 dns.Record_DNSKEY(algo=5), 1740 dns.Record_DNSKEY(algo=6)) 1741 self._equalityTest( 1742 dns.Record_DNSKEY(pub_key='abcdef-digest'), 1743 dns.Record_DNSKEY(pub_key='abcdef-digest'), 1744 dns.Record_DNSKEY(pub_key='abcdef-digest-f')) 1745 self._equalityTest( 1746 dns.Record_DNSKEY(ttl=10), 1747 dns.Record_DNSKEY(ttl=10), 1748 dns.Record_DNSKEY(ttl=20)) 1749 1750 def test_nsec(self): 1751 """ 1752 L(dns.DNSKEY) instances compare equal iff they have the same 1753 nxt_name, type_bitmaps and ttl 1754 """ 1755 self._equalityTest( 1756 dns.Record_NSEC(nxt_name="example.com"), 1757 dns.Record_NSEC(nxt_name="example.com"), 1758 dns.Record_NSEC(nxt_name="a.example.com")) 1759 self._equalityTest( 1760 dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 1761 dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 1762 dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 1763 self._equalityTest( 1764 dns.Record_NSEC(ttl=5), 1765 dns.Record_NSEC(ttl=5), 1766 dns.Record_NSEC(ttl=6)) 1767 1768 def test_nsec3param(self): 1769 """ 1770 L(dns.DNSKEY) instances compare equal iff they have the same 1771 hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 1772 """ 1773 self._equalityTest( 1774 dns.Record_NSEC3PARAM(hash_algo=1), 1775 dns.Record_NSEC3PARAM(hash_algo=1), 1776 dns.Record_NSEC3PARAM(hash_algo=2)) 1777 self._equalityTest( 1778 dns.Record_NSEC3PARAM(flags=1), 1779 dns.Record_NSEC3PARAM(flags=1), 1780 dns.Record_NSEC3PARAM(flags=2)) 1781 self._equalityTest( 1782 dns.Record_NSEC3PARAM(iterations=5), 1783 dns.Record_NSEC3PARAM(iterations=5), 1784 dns.Record_NSEC3PARAM(iterations=6)) 1785 self._equalityTest( 1786 dns.Record_NSEC3PARAM(salt="abcdef"), 1787 dns.Record_NSEC3PARAM(salt="abcdef"), 1788 dns.Record_NSEC3PARAM(salt="abcdefg")) 1789 self._equalityTest( 1790 dns.Record_NSEC3PARAM(ttl=5), 1791 dns.Record_NSEC3PARAM(ttl=5), 1792 dns.Record_NSEC3PARAM(ttl=6)) 1793 1794 def test_nsec3(self): 1795 """ 1796 L(dns.DNSKEY) instances compare equal iff they have the same 1797 hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 1798 """ 1799 self._equalityTest( 1800 dns.Record_NSEC3(hash_algo=1), 1801 dns.Record_NSEC3(hash_algo=1), 1802 dns.Record_NSEC3(hash_algo=2)) 1803 self._equalityTest( 1804 dns.Record_NSEC3(flags=1), 1805 dns.Record_NSEC3(flags=1), 1806 dns.Record_NSEC3(flags=2)) 1807 self._equalityTest( 1808 dns.Record_NSEC3(iterations=5), 1809 dns.Record_NSEC3(iterations=5), 1810 dns.Record_NSEC3(iterations=6)) 1811 self._equalityTest( 1812 dns.Record_NSEC3(salt="abcdef"), 1813 dns.Record_NSEC3(salt="abcdef"), 1814 dns.Record_NSEC3(salt="abcdefg")) 1815 self._equalityTest( 1816 dns.Record_NSEC3(nxt_hash_owner="example.com"), 1817 dns.Record_NSEC3(nxt_hash_owner="example.com"), 1818 dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 1819 self._equalityTest( 1820 dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 1821 dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 1822 dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 1823 self._equalityTest( 1824 dns.Record_NSEC3(ttl=5), 1825 dns.Record_NSEC3(ttl=5), 1826 dns.Record_NSEC3(ttl=6)) 1827 1828 1829 1830 No newline at end of file -
twisted/names/test/test_names.py
98 98 '\x12\x01\x16\xfe\xc1\x00\x01'), 99 99 dns.Record_NAPTR(100, 10, "u", "sip+E2U", 100 100 "!^.*$!sip:information@domain.tld!"), 101 dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF')], 101 dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF'), 102 dns.Record_DNSKEY(0x10, 3, 5, 103 "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=" 104 )], 102 105 'http.tcp.test-domain.com': [ 103 106 dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') 104 107 ], 105 108 'host.test-domain.com': [ 106 109 dns.Record_A('123.242.1.5'), 107 110 dns.Record_A('0.255.0.255'), 111 dns.Record_RRSIG(dns.A, 5, 3, 86400, '20120101000000', '20120201000000', 2642, 'test-domain.com', 112 "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=") 108 113 ], 109 114 'host-two.test-domain.com': [ 110 115 # … … 224 229 """Test DNS 'A' record queries with multiple answers""" 225 230 return self.namesTest( 226 231 self.resolver.lookupAddress('host.test-domain.com'), 227 [dns.Record_A('123.242.1.5', ttl=19283784), dns.Record_A('0.255.0.255', ttl=19283784)] 232 [dns.Record_A('123.242.1.5', ttl=19283784), 233 dns.Record_A('0.255.0.255', ttl=19283784)] 228 234 ) 229 235 230 236 … … 232 238 """Test DNS 'A' record queries with edge cases""" 233 239 return self.namesTest( 234 240 self.resolver.lookupAddress('host-two.test-domain.com'), 235 [dns.Record_A('255.255.255.254', ttl=19283784), dns.Record_A('0.0.0.0', ttl=19283784)] 241 [dns.Record_A('255.255.255.254', ttl=19283784), 242 dns.Record_A('0.0.0.0', ttl=19283784)] 236 243 ) 237 244 238 245 … … 264 271 """Test DNS 'HINFO' record queries""" 265 272 return self.namesTest( 266 273 self.resolver.lookupHostInfo('test-domain.com'), 267 [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', ttl=19283784)] 274 [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', 275 ttl=19283784)] 268 276 ) 269 277 270 278 def testPTR(self): … … 286 294 """Test additional processing for CNAME records""" 287 295 return self.namesTest( 288 296 self.resolver.lookupAddress('cname.test-domain.com'), 289 [dns.Record_CNAME('test-domain.com', ttl=19283784), dns.Record_A('127.0.0.1', ttl=19283784)] 297 [dns.Record_CNAME('test-domain.com', ttl=19283784), 298 dns.Record_A('127.0.0.1', ttl=19283784)] 290 299 ) 291 300 292 301 def testMB(self): … … 317 326 """Test DNS 'MINFO' record queries""" 318 327 return self.namesTest( 319 328 self.resolver.lookupMailboxInfo('test-domain.com'), 320 [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', ttl=19283784)] 329 [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', 330 ttl=19283784)] 321 331 ) 322 332 323 333 … … 325 335 """Test DNS 'SRV' record queries""" 326 336 return self.namesTest( 327 337 self.resolver.lookupService('http.tcp.test-domain.com'), 328 [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl=19283784)] 338 [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', 339 ttl=19283784)] 329 340 ) 330 341 331 342 def testAFSDB(self): 332 343 """Test DNS 'AFSDB' record queries""" 333 344 return self.namesTest( 334 345 self.resolver.lookupAFSDatabase('test-domain.com'), 335 [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', ttl=19283784)] 346 [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', 347 ttl=19283784)] 336 348 ) 337 349 338 350 … … 340 352 """Test DNS 'RP' record queries""" 341 353 return self.namesTest( 342 354 self.resolver.lookupResponsibility('test-domain.com'), 343 [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', ttl=19283784)] 355 [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', 356 ttl=19283784)] 344 357 ) 345 358 346 359 … … 348 361 """Test DNS 'TXT' record queries""" 349 362 return self.namesTest( 350 363 self.resolver.lookupText('test-domain.com'), 351 [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', ttl=19283784), 352 dns.Record_TXT('Some more text, haha! Yes. \0 Still here?', ttl=19283784)] 364 [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', 365 ttl=19283784), 366 dns.Record_TXT('Some more text, haha! Yes. \0 Still here?', 367 ttl=19283784)] 353 368 ) 354 369 355 370 … … 359 374 """ 360 375 return self.namesTest( 361 376 self.resolver.lookupSenderPolicy('test-domain.com'), 362 [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all', ttl=19283784), 363 dns.Record_SPF('v=spf1 +mx a:\0colo', '.example.com/28 -all not valid', ttl=19283784)] 377 [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all', 378 ttl=19283784), 379 dns.Record_SPF('v=spf1 +mx a:\0colo', 380 '.example.com/28 -all not valid', 381 ttl=19283784)] 364 382 ) 365 383 366 384 … … 368 386 """Test DNS 'WKS' record queries""" 369 387 return self.namesTest( 370 388 self.resolver.lookupWellKnownServices('test-domain.com'), 371 [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] 389 [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, 390 '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] 372 391 ) 373 392 374 393 … … 381 400 dns.Record_A('1.2.3.4', ttl='1S'), 382 401 dns.Record_NS('ns1.domain', ttl='2M'), 383 402 dns.Record_NS('ns2.domain', ttl='3H'), 384 dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D')] 403 dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', 404 ttl='4D')] 385 405 ) 386 406 387 407 … … 389 409 """Test DNS 'AAAA' record queries (IPv6)""" 390 410 return self.namesTest( 391 411 self.resolver.lookupIPV6Address('test-domain.com'), 392 [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', ttl=19283784)] 412 [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', 413 ttl=19283784)] 393 414 ) 394 415 395 416 def testA6(self): … … 398 419 self.resolver.lookupAddress6('test-domain.com'), 399 420 [dns.Record_A6(0, 'ABCD::4321', '', ttl=19283784), 400 421 dns.Record_A6(12, '0:0069::0', 'some.network.tld', ttl=19283784), 401 dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net', ttl=19283784)] 422 dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 423 'tra.la.la.net', ttl=19283784)] 402 424 ) 403 425 404 426 … … 407 429 Test DNS 'AXFR' queries (Zone transfer) 408 430 """ 409 431 default_ttl = soa_record.expire 410 results = [copy.copy(r) for r in reduce(operator.add, test_domain_com.records.values())] 432 results = [copy.copy(r) 433 for r in reduce(operator.add, 434 test_domain_com.records.values())] 411 435 for r in results: 412 436 if r.ttl is None: 413 437 r.ttl = default_ttl … … 434 458 [dns.Record_NAPTR(100, 10, "u", "sip+E2U", 435 459 "!^.*$!sip:information@domain.tld!", 436 460 ttl=19283784)]) 461 462 def test_DNSKEY(self): 463 """Test DNS 'DNSKEY' record queries.""" 464 return self.namesTest( 465 self.resolver.lookupDNSKey('test-domain.com'), 466 [dns.Record_DNSKEY(0x10, 3, 5, 467 "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=", 468 ttl=19283784)]) 437 469 438 439 440 470 class DNSServerFactoryTests(unittest.TestCase): 441 471 """ 442 472 Tests for L{server.DNSServerFactory}. … … 523 553 self.d.addCallback(self._gotResults) 524 554 self.controller = client.AXFRController('fooby.com', self.d) 525 555 526 self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, ttl=86400, auth=False, 556 self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, 557 ttl=86400, auth=False, 527 558 payload=dns.Record_SOA(mname='fooby.com', 528 559 rname='hooj.fooby.com', 529 560 serial=100, … … 535 566 536 567 self.records = [ 537 568 self.soa, 538 dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, 569 dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, 570 auth=False, 539 571 payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700)), 540 572 541 573 dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, auth=False, … … 548 580 549 581 def _makeMessage(self): 550 582 # hooray they all have the same message format 551 return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, auth=1, rCode=0, trunc=0, maxSize=0) 583 return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, 584 auth=1, rCode=0, trunc=0, maxSize=0) 552 585 553 586 def testBindAndTNamesStyle(self): 554 587 # Bind style = One big single message … … 890 923 self.assertEqual(service.domains[1].domain, 'example.edu') 891 924 892 925 893 894 926 class SecondaryAuthorityTests(unittest.TestCase): 895 927 """ 896 928 L{twisted.names.secondary.SecondaryAuthority} correctly constructs objects -
twisted/names/test/test_ser_num_arith.py
1 # Copyright (c) Twisted Matrix Laboratories. 2 # See LICENSE for details. 3 4 """ 5 Test cases for L{twisted.names.ser_num_arith}. 6 """ 7 8 from twisted.names.ser_num_arith import SNA, DateSNA 9 from twisted.trial import unittest 10 11 class SNATest(unittest.TestCase): 12 13 def setUp(self): 14 self.s1 = SNA(1) 15 self.s1a = SNA(1) 16 self.s2 = SNA(2) 17 self.sMaxVal = SNA(SNA.HLFRNG+SNA.HLFRNG-1) 18 19 def test_equality(self): 20 """ 21 Test SNA equality 22 """ 23 self.assertEqual(self.s1, self.s1a) 24 self.assertNotIdentical(self.s1, self.s1a) 25 self.assertEqual(hash(self.s1), hash(self.s1a)) 26 self.assertNotEqual(hash(self.s1), hash(self.s2)) 27 28 def test_le(self): 29 """ 30 Test SNA less than or equal 31 """ 32 self.assertTrue( self.s1 <= self.s1 ) 33 self.assertTrue( self.s1 <= self.s1a ) 34 self.assertTrue( self.s1 <= self.s2 ) 35 self.assertFalse( self.s2 <= self.s1 ) 36 37 def test_ge(self): 38 """ 39 Test SNA greater than or equal 40 """ 41 self.assertTrue( self.s1 >= self.s1 ) 42 self.assertTrue( self.s1 >= self.s1a ) 43 self.assertFalse( self.s1 >= self.s2 ) 44 self.assertTrue( self.s2 >= self.s1 ) 45 46 47 def test_lt(self): 48 """ 49 Test SNA less than 50 """ 51 self.assertFalse( self.s1 < self.s1 ) 52 self.assertFalse( self.s1 < self.s1a ) 53 self.assertTrue( self.s1 < self.s2 ) 54 self.assertFalse( self.s2 < self.s1 ) 55 56 def test_gt(self): 57 """ 58 Test SNA greater than 59 """ 60 self.assertFalse( self.s1 > self.s1 ) 61 self.assertFalse( self.s1 > self.s1a ) 62 self.assertFalse( self.s1 > self.s2 ) 63 self.assertTrue( self.s2 > self.s1 ) 64 65 def test_add(self): 66 """ 67 Test SNA addition 68 """ 69 self.assertEqual( self.s1 + self.s1, self.s2) 70 self.assertEqual( self.s1 + SNA(SNA.MAXADD), SNA(SNA.MAXADD + 1) ) 71 self.assertEqual( SNA(SNA.MAXADD) + SNA(SNA.MAXADD) + SNA(2), SNA(0) ) 72 73 def test_maxval(self): 74 """ 75 Test SNA maxval 76 """ 77 smaxplus1 = self.sMaxVal + self.s1 78 self.assertTrue( smaxplus1 > self.sMaxVal ) 79 self.assertEqual( smaxplus1, SNA(0) ) 80 81 def test_max(self): 82 """ 83 Test the SNA max function 84 """ 85 self.assertEqual( SNA.max([None, self.s1]), self.s1 ) 86 self.assertEqual( SNA.max([self.s1, None]), self.s1 ) 87 self.assertEqual( SNA.max([self.s1, self.s1a]), self.s1 ) 88 self.assertEqual( SNA.max([self.s2, self.s1a, self.s1, None]), self.s2 ) 89 self.assertEqual( SNA.max([SNA(SNA.MAXADD), self.s2, self.s1a, self.s1, None]), 90 SNA(SNA.MAXADD) ) 91 self.assertEqual( SNA.max([self.s2, self.s1a, self.s1, None, self.sMaxVal]), 92 self.s2 ) 93 94 def test_dateSNA(self): 95 """ 96 Test DateSNA construction and comparison 97 """ 98 date1 = DateSNA('20120101000000') 99 date2 = DateSNA('20130101000000') 100 self.assertTrue( date1 < date2 ) 101 102 def test_dateAdd(self): 103 """ 104 Test DateSNA addition 105 """ 106 date3 = DateSNA('20370101000000') 107 sna1 = SNA(365*24*60*60) 108 date4 = date3 + sna1 109 self.assertEqual( date4.asInt(), date3.asInt() + sna1.asInt()) 110 111 def test_asDate(self): 112 """ 113 Test DateSNA conversion 114 """ 115 date1 = '20120101000000' 116 date1Sna = DateSNA(date1) 117 self.assertEqual(date1Sna.asDate(), date1) 118 119 def test_roundTrip(self): 120 """ 121 Test DateSNA conversion 122 """ 123 date1 = '20370101000000' 124 date1Sna = DateSNA(date1) 125 intval = date1Sna.asInt() 126 sna1a = SNA(intval) 127 128 dateSna1a = DateSNA.fromSNA(sna1a) 129 self.assertEqual(date1Sna, dateSna1a) 130 131 dateSna2 = DateSNA.fromInt(intval) 132 self.assertEqual(date1Sna, dateSna2) 133 134 No newline at end of file
