Ticket #5454: addEdsn0AndDnssec5454V04.patch

File addEdsn0AndDnssec5454V04.patch, 105.1 KB (added by BobNovas, 3 years ago)

addresses tjijs' comments

  • doc/names/examples/index.xhtml

     
    1515        <li><a href="testdns.py">testdns.py</a> - Prints the results of an Address record lookup, Mail-Exchanger record lookup, and Nameserver record lookup for the given hostname for a given hostname.</li> 
    1616        <li><a href="dns-service.py">dns-service.py</a> - Searches for SRV records in DNS.</li> 
    1717        <li><a href="gethostbyname.py">gethostbyname.py</a> - Returns the IP address for a given hostname.</li> 
     18        <li><a href="dnssecTest.py">dnssecTest.py</a></li> 
    1819    </ul> 
    1920</body> 
    2021</html> 
  • doc/names/examples/testdnssec.py

     
     1#!/usr/bin/env python 
     2 
     3# Copyright (c) Twisted Matrix Laboratories. 
     4# See LICENSE for details. 
     5 
     6""" 
     7Sample app to lookup DS records and show a DNSSEC result 
     8""" 
     9 
     10import sys 
     11from twisted.names.common import DnssecConfig 
     12from twisted.names.client import Resolver 
     13from twisted.names import client 
     14from twisted.internet import reactor 
     15 
     16def deferredAnswer(result): 
     17    #expect - a 4-tuple with a couple of DS RR's and an RRSIG RR in the answer. 
     18    print "    Answer: %s\n    Authority: %s\n    Additional: %s\n    Message: %s" % result 
     19     
     20    #expect - the AD bit to be set 
     21    message = result[3] 
     22    authData = not not message.authData 
     23    print "expect authData to be True: %s" % authData 
     24     
     25    reactor.stop() 
     26 
     27def errAnswer(error): 
     28    print "Error: %s" % error 
     29    reactor.stop() 
     30 
     31def main(): 
     32 
     33    reactor.callWhenRunning(doLookup) 
     34    reactor.run() 
     35 
     36def doLookup(): 
     37 
     38    #DnssecConfig - set ednsEnabled True if dnssecOk is True or you won't get 
     39    # a DNSSEC result - since DO is in the EDNS OPT record. 
     40    #For efficiency, set maxUdpPktSz large enough to get a DNSSEC message  
     41        # without falling back to TCP but not so large that a network with small 
     42    # MTU fragments packets.  1492 is generally absolutely safe.   
     43        # 4096 usually works. It depends on the network.         
     44    dsc = DnssecConfig(ednsEnabled=True, maxUdpPktSz=4096, dnssecOk=True, chkDis=False) 
     45 
     46    #setup a DNSSEC resolver using a public validating resolver  
     47    # and set it as the client's theResolver 
     48    resolver = Resolver(servers=[('149.20.64.20', 53)], dnssecConfig=dsc) 
     49    client.theResolver = resolver 
     50 
     51    #query for DS records for comcast.net  
     52    client.lookupDS('comcast.net')\ 
     53        .addCallback(deferredAnswer)\ 
     54        .addErrback(errAnswer) 
     55 
     56if __name__ == '__main__': 
     57    main() 
     58 No newline at end of file 
  • doc/names/howto/names.xhtml

     
    4949directives are not yet supported. 
    5050</p> 
    5151 
     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 <a href="http://www.ietf.org/rfc/rfc4033.txt">RFC4033</a>.) To use DNSSEC requires EDNS0, because to enable DNSSEC requires setting the DNSSEC OK (DO) bit which is in the EDNS0 OPT Record. <a href="http://www.ietf.org/rfc/rfc4035.txt"> RFC4035</a> 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 
    5260</body></html> 
  • twisted/names/client.py

     
    7171    protocol = property(_getProtocol) 
    7272 
    7373 
    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): 
    7580        """ 
    7681        Construct a resolver which will query domain name servers listed in 
    7782        the C{resolv.conf(5)}-format file given by C{resolv} as well as 
     
    99104            for DNS datagrams, and enforce timeouts.  If not provided, the 
    100105            global reactor will be used. 
    101106 
     107        @param dnssecConfig: An L{DnssecConfig} - see common.DnssecConfig() 
     108 
    102109        @raise ValueError: Raised if no nameserver addresses can be found. 
    103110        """ 
    104         common.ResolverBase.__init__(self) 
     111        common.ResolverBase.__init__(self, dnssecConfig) 
    105112 
    106113        if reactor is None: 
    107114            from twisted.internet import reactor 
     
    381388            return self.queryTCP(message.queries).addCallback(self.filterAnswers) 
    382389        if message.rCode != dns.OK: 
    383390            return failure.Failure(self.exceptionForCode(message.rCode)(message)) 
    384         return (message.answers, message.authority, message.additional) 
    385391 
     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, 
     398                    message.additional, message) 
     399        else: 
     400            #dnssecOk was not requested - return a legacy 3-tuple 
     401            return (message.answers, message.authority, message.additional) 
    386402 
     403 
    387404    def _lookup(self, name, cls, type, timeout): 
    388405        """ 
    389406        Build a L{dns.Query} for the given parameters and dispatch it via UDP. 
     
    953970    @rtype: C{Deferred} 
    954971    """ 
    955972    return getResolver().lookupNamingAuthorityPointer(name, timeout) 
     973 
     974 
     975def lookupDNSKey(name, timeout=None): 
     976    """ 
     977    DNSKEY lookup. 
     978 
     979    @type name: C{str} 
     980    @param name: DNS name to resolve. 
     981 
     982    @type timeout: Sequence of C{int} 
     983    @param timeout: Number of seconds after which to reissue the query. 
     984        When the last timeout expires, the query is considered failed. 
     985 
     986    @rtype: C{Deferred} 
     987     
     988    @since: 12.1 
     989    """ 
     990    return getResolver().lookupDNSKey(name, timeout) 
     991 
     992 
     993def lookupDS(name, timeout=None): 
     994    """ 
     995    DS lookup. 
     996 
     997    @type name: C{str} 
     998    @param name: DNS name to resolve. 
     999 
     1000    @type timeout: Sequence of C{int} 
     1001    @param timeout: Number of seconds after which to reissue the query. 
     1002        When the last timeout expires, the query is considered failed. 
     1003 
     1004    @rtype: C{Deferred} 
     1005     
     1006    @since: 12.1 
     1007    """ 
     1008    return getResolver().lookupDS(name, timeout) 
     1009 
     1010 
     1011def lookupNSEC(name, timeout=None): 
     1012    """ 
     1013    NSEC lookup. 
     1014 
     1015    @type name: C{str} 
     1016    @param name: DNS name to resolve. 
     1017 
     1018    @type timeout: Sequence of C{int} 
     1019    @param timeout: Number of seconds after which to reissue the query. 
     1020        When the last timeout expires, the query is considered failed. 
     1021 
     1022    @rtype: C{Deferred} 
     1023     
     1024    @since: 12.1 
     1025    """ 
     1026    return getResolver().lookupNSEC(name, timeout) 
     1027 
     1028 
     1029def lookupNSEC3(name, timeout=None): 
     1030    """ 
     1031    NSEC3 lookup. 
     1032 
     1033    @type name: C{str} 
     1034    @param name: DNS name to resolve. 
     1035 
     1036    @type timeout: Sequence of C{int} 
     1037    @param timeout: Number of seconds after which to reissue the query. 
     1038        When the last timeout expires, the query is considered failed. 
     1039 
     1040    @rtype: C{Deferred} 
     1041     
     1042    @since: 12.1 
     1043    """ 
     1044    return getResolver().lookupNSEC3(name, timeout) 
     1045 
     1046 
     1047def lookupNSEC3Param(name, timeout=None): 
     1048    """ 
     1049    NSEC3 Param lookup. 
     1050 
     1051    @type name: C{str} 
     1052    @param name: DNS name to resolve. 
     1053 
     1054    @type timeout: Sequence of C{int} 
     1055    @param timeout: Number of seconds after which to reissue the query. 
     1056        When the last timeout expires, the query is considered failed. 
     1057 
     1058    @rtype: C{Deferred} 
     1059     
     1060    @since: 12.1 
     1061    """ 
     1062    return getResolver().lookupNSEC3Param(name, timeout) 
     1063 
     1064 
     1065def lookupRRSIG(name, timeout=None): 
     1066    """ 
     1067    RRSIG lookup. 
     1068 
     1069    @type name: C{str} 
     1070    @param name: DNS name to resolve. 
     1071 
     1072    @type timeout: Sequence of C{int} 
     1073    @param timeout: Number of seconds after which to reissue the query. 
     1074        When the last timeout expires, the query is considered failed. 
     1075 
     1076    @rtype: C{Deferred} 
     1077     
     1078    @since: 12.1 
     1079    """ 
     1080    return getResolver().lookupRRSIG(name, timeout) 
  • twisted/names/common.py

     
    1818 
    1919EMPTY_RESULT = (), (), () 
    2020 
     21 
     22 
     23class DnssecConfig(): 
     24    """ 
     25    Sets recDes and DNSSEC parameters. See the following RFC's for details: 
     26     
     27        U{RFC 4033: DNS Security Introduction and Requirements 
     28            <http://www.ietf.org/rfc/rfc4033.txt>} 
     29     
     30        U{RFC 4034: Resource Records for the DNS Security Extensions 
     31            <http://www.ietf.org/rfc/rfc4034.txt>} 
     32     
     33        U{RFC 4035: Protocol Modifications for the DNS Security Extensions 
     34            <http://www.ietf.org/rfc/rfc4035.txt>} 
     35 
     36    @type recDes: C{bool} 
     37    @ivar recDes: Recursion Desired (RD flag). Not a DNSSEC parameter and does 
     38        not require L{ednsEnabled}, but still nice to be able to control  
     39        whether or not you're asking for recursion. 
     40 
     41    @type ednsEnabled: C{bool} 
     42    @ivar ednsEnabled: If True, adds an OPT record to the query.  
     43        The OPT record contains a version field (see L{version}) that  
     44        indicates the version of EDNS that you can handle. 
     45 
     46    @type maxUdpPktSz: C{int} 
     47    @ivar maxUdpPktSz: The max size UDP packet (bytes) that your end-to-end 
     48        network can handle. On a modern network a reliable size is 1492, 
     49        although up to 65535 is possible. Requires L{ednsEnabled} to be True. 
     50 
     51    @type dnssecOK: C{bool} 
     52    @ivar dnssecOK: Dnssec Ok (DO flag). If True, sets a flag that indicates  
     53        you want DNSSEC RR's and validation if the resolver validates. If DO  
     54        is set, AD will be set in the response if the answer validates. 
     55        Requires L{ednsEnabled}. 
     56 
     57    @type chkDis: C{bool} 
     58    @ivar chkDis: Checking Disabled (CD flag). If dnssecOk and chkDis are both 
     59        True, a validating resolver won't do validation but will return the 
     60        DNSSEC RR's so that YOU can. Requires L{ednsEnabled} 
     61 
     62    @type version: C{int} 
     63    @ivar version: Sets the EDNS version level. Currently, only version 0 is 
     64        defined and supported by U{RFC 2671: Extension Mechanisms for DNS  
     65        (EDNS0)<http://www.ietf.org/rfc/rfc2671.txt>}       
     66                     
     67    @since: 12.1 
     68    """ 
     69    def __init__(self, 
     70                 recDes=True, 
     71                 ednsEnabled=False, 
     72                 maxUdpPktSz=512, 
     73                 dnssecOk=False, 
     74                 chkDis=False, 
     75                 version=0): 
     76 
     77        self.recDes = recDes 
     78        self.ednsEnabled = ednsEnabled 
     79        self.maxUdpPktSz = maxUdpPktSz 
     80        self.dnssecOk = dnssecOk 
     81        self.chkDis = chkDis 
     82        self.version = version 
     83 
     84        assert not self.ednsEnabled or 512 <= self.maxUdpPktSz <= 65535 
     85        assert version == 0 
     86 
     87 
     88 
    2189class ResolverBase: 
    2290    """ 
    2391    L{ResolverBase} is a base class for L{IResolver} implementations which 
     
    36104 
    37105    typeToMethod = None 
    38106 
    39     def __init__(self): 
     107    def __init__(self, dnssecConfig=None): 
    40108        self.typeToMethod = {} 
    41109        for (k, v) in typeToMethod.items(): 
    42110            self.typeToMethod[k] = getattr(self, v) 
     111        self.dnssecConfig = dnssecConfig 
     112        if self.dnssecConfig == None: 
     113            self.dnssecConfig = DnssecConfig() 
    43114 
    44  
    45115    def exceptionForCode(self, responseCode): 
    46116        """ 
    47117        Convert a response code (one of the possible values of 
     
    201271        """ 
    202272        return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) 
    203273 
     274 
     275    def lookupDNSKey(self, name, timeout=None): 
     276        """ 
     277        @see: twisted.names.client.lookupDNSKey 
     278         
     279        @since: 12.1 
     280        """ 
     281        return self._lookup(name, dns.IN, dns.DNSKEY, timeout) 
     282 
     283 
     284    def lookupDS(self, name, timeout=None): 
     285        """ 
     286        @see: twisted.names.client.lookupDS 
     287         
     288        @since: 12.1 
     289        """ 
     290        return self._lookup(name, dns.IN, dns.DS, timeout) 
     291 
     292 
     293    def lookupNSEC(self, name, timeout=None): 
     294        """ 
     295        @see: twisted.names.client.lookupNSEC 
     296         
     297        @since: 12.1 
     298        """ 
     299        return self._lookup(name, dns.IN, dns.NSEC, timeout) 
     300 
     301 
     302    def lookupNSEC3(self, name, timeout=None): 
     303        """ 
     304        @see: twisted.names.client.lookupNSEC3 
     305         
     306        @since: 12.1 
     307        """ 
     308        return self._lookup(name, dns.IN, dns.NSEC3, timeout) 
     309 
     310 
     311    def lookupNSEC3Param(self, name, timeout=None): 
     312        """ 
     313        @see: twisted.names.client.lookupNSEC3Param 
     314         
     315        @since: 12.1 
     316        """ 
     317        return self._lookup(name, dns.IN, dns.NSEC3PARAM, timeout) 
     318 
     319 
     320    def lookupRRSIG(self, name, timeout=None): 
     321        """ 
     322        @see: twisted.names.client.lookupRRSIG 
     323         
     324        @since: 12.1 
     325        """ 
     326        return self._lookup(name, dns.IN, dns.RRSIG, timeout) 
     327 
     328 
    204329    def getHostByName(self, name, timeout = None, effort = 10): 
    205330        """ 
    206331        @see: twisted.names.client.getHostByName 
     
    268393    dns.MX:    'lookupMailExchange', 
    269394    dns.TXT:   'lookupText', 
    270395    dns.SPF:   'lookupSenderPolicy', 
     396    dns.DNSKEY:'lookupDNSKey', 
     397    dns.DS:    'lookupDS', 
     398    dns.NSEC:  'lookupNSEC', 
     399    dns.NSEC3: 'lookupNSEC3', 
     400    dns.NSEC3PARAM: 'lookupNSEC3Param', 
     401    dns.RRSIG: 'lookupRRSIG', 
    271402 
    272403    dns.RP:    'lookupResponsibility', 
    273404    dns.AFSDB: 'lookupAFSDatabase', 
  • twisted/names/dns.py

     
    1515__all__ = [ 
    1616    'IEncodable', 'IRecord', 
    1717 
    18     'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'HINFO', 
     18    'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'DNSKEY', 'DS', 'HINFO', 
    1919    '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', 
    2122 
    2223    'ANY', 'CH', 'CS', 'HS', 'IN', 
    2324 
     
    2627    'EFORMAT', 'ENAME', 'ENOTIMP', 'EREFUSED', 'ESERVER', 
    2728 
    2829    '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', 
    3032    'Record_MG', 'Record_MINFO', 'Record_MR', 'Record_MX', 'Record_NAPTR', 
    31     'Record_NS', 'Record_NULL', 'Record_PTR', 'Record_RP', 'Record_SOA', 
    32     'Record_SPF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 
     33    'Record_NS', 'Record_NSEC', 'Record_NSEC3', 'Record_NULL', 'Record_OPT', 
     34    'Record_PTR', 'Record_RP', 'Record_RRSIG', 'Record_SOA', 'Record_SPF', 
     35    'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 
    3336 
    3437    'QUERY_CLASSES', 'QUERY_TYPES', 'REV_CLASSES', 'REV_TYPES', 'EXT_QUERIES', 
    3538 
    36     'Charstr', 'Message', 'Name', 'Query', 'RRHeader', 'SimpleRecord', 
    37     'DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', 
     39    'Charstr', 'Message', 'Name', 'OPTHeader', 'Query', 'RRHeader', 
     40    'SimpleRecord','DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', 
    3841 
    3942    'OK', 'OP_INVERSE', 'OP_NOTIFY', 'OP_QUERY', 'OP_STATUS', 'OP_UPDATE', 
    4043    'PORT', 
     
    4649# System imports 
    4750import warnings 
    4851 
     52import re 
    4953import struct, random, types, socket 
    5054 
    5155import cStringIO as StringIO 
     
    5458 
    5559from zope.interface import implements, Interface, Attribute 
    5660 
     61from base64 import b64decode, b64encode 
    5762 
    5863# Twisted imports 
    5964from twisted.internet import protocol, defer 
     
    6166from twisted.python import log, failure 
    6267from twisted.python import util as tputil 
    6368from twisted.python import randbytes 
     69from twisted.names.ser_num_arith import SNA, DateSNA 
    6470 
    6571 
    6672def randomSource(): 
     
    7985NAPTR = 35 
    8086A6 = 38 
    8187DNAME = 39 
     88OPT = 41 
     89DS = 43 
     90RRSIG = 46 
     91NSEC = 47 
     92DNSKEY = 48 
     93NSEC3 = 50 
     94NSEC3PARAM = 51 
    8295SPF = 99 
    8396 
    8497QUERY_TYPES = { 
     
    108121    NAPTR: 'NAPTR', 
    109122    A6: 'A6', 
    110123    DNAME: 'DNAME', 
    111     SPF: 'SPF' 
     124    OPT: 'OPT', 
     125    DS: 'DS', 
     126    RRSIG: 'RRSIG', 
     127    NSEC: 'NSEC', 
     128    DNSKEY: 'DNSKEY', 
     129    NSEC3: 'NSEC3', 
     130    NSEC3PARAM: 'NSEC3PARAM', 
     131    SPF: 'SPF', 
    112132} 
    113133 
    114134IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) 
     
    371391    def __str__(self): 
    372392        return self.name 
    373393 
     394class Sigstr(object): 
     395    """ 
     396    for signatures and keys. display as b64 encoded 
     397     
     398    @since: 12.1 
     399    """ 
     400    implements(IEncodable) 
     401 
     402    def __init__(self, string=''): 
     403        if not isinstance(string, str): 
     404            raise ValueError("%r is not a string" % (string, )) 
     405        self.string = string # b64encoded string 
     406 
     407    def encode(self, strio, compDict=None): 
     408        """ 
     409        Write the byte representation (the un-b64-encoded string) 
     410        to the file. 
     411 
     412        @type strio: file 
     413        @param srio: The byte representation of this signature or key 
     414        will be written to this file 
     415 
     416        @type compDict: dict 
     417        @param compDict: not used. 
     418        """ 
     419        strio.write(b64decode(self.string)) 
     420 
     421    def decode(self, strio, length=None): 
     422        """ 
     423        Decode a signature or a key. 
     424 
     425        @type strio: file 
     426        @param strio: Exactly length bytes will be read from this file 
     427        to decode the full signature or key 
     428 
     429        @type length: int 
     430        @param lenth: length must always be given. A signature or key 
     431        is always the last thing in an RR and so you can always determine 
     432        its length. 
     433        """ 
     434        self.string = '' 
     435        if length == None: 
     436            return 
     437 
     438        assert isinstance(length, int) 
     439        buff = readPrecisely(strio, length) 
     440        self.string = b64encode(buff) 
     441 
     442    def __eq__(self, other): 
     443        if isinstance(other, Sigstr): 
     444            return self.string == other.string 
     445        return False 
     446 
     447    def __hash__(self): 
     448        return hash(self.string) 
     449 
     450    def __str__(self): 
     451        return self.string 
     452 
     453 
     454class TypeBitmaps(object): 
     455    """ 
     456    bitmap encoding scheme used by NSEC and NSEC3 RR's 
     457    to indicate the RRset types that exist at the 
     458    NSEC/NSEC3 RR's original owner name or hashed name. 
     459 
     460    See the following RFC's for details:  
     461     
     462        U{RFC 4034: Resource Records for the DNS Security Extensions 
     463            <http://www.ietf.org/rfc/rfc4034.txt>} 
     464 
     465        U{RFC 5155: DNS Security (DNSSEC) Hashed Authenticated Denial of 
     466            Existence <http://tools.ietf.org/rfc/rfc5155.txt>} 
     467     
     468    @since: 12.1 
     469    """ 
     470    fmt = 'BB' 
     471    typeRegex = re.compile('TYPE(\d+)') 
     472 
     473    def __init__(self, string=''): 
     474        self.string = string 
     475 
     476    def encode(self, strio, compDict=None): 
     477        """ 
     478        Encode the string field, which consists of a set 
     479        of type names, into an NSEC/NSEC3 type bitmap. 
     480 
     481        @type strio: file 
     482        @param strio: the byte representation of the type bitmap 
     483        will be written to this file. 
     484 
     485        @type compDict: dict 
     486        @param compDict: not used. 
     487        """ 
     488        if not self.string: 
     489            return; 
     490 
     491        # get a sorted list of RR Type Values 
     492        mnus = self.string.split(' ') 
     493        mnuVals = [] 
     494        for mnu in mnus: 
     495            mnuVal = REV_TYPES.get(mnu, None) 
     496            if not mnuVal: 
     497                m = self.typeRegex.match(mnu) 
     498                if m.groups(): 
     499                    mnuVal = int(m.group(1)) 
     500                    assert mnuVal < 65536 
     501                else: 
     502                    log.err("can't parse %s in %s" % (mnu, self.string, )) 
     503                    continue; 
     504            mnuVals.append(mnuVal) 
     505        mnuVals.sort() 
     506 
     507        # convert that to a dict of windows and lists 
     508        windDict = {} 
     509        for v in mnuVals: 
     510            window = (v >> 8) & 0xFF 
     511            if window not in windDict: 
     512                windDict[window] = [] 
     513            windDict[window].append(v & 0xFF) 
     514 
     515        # have to sort the keys - they're not in order! 
     516        windows = windDict.keys() 
     517        windows.sort() 
     518 
     519        # create the bitmaps 
     520        bmap = bytearray() 
     521        for w in windows: 
     522            bmapseg = bytearray(32) 
     523            maxoff = 0 
     524            for v in windDict[w]: 
     525                vm1 = v - 1 
     526                off = vm1 >> 3 
     527                bit = vm1 & 0x7 
     528                msk = 1 << bit 
     529                bmapseg[off] |= msk 
     530                maxoff = max(off, maxoff) 
     531            bmapseg = bmapseg[0:maxoff+1] 
     532            bmap += chr(w) + chr(maxoff+1) + bmapseg 
     533 
     534        strio.write(str(bmap)) 
     535 
     536    def decode(self, strio, length=None): 
     537        """ 
     538        Decode an NSEC/NSEC3 type bitmap into a string 
     539        representation of type names. 
     540        """ 
     541        self.type_bitmaps = "" 
     542        if length == None: 
     543            return 
     544 
     545        type_bitmaps = bytearray() 
     546        l = struct.calcsize(self.fmt) 
     547        parsed_length = 0 
     548        while parsed_length < length: 
     549            buff = readPrecisely(strio, l) 
     550            wb_num, bm_len = struct.unpack(self.fmt, buff) 
     551            assert parsed_length + 2 + bm_len <= length 
     552            bm = readPrecisely(strio, bm_len) 
     553            byteNum = -1 
     554            for b in bm: 
     555                byteNum += 1 
     556                ob = ord(b) 
     557                if ob == 0: 
     558                    continue 
     559 
     560                for v in range(8): 
     561                    msk = 1<<v 
     562                    if ob & msk: 
     563                        val = wb_num*256 + byteNum*8 + v + 1 
     564                        mnu = QUERY_TYPES.get(val, None) 
     565                        if not mnu: 
     566                            mnu = 'TYPE' + str(val) 
     567                        type_bitmaps += (mnu + ' ') 
     568 
     569            parsed_length += 2 + bm_len 
     570 
     571        self.type_bitmaps = str(type_bitmaps[0:-1]) 
     572 
     573    def __eq__(self, other): 
     574        if isinstance(other, TypeBitmaps): 
     575            return self.string == other.string 
     576        return False 
     577 
     578    def __hash__(self): 
     579        return hash(self.string) 
     580 
     581    def __str__(self): 
     582        return self.string 
     583 
    374584class Query: 
    375585    """ 
    376586    Represent a single DNS query. 
     
    434644        return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 
    435645 
    436646 
    437 class RRHeader(tputil.FancyEqMixin): 
     647 
     648class OPTHeader(tputil.FancyEqMixin): 
    438649    """ 
     650    A OPT record header. 
     651 
     652    @cvar fmt: C{str} specifying the byte format of an OPT Header. 
     653 
     654    @ivar name: Root (0, 8-bits) 
     655    @ivar type: 41 (OPT Record) 
     656    @ivar payload: An object that implements the IEncodable interface 
     657    @ivar auth: Whether this header is authoritative or not. 
     658     
     659    @since: 12.1 
     660    """ 
     661 
     662    implements(IEncodable) 
     663 
     664    compareAttributes = ('name', 'type', 'payload', 'auth') 
     665 
     666    fmt = "!H" 
     667 
     668    name = None 
     669    type = None 
     670    payload = None 
     671 
     672    # OPTHeader _really_ has no ttl or rdlength, but the 
     673    # existence of the attributes is required. 
     674    ttl = None 
     675    rdlength = None 
     676 
     677    cachedResponse = None 
     678 
     679 
     680    def __init__(self, payload=None, auth=False): 
     681        """ 
     682        @type name: C{str} 
     683        @param name: Root (0) 
     684 
     685        @type type: C{int} 
     686        @param type: Query type 41. 
     687 
     688        @type payload: An object implementing C{IEncodable} 
     689        @param payload: The OPT payload 
     690        """ 
     691        assert (payload is None) or (payload.TYPE == OPT) 
     692 
     693        self.name = 0 
     694        self.type = OPT 
     695        self.payload = payload 
     696        self.auth = auth 
     697 
     698 
     699    def encode(self, strio, compDict=None): 
     700        """ 
     701        Encode this OPT record header into proper format 
     702         
     703        @type strio: file 
     704        @param strio: the byte representation of this OPTHeader will be written 
     705        to this file. 
     706         
     707        @type compDict: dict 
     708        @param compDict: not used. 
     709        """ 
     710        strio.write(struct.pack('!B', 0)) 
     711        strio.write(struct.pack(self.fmt, self.type)) 
     712        if self.payload: 
     713            prefix = strio.tell() 
     714            self.payload.encode(strio, compDict) 
     715            aft = strio.tell() 
     716            strio.seek(prefix - 2, 0) 
     717            strio.write(struct.pack('!H', aft - prefix)) 
     718            strio.seek(aft, 0) 
     719 
     720 
     721    def decode(self, strio, length = None): 
     722        """ 
     723        Decode a byte string into this OPTHeader. 
     724 
     725        @type strio: file 
     726        @param strio: Bytes will be read from this file until the full  
     727        OPTHeader is decoded. 
     728        """ 
     729        self.name.decode(strio) 
     730        l = struct.calcsize(self.fmt) 
     731        buff = readPrecisely(strio, l) 
     732        r = struct.unpack(self.fmt, buff) 
     733        self.type = r[0] 
     734 
     735 
     736    def isAuthoritative(self): 
     737        return self.auth 
     738 
     739 
     740    def __str__(self): 
     741        return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 
     742 
     743 
     744    @classmethod 
     745    def _headerFactory(cls, strio, auth=False): 
     746        """ 
     747        reads enough of the stream to figure out if what is there is 
     748        an OPTHeader or an RRHeader 
     749        """ 
     750        beginPos = strio.tell() 
     751        name = Name() 
     752        name.decode(strio) 
     753        type = struct.unpack(cls.fmt, readPrecisely(strio, 2))[0] 
     754 
     755        if len(name.name) == 0 and type == OPT: 
     756            return cls() 
     757        else: 
     758            # back up to the beginning and try again 
     759            strio.seek(beginPos, 0) 
     760            rrh = RRHeader(auth=auth) 
     761            rrh.decode(strio) 
     762            return rrh 
     763 
     764    __repr__ = __str__ 
     765 
     766 
     767 
     768class RRHeader(OPTHeader): 
     769    """ 
    439770    A resource record header. 
    440771 
    441772    @cvar fmt: C{str} specifying the byte format of an RR. 
     
    445776    @ivar cls: The query class of the original request. 
    446777    @ivar ttl: The time-to-live for this record. 
    447778    @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. 
     779    @ivar auth: Whether this header is authoritative or not. 
    451780    """ 
    452781 
    453782    implements(IEncodable) 
     
    10501379 
    10511380    fancybasename = 'SRV' 
    10521381    compareAttributes = ('priority', 'weight', 'target', 'port', 'ttl') 
    1053     showAttributes = ('priority', 'weight', ('target', 'target', '%s'), 'port', 'ttl') 
     1382    showAttributes = ('priority', 'weight', 
     1383                      ('target', 'target', '%s'), 'port', 'ttl') 
    10541384 
    10551385    def __init__(self, priority=0, weight=0, port=0, target='', ttl=None): 
    10561386        self.priority = int(priority) 
     
    14641794 
    14651795 
    14661796 
     1797class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1798    """ 
     1799    EDNS0 Option record. 
     1800 
     1801    @type payload_size: C{int} 
     1802    @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 
     1803        network can handle. 
     1804 
     1805    @type dnssecOk: C{bool} 
     1806    @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 
     1807        validation (and set the AD bit if the response validates). 
     1808 
     1809    @type version: C{int} 
     1810    @ivar version: The version of DNSSEC used. Currently only version 0 
     1811        is defined. 
     1812         
     1813    @since: 12.1 
     1814    """ 
     1815    implements(IEncodable, IRecord) 
     1816    TYPE = OPT 
     1817    fmt = '!HBBHH' 
     1818 
     1819    fancybasename = 'OPT' 
     1820    showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 
     1821    compareAttributes = ('payload_size', 'flags', 'version') 
     1822 
     1823 
     1824    def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 
     1825        self.payload_size = payload_size 
     1826        self.version = version 
     1827        self.flags = (dnssecOk & 1) << 15 
     1828 
     1829 
     1830    def encode(self, strio, compDict = None): 
     1831        OPTHeader().encode(strio) 
     1832        strio.write(struct.pack('!H', self.payload_size)) 
     1833        strio.write(struct.pack('!B', 0)) # high order 0 
     1834        strio.write(struct.pack('!B', self.version)) 
     1835        strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 
     1836        strio.write(struct.pack('!H', 0)) # Data length: 0 
     1837 
     1838 
     1839    def decode(self, strio, length=None): 
     1840        """ 
     1841        are OPT Records always 0 rdlength? 
     1842        """ 
     1843        l = struct.calcsize(self.fmt) 
     1844        buff = readPrecisely(strio, l) 
     1845        r = struct.unpack(self.fmt, buff) 
     1846        self.payload_size, z, self.version, self.flags, length = r 
     1847        assert length == 0 
     1848 
     1849 
     1850    def __hash__(self): 
     1851        return hash((self.payload_size, self.version, self.flags)) 
     1852 
     1853 
     1854 
     1855class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1856    """ 
     1857    DNSSEC RRSIG record.  See RFC 4034 for details. 
     1858 
     1859    @type type_covered: C{int} 
     1860    @ivar type_covered: Identifies the type of the RRset that this RRSIG covers. 
     1861 
     1862    @type algo: C{int} 
     1863    @ivar algo: Identifies the crypto algorithm type used to create the 
     1864        signature. 
     1865        (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 
     1866 
     1867    @type labels: C{int} 
     1868    @ivar labels: Specifies the number of labels in the original RRSIG RR 
     1869        owner name. A validator can use this to determine whether the answer 
     1870        was synthesized from a wildcard. 
     1871 
     1872    @type original_ttl: C{int} 
     1873    @ivar original_ttl: Specifies the TTL of the covered RRset as it appears 
     1874        in the authoritative zone. 
     1875 
     1876    @type sig_expiration: C{int} 
     1877    @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 
     1878        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1879 
     1880    @type sig_inception: C{int} 
     1881    @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 
     1882        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1883 
     1884    @type key_tag: C{int} 
     1885    @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates 
     1886        this signature, in network byte order. See RFC 4034 App B. 
     1887 
     1888    @type signers_name: L{Name} 
     1889    @ivar signers_name: Identifies the owner name of the DNSKEY RR that a 
     1890        validator should use to validate this signature. Must not use DNS 
     1891        name compression. 
     1892 
     1893    @type signature: L{Sigstr} 
     1894    @ivar signature: Contains the cryptographic signature that covers the RRSIG 
     1895        RDATA (excluding the Signature field and the RRset specified by the 
     1896        RRSIG owner name, RRSIG class and RRSIG Type Covered fields. 
     1897 
     1898    @type ttl: C{int} 
     1899    @ivar ttl: The maximum number of seconds which this record should be 
     1900        cached. 
     1901         
     1902    @since: 12.1 
     1903    """ 
     1904    implements(IEncodable, IRecord) 
     1905    TYPE = RRSIG 
     1906    fmt = '!HBBIIIH' 
     1907 
     1908    fancybasename = 'RRSIG' 
     1909    showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 
     1910                         ('_sig_expiration', 'sig_expiration', '%s'), 
     1911                         ('_sig_inception', 'sig_inception', '%s'), 
     1912                         'key_tag', 
     1913                         ('signers_name', 'signers_name', '%s'), 
     1914                         ('_signature', 'signature', '%s'), 'ttl') 
     1915    compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 
     1916                         'sig_expiration', 'sig_inception', 'key_tag', 
     1917                         'signers_name', 'signature', 'ttl') 
     1918 
     1919    _sig_expiration = property(lambda self: str(self.sig_expiration)) 
     1920    _sig_inception = property(lambda self: str(self.sig_inception)) 
     1921    _signature = property(lambda self: self.signature.string) 
     1922 
     1923 
     1924    def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0, 
     1925                 sig_expiration='', sig_inception='', key_tag=0, 
     1926                 signers_name='', signature='', ttl=None): 
     1927        self.type_covered = type_covered 
     1928        self.algo = algo 
     1929        self.labels = labels 
     1930        self.original_ttl = original_ttl 
     1931        self.sig_expiration = DateSNA(sig_expiration) 
     1932        self.sig_inception = DateSNA(sig_inception) 
     1933        self.key_tag = key_tag 
     1934        self.signers_name = Name(signers_name) 
     1935        self.signature = Sigstr(signature) 
     1936        self.ttl = str2time(ttl) 
     1937 
     1938 
     1939    def encode(self, strio, compDict = None): 
     1940        strio.write(struct.pack(self.fmt, 
     1941                                self.type_covered, 
     1942                                self.algo, 
     1943                                self.labels, 
     1944                                self.original_ttl, 
     1945                                self.sig_expiration.asInt(), 
     1946                                self.sig_inception.asInt(), 
     1947                                self.key_tag)) 
     1948        self.signers_name.encode(strio, None) 
     1949        self.signature.encode(strio, compDict) 
     1950 
     1951 
     1952    def decode(self, strio, length=None): 
     1953        start = strio.tell() 
     1954        l = struct.calcsize(self.fmt) 
     1955        buff = readPrecisely(strio, l) 
     1956        r = struct.unpack(self.fmt, buff) 
     1957        self.type_covered, self.algo, self.labels, self.original_ttl, \ 
     1958            sig_expiration, sig_inception, self.key_tag = r 
     1959        self.sig_expiration = DateSNA.fromInt(sig_expiration) 
     1960        self.sig_inception = DateSNA.fromInt(sig_inception) 
     1961        self.signers_name.decode(strio) 
     1962        here = strio.tell() 
     1963        self.signature.decode(strio, length + start - here if length else None) 
     1964 
     1965 
     1966    def __hash__(self): 
     1967        return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 
     1968                     self.sig_expiration, self.sig_inception, self.key_tag, 
     1969                     self.signers_name, self.signature)) 
     1970 
     1971 
     1972 
     1973class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1974    """ 
     1975    A DNSSEC DS record. 
     1976 
     1977    @type key_tag: C{int} 
     1978    @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS 
     1979        record. 
     1980 
     1981    @type algo: C{int} 
     1982    @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this 
     1983        DS record. 
     1984 
     1985    @type digest_type: C{int} 
     1986    @ivar digest_type: Identifies the algorithm used to construct the digest 
     1987        field. 
     1988 
     1989    @type digest: L{Sigstr} 
     1990    @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by 
     1991        the algorithm identified by the digest_type field. 
     1992 
     1993    @type ttl: C{int} 
     1994    @ivar ttl: The maximum number of seconds which this record should be 
     1995        cached. 
     1996         
     1997    @since: 12.1 
     1998    """ 
     1999    implements(IEncodable, IRecord) 
     2000    TYPE = DS 
     2001    fmt = '!HBB' 
     2002 
     2003    fancybasename = 'DS' 
     2004    showAttributes = ('key_tag', 'algo', 'digest_type', 
     2005                      ('_digest', 'digest', '%s'), 'ttl') 
     2006    compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 
     2007 
     2008    _digest = property(lambda self: self.digest.string) 
     2009 
     2010 
     2011    def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 
     2012        self.key_tag = key_tag 
     2013        self.algo = algo 
     2014        self.digest_type = digest_type 
     2015        self.digest = Sigstr(digest) 
     2016        self.ttl = str2time(ttl) 
     2017 
     2018 
     2019    def encode(self, strio, compDict = None): 
     2020        strio.write(struct.pack(self.fmt, 
     2021                                self.key_tag, 
     2022                                self.algo, 
     2023                                self.digest_type)) 
     2024        self.digest.encode(strio, None) 
     2025 
     2026 
     2027    def decode(self, strio, length=None): 
     2028        start = strio.tell() 
     2029        l = struct.calcsize(self.fmt) 
     2030        buff = readPrecisely(strio, l) 
     2031        r = struct.unpack(self.fmt, buff) 
     2032        self.key_tag, self.algo, self.digest_type = r 
     2033        here = strio.tell() 
     2034        self.digest.decode(strio, length + start - here if length else None) 
     2035 
     2036 
     2037    def __hash__(self): 
     2038        return hash((self.key_tag, self.algo, self.digest_type, self.digest)) 
     2039 
     2040 
     2041 
     2042class Record_DNSKEY(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2043    """ 
     2044    A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 
     2045 
     2046    @type flags: C{int} 
     2047    @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 
     2048        DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 
     2049        the name of a zone.  If bit 7 has value 0, then the DNSKEY record 
     2050        holds some other type of DNS public key and MUST NOT be used to 
     2051        verify RRSIGs that cover RRsets. 
     2052        Bit 15 is the Secure Entry Point flag. See RFC 3757.) 
     2053        All other bits are reserved and must be zero. 
     2054 
     2055    @type protocol: C{int} 
     2056    @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 
     2057        if this field does not contain 3. 
     2058 
     2059    @type algo: C{int} 
     2060    @ivar algo: Identifies the public key's cryptographic algorithm and 
     2061        determines the format of the pub_key field.  See RFC 4034 App A. 
     2062 
     2063    @type pub_key: L{Sigstr} 
     2064    @ivar pub_key: Holds the public key material. 
     2065 
     2066    @type ttl: C{int} 
     2067    @ivar ttl: The maximum number of seconds which this record should be 
     2068        cached. 
     2069         
     2070    @since: 12.1 
     2071    """ 
     2072    implements(IEncodable, IRecord) 
     2073    TYPE = DNSKEY 
     2074    fmt = '!HBB' 
     2075 
     2076    fancybasename = 'DNSKEY' 
     2077    showAttributes = ('flags', 'protocol', 'algo', 
     2078                      ('_pub_key', 'pub_key', '%s'), 'ttl') 
     2079    compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 
     2080 
     2081    _pub_key = property(lambda self: self.pub_key.string) 
     2082 
     2083 
     2084    def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 
     2085        self.flags = flags 
     2086        self.protocol = protocol 
     2087        self.algo = algo 
     2088        self.pub_key = Sigstr(pub_key) 
     2089        self.ttl = str2time(ttl) 
     2090 
     2091 
     2092    def encode(self, strio, compDict = None): 
     2093        strio.write(struct.pack(self.fmt, 
     2094                                self.flags, 
     2095                                self.protocol, 
     2096                                self.algo)) 
     2097        self.pub_key.encode(strio, None) 
     2098 
     2099 
     2100    def decode(self, strio, length=None): 
     2101        start = strio.tell() 
     2102        l = struct.calcsize(self.fmt) 
     2103        buff = readPrecisely(strio, l) 
     2104        r = struct.unpack(self.fmt, buff) 
     2105        self.flags, self.protocol, self.algo = r 
     2106        here = strio.tell() 
     2107        self.pub_key.decode(strio, length + start - here if length else None) 
     2108 
     2109 
     2110    def __hash__(self): 
     2111        return hash((self.flags, self.protocol, self.algo, self.pub_key)) 
     2112 
     2113 
     2114 
     2115class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2116    """ 
     2117    A DNSSEC NSEC record provides authenticated denial of existance for DNS 
     2118    data. 
     2119 
     2120    A DNSSEC NSEC record lists: 
     2121 
     2122        1) the next owner name in canonical ordering of the zone that contains 
     2123           authoritative data or a delegation point NS RRset. 
     2124 
     2125        2) the set of RR types present at the NSEC RR's owner name. 
     2126 
     2127    @type nxt_name: L{Name} 
     2128    @ivar nxt_name: The next owner name that has authoritative data or contains 
     2129        a delegation point NS RRset. 
     2130 
     2131    @type type_bitmaps: L{TypeBitmaps} 
     2132    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's 
     2133        owner name. 
     2134 
     2135    @type ttl: C{int} 
     2136    @ivar ttl: The maximum number of seconds which this record should be 
     2137        cached. 
     2138         
     2139    @since: 12.1 
     2140    """ 
     2141    implements(IEncodable, IRecord) 
     2142    TYPE = NSEC 
     2143 
     2144    fancybasename = 'NSEC' 
     2145    showAttributes = (('nxt_name', 'nxt_name', '%s'), 
     2146                      ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2147    compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 
     2148 
     2149    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2150 
     2151 
     2152    def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 
     2153        self.nxt_name = Name(nxt_name) 
     2154        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2155        self.ttl = str2time(ttl) 
     2156 
     2157 
     2158    def encode(self, strio, compDict = None): 
     2159        self.nxt_name.encode(strio, None) 
     2160        self.type_bitmaps.encode(strio, None) 
     2161 
     2162 
     2163    def decode(self, strio, length=None): 
     2164        start = strio.tell() 
     2165        self.nxt_name.decode(strio, None) 
     2166        here = strio.tell() 
     2167        self.type_bitmaps.decode(strio, length + start - here if length 
     2168                                 else None) 
     2169 
     2170 
     2171    def __hash__(self): 
     2172        return hash((self.nxt_name, self.type_bitmaps)) 
     2173 
     2174 
     2175 
     2176class Record_NSEC3PARAM(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2177    """ 
     2178    A DNSSEC NSEC3PARAM record contains the NSEC3 parameters (hash algorithm, 
     2179    flags, iterations and salt) needed by authoritative servers to calculate 
     2180    hashed owner names.  The presence of an NSEC3PARAM RR at a zone apex 
     2181    indicates that the specified parameters may be used by authoritative 
     2182    servers to choose an appropriate set of NSEC3 RRs for negative responses. 
     2183 
     2184    @type hash_algo: C{int} 
     2185    @ivar hash_algo: Identifies the cryptographic hash algorithm used to 
     2186        construct the hash value. 
     2187 
     2188    @type flags: C{int} 
     2189    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is 
     2190        the opt-out flag. If the opt-out flag is set, the NSEC3 record covers 
     2191        zero or more unsigned delegations. If the opt-out flag is clear, the 
     2192        NSEC3 record covers zero unsigned delegations. 
     2193 
     2194    @type iterations: C{int} 
     2195    @ivar iterations: Defines the nubmer of additional times the hash algorithm 
     2196        has been performed. 
     2197 
     2198    @type salt: L{Charset} 
     2199    @ivar salt: Identifies the salt value provided to the hash. 
     2200 
     2201    @type ttl: C{int} 
     2202    @ivar ttl: The maximum number of seconds which this record should be 
     2203        cached. 
     2204         
     2205    @since: 12.1 
     2206    """ 
     2207    implements(IEncodable, IRecord) 
     2208    TYPE = NSEC3 
     2209    fmt = '!BBH' 
     2210 
     2211    fancybasename = 'NSEC3' 
     2212    showAttributes = ('hash_algo', 'flags', 'iterations', 
     2213                      ('_salt', 'salt', '%s'), 'ttl') 
     2214    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'ttl') 
     2215 
     2216    _salt = property(lambda self: self.salt.string) 
     2217 
     2218 
     2219    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', ttl=None): 
     2220        self.hash_algo = hash_algo 
     2221        self.flags = flags 
     2222        self.iterations = iterations 
     2223        self.salt = Charstr(salt) 
     2224        self.ttl = str2time(ttl) 
     2225 
     2226 
     2227    def encode(self, strio, compDict = None): 
     2228        strio.write(struct.pack(self.fmt, 
     2229                                self.hash_algo, 
     2230                                self.flags, 
     2231                                self.iterations)) 
     2232        self.salt.encode(strio, None) 
     2233 
     2234 
     2235    def decode(self, strio, length=None): 
     2236        start = strio.tell() 
     2237        l = struct.calcsize(self.fmt) 
     2238        buff = readPrecisely(strio, l) 
     2239        r = struct.unpack(self.fmt, buff) 
     2240        self.hash_algo, self.flags, self.iterations = r 
     2241        self.salt.decode(strio) 
     2242        here = strio.tell() 
     2243 
     2244 
     2245    def __hash__(self): 
     2246        return hash((self.hash_algo, self.flags, self.iterations, self.salt)) 
     2247 
     2248 
     2249 
     2250class Record_NSEC3(Record_NSEC3PARAM): 
     2251    """ 
     2252    A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of 
     2253    existence for DNS data and permits a gradual expansion of delegation-centric 
     2254    zones. 
     2255 
     2256    A DNSSEC NSEC3 record lists: 
     2257 
     2258        1) the set of RR types present at the original owner name of the NSEC 
     2259           RR. 
     2260 
     2261        2) the next hashed owner name in the hash order of the zone. 
     2262 
     2263    @type hash_algo: C{int} 
     2264    @ivar hash_algo: Identifies the cryptographic hash algorithm used to 
     2265        construct the hash value. 
     2266 
     2267    @type flags: C{int} 
     2268    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined 
     2269        is the opt-out flag. If the opt-out flag is set, the NSEC3 record 
     2270        covers zero or more unsigned delegations. If the opt-out flag is 
     2271        clear, the NSEC3 record covers zero unsigned delegations. 
     2272 
     2273    @type iterations: C{int} 
     2274    @ivar iterations: Defines the nubmer of additional times the hash algorithm 
     2275        has been performed. 
     2276 
     2277    @type salt: L{Charset} 
     2278    @ivar salt: Identifies the salt value provided to the hash. 
     2279 
     2280    @type nxt_hash_owner_name: L{Charset} 
     2281    @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone 
     2282        in hash order. 
     2283 
     2284    @type type_bitmaps: L{TypeBitmaps} 
     2285    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's 
     2286        original owner name. 
     2287 
     2288    @type ttl: C{int} 
     2289    @ivar ttl: The maximum number of seconds which this record should be 
     2290        cached. 
     2291         
     2292    @since: 12.1 
     2293    """ 
     2294    implements(IEncodable, IRecord) 
     2295    TYPE = NSEC3 
     2296    fmt = '!BBH' 
     2297 
     2298    fancybasename = 'NSEC3' 
     2299    showAttributes = ('hash_algo', 'flags', 'iterations', 
     2300                      ('_salt', 'salt', '%s'), 
     2301                      ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), 
     2302                      ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2303    compareAttributes = ('hash_algo', 'flags', 'iterations', 
     2304                         'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 
     2305 
     2306    _salt = property(lambda self: self.salt.string) 
     2307    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2308 
     2309 
     2310    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', 
     2311                 nxt_hash_owner='', type_bitmaps=None, ttl=None): 
     2312        Record_NSEC3PARAM.__init__(self, hash_algo, flags, 
     2313                                   iterations, salt, ttl) 
     2314        self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 
     2315        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2316 
     2317 
     2318    def encode(self, strio, compDict = None): 
     2319        Record_NSEC3PARAM.encode(self, strio, compDict) 
     2320        self.nxt_hash_owner_name.encode(strio, None) 
     2321        self.type_bitmaps.encode(strio, None) 
     2322 
     2323 
     2324    def decode(self, strio, length=None): 
     2325        start = strio.tell() 
     2326        Record_NSEC3PARAM.decode(self, strio, compDict) 
     2327        self.nxt_hash_owner_name.decode(strio) 
     2328        here = strio.tell() 
     2329        self.type_bitmaps.decode(strio, length + start - here if length 
     2330                                 else None) 
     2331 
     2332 
     2333    def __hash__(self): 
     2334        return hash((self.hash_algo, self.flags, self.iterations, self.salt, 
     2335                     self.nxt_hash_owner_name, self.type_bitmaps)) 
     2336 
     2337 
     2338 
    14672339# This is a fallback record 
    14682340class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 
    14692341    """ 
     
    14842356    compareAttributes = ('data', 'ttl') 
    14852357    showAttributes = ('data', 'ttl') 
    14862358 
     2359 
    14872360    def __init__(self, data='', ttl=None): 
    14882361        self.data = data 
    14892362        self.ttl = str2time(ttl) 
     
    15402413    queries = answers = add = ns = None 
    15412414 
    15422415    def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 
    1543                        auth=0, rCode=OK, trunc=0, maxSize=512): 
     2416                 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 
    15442417        self.maxSize = maxSize 
    15452418        self.id = id 
    15462419        self.answer = answer 
    15472420        self.opCode = opCode 
    1548         self.auth = auth 
    1549         self.trunc = trunc 
    1550         self.recDes = recDes 
    1551         self.recAv = recAv 
     2421        self.auth = auth            # AA - Authoritative Answer 
     2422        self.trunc = trunc          # TC - TrunCated 
     2423        self.recDes = recDes        # RD - Recursion Desired 
     2424        self.recAv = recAv          # RA - Recursion Available 
     2425        self.authData = authData    # AD - Authentic Data 
     2426        self.chkDis = chkDis        # CD - Checking Disabled 
    15522427        self.rCode = rCode 
    15532428        self.queries = [] 
    15542429        self.answers = [] 
     
    15882463        if self.maxSize and size > self.maxSize: 
    15892464            self.trunc = 1 
    15902465            body = body[:self.maxSize - self.headerSize] 
    1591         byte3 = (( ( self.answer & 1 ) << 7 ) 
    1592                  | ((self.opCode & 0xf ) << 3 ) 
    1593                  | ((self.auth & 1 ) << 2 ) 
    1594                  | ((self.trunc & 1 ) << 1 ) 
    1595                  | ( self.recDes & 1 ) ) 
    1596         byte4 = ( ( (self.recAv & 1 ) << 7 ) 
    1597                   | (self.rCode & 0xf ) ) 
     2466        byte3 = (((self.answer & 1) << 7) 
     2467                 | ((self.opCode & 0xf) << 3) 
     2468                 | ((self.auth & 1 ) << 2) 
     2469                 | ((self.trunc & 1 ) << 1) 
     2470                 | (self.recDes & 1)) 
     2471        byte4 = (((self.recAv & 1) << 7) 
     2472                 | ((self.authData & 1) << 5) 
     2473                 | ((self.chkDis & 1) << 4) 
     2474                 | (self.rCode & 0xf)) 
    15982475 
    15992476        strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, 
    16002477                                len(self.queries), len(self.answers), 
     
    16072484        header = readPrecisely(strio, self.headerSize) 
    16082485        r = struct.unpack(self.headerFmt, header) 
    16092486        self.id, byte3, byte4, nqueries, nans, nns, nadd = r 
    1610         self.answer = ( byte3 >> 7 ) & 1 
    1611         self.opCode = ( byte3 >> 3 ) & 0xf 
    1612         self.auth = ( byte3 >> 2 ) & 1 
    1613         self.trunc = ( byte3 >> 1 ) & 1 
     2487        self.answer = (byte3 >> 7) & 1 
     2488        self.opCode = (byte3 >> 3) & 0xf 
     2489        self.auth = (byte3 >> 2) & 1 
     2490        self.trunc = (byte3 >> 1) & 1 
    16142491        self.recDes = byte3 & 1 
    1615         self.recAv = ( byte4 >> 7 ) & 1 
     2492        self.recAv = (byte4 >> 7) & 1 
     2493        self.authData = (byte4 >> 5) & 1 
     2494        self.chkDis = (byte4 >> 4) & 1 
    16162495        self.rCode = byte4 & 0xf 
    16172496 
    16182497        self.queries = [] 
     
    16242503                return 
    16252504            self.queries.append(q) 
    16262505 
    1627         items = ((self.answers, nans), (self.authority, nns), (self.additional, nadd)) 
     2506        items = ((self.answers, nans), 
     2507                 (self.authority, nns), 
     2508                 (self.additional, nadd)) 
    16282509        for (l, n) in items: 
    16292510            self.parseRecords(l, n, strio) 
    16302511 
    16312512 
    16322513    def parseRecords(self, list, num, strio): 
    16332514        for i in range(num): 
    1634             header = RRHeader(auth=self.auth) 
    16352515            try: 
    1636                 header.decode(strio) 
     2516                header = OPTHeader._headerFactory(strio, auth=self.auth) 
    16372517            except EOFError: 
    16382518                return 
    16392519            t = self.lookupRecordType(header.type) 
     
    17432623            query, or errbacked with any errors that could happen (exceptions 
    17442624            during writing of the query, timeout errors, ...). 
    17452625        """ 
    1746         m = Message(id, recDes=1) 
     2626        dnssecConfig = self.controller.dnssecConfig 
     2627        chkDis = dnssecConfig.chkDis 
     2628        m = Message(id, recDes=dnssecConfig.recDes, chkDis=chkDis) 
    17472629        m.queries = queries 
     2630        if dnssecConfig.ednsEnabled: 
     2631            m.additional = [Record_OPT(payload_size = dnssecConfig.maxUdpPktSz, 
     2632                                       version = dnssecConfig.version, 
     2633                                       dnssecOk = dnssecConfig.dnssecOk)] 
    17482634 
    17492635        try: 
    17502636            writeMessage(m) 
     
    17982684        self.transport.write(message.toStr(), address) 
    17992685 
    18002686    def startListening(self): 
    1801         self._reactor.listenUDP(0, self, maxPacketSize=512) 
     2687        maxPacketSize = 512 
     2688        if self.controller.dnssecConfig.ednsEnabled: 
     2689            maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 
     2690        self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 
    18022691 
    18032692    def datagramReceived(self, data, addr): 
    18042693        """ 
  • twisted/names/secondary.py

     
    9090 
    9191    @ivar _reactor: The reactor to use to perform the zone transfers, or C{None} 
    9292        to use the global reactor. 
     93 
     94    @ivar dnssecConfig: a L{DnssecConfig} giving the DNSSEC configuration to set 
     95        on the resolver. 
    9396    """ 
    9497 
    9598    transferring = False 
     
    97100    _port = 53 
    98101    _reactor = None 
    99102 
    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) 
    102105        self.primary = primaryIP 
    103106        self.domain = domain 
    104107 
     
    150153 
    151154        return FileAuthority.__dict__['_lookup'](self, name, cls, type, timeout) 
    152155 
    153     #shouldn't we just subclass? :P 
     156    # shouldn't we just subclass? :P 
    154157 
    155158    lookupZone = FileAuthority.__dict__['lookupZone'] 
    156159 
     
    164167                r.setdefault(str(rec.name).lower(), []).append(rec.payload) 
    165168 
    166169    def _ebZone(self, failure): 
    167         log.msg("Updating %s from %s failed during zone transfer" % (self.domain, self.primary)) 
     170        log.msg("Updating %s from %s failed during zone transfer" 
     171                % (self.domain, self.primary)) 
    168172        log.err(failure) 
    169173 
    170174    def update(self): 
     
    175179 
    176180    def _ebTransferred(self, failure): 
    177181        self.transferred = False 
    178         log.msg("Transferring %s from %s failed after zone transfer" % (self.domain, self.primary)) 
     182        log.msg("Transferring %s from %s failed after zone transfer" 
     183                % (self.domain, self.primary)) 
    179184        log.err(failure) 
  • 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""" 
     6Serial Number Arithmetic 
     7 
     8This module implements RFC 1982 DNS Serial Number Arithmetic 
     9(see http://tools.ietf.org/pdf/rfc1982.pdf). 
     10SNA is used in DNS and specifically in DNSSEC as defined in 
     11RFC 4034 in the DNSSEC Signature Expiration and Inception Fields. 
     12 
     13@author: Bob Novas 
     14 
     15@since: 12.1 
     16""" 
     17 
     18import calendar, time 
     19 
     20 
     21 
     22class SNA(object): 
     23    """ 
     24    implements RFC 1982 - DNS Serial Number Arithmetic 
     25    """ 
     26    SERIAL_BITS = 32 
     27    MODULOVAL = 2**SERIAL_BITS 
     28    HLFRNG = 2**(SERIAL_BITS-1) 
     29    MAXADD = (2**(SERIAL_BITS-1)-1) 
     30 
     31 
     32    def __init__(self, number): 
     33        self._number = int(number)%self.MODULOVAL 
     34 
     35 
     36    def __repr__(self): 
     37        return str(self._number) 
     38 
     39 
     40    def asInt(self): 
     41        """ 
     42        return an integer representing the object 
     43        """ 
     44        return self._number 
     45 
     46 
     47    def __eq__(self, sna2): 
     48        """ 
     49        define the equality operator 
     50        """ 
     51        return sna2._number == self._number 
     52 
     53 
     54    def __lt__(self, sna2): 
     55        """ 
     56        define the less than operator 
     57        """ 
     58        return ((self != sna2) and 
     59               ((self._number < sna2._number) and 
     60                ((sna2._number - self._number) < self.HLFRNG) or 
     61               (self._number > sna2._number) and 
     62                ((self._number - sna2._number) > self.HLFRNG))) 
     63 
     64 
     65    def __gt__(self, sna2): 
     66        """ 
     67        define the greater than operator 
     68        """ 
     69        return ((self != sna2) and 
     70               ((self._number < sna2._number) and 
     71               ((sna2._number - self._number) > self.HLFRNG) or 
     72               (self._number > sna2._number) and 
     73               ((self._number - sna2._number) < self.HLFRNG))) 
     74 
     75 
     76    def __le__(self, sna2): 
     77        """ 
     78        define the less than or equal operator 
     79        """ 
     80        return self == sna2 or self < sna2 
     81 
     82 
     83    def __ge__(self, sna2): 
     84        """ 
     85        define the greater than or equal operator 
     86        """ 
     87        return self == sna2 or self > sna2 
     88 
     89 
     90    def __add__(self, sna2): 
     91        """ 
     92        define the addition operator 
     93        """ 
     94        if sna2 <= SNA(self.MAXADD): 
     95            return SNA( (self._number + sna2._number)%self.MODULOVAL ) 
     96        else: 
     97            raise ArithmeticError 
     98 
     99 
     100    def __hash__(self): 
     101        """ 
     102        define a hash function 
     103        """ 
     104        return hash(self._number) 
     105 
     106 
     107 
     108def max(snaList): 
     109    """ 
     110    takes a list of sna's from which it will pick the one 
     111    with the highest value 
     112    """ 
     113    if len(snaList) == 0: 
     114        return None 
     115    trialMax = snaList[0] 
     116    for s in snaList[1:]: 
     117        if not trialMax: 
     118            trialMax = s 
     119        elif s and s > trialMax: 
     120            trialMax = s 
     121    return trialMax 
     122 
     123 
     124 
     125class DateSNA(SNA): 
     126    """ 
     127    implements DNS Serial Number Arithmetic 
     128    for dates 'YYYYMMDDHHMMSS' per RFC 4034 P3.1.5 
     129    """ 
     130    fmt = '%Y%m%d%H%M%S' 
     131 
     132 
     133    def __init__(self, utcDateTime=''): 
     134        """ 
     135        accept a UTC date/time string as YYMMDDHHMMSS 
     136        and convert it to seconds since the epoch 
     137        """ 
     138        if not utcDateTime: 
     139            utcDateTime = '19700101000000' 
     140        dtstruct = time.strptime(utcDateTime, DateSNA.fmt) 
     141        secondsSinceE = calendar.timegm(dtstruct) 
     142        super(DateSNA, self).__init__(secondsSinceE) 
     143 
     144 
     145    def __add__(self, sna2): 
     146        """ 
     147        define the addition operator 
     148        """ 
     149        if not isinstance(sna2, SNA): 
     150            return NotImplemented 
     151 
     152        if (sna2 <= SNA(self.MAXADD) and 
     153            (self._number + sna2._number < self.MODULOVAL)): 
     154            sna = SNA((self._number + sna2._number)%self.MODULOVAL) 
     155            return DateSNA.fromSNA(sna) 
     156        else: 
     157            raise ArithmeticError 
     158 
     159 
     160    def asDate(self): 
     161        """return a representation of the object as a date string""" 
     162        dtstruct = time.gmtime(self._number) 
     163        return time.strftime(DateSNA.fmt, dtstruct) 
     164 
     165 
     166    @classmethod 
     167    def fromSNA(cls, sna): 
     168        """ 
     169        create an DateSNA object from an SNA 
     170        """ 
     171        d = cls() 
     172        d._number = sna._number 
     173        return d 
     174 
     175 
     176    @classmethod 
     177    def fromInt(cls, i): 
     178        """ 
     179        create an DateSNA object from an int 
     180        """ 
     181        return cls.fromSNA(SNA(i)) 
     182 
     183 
     184    def __str__(self): 
     185        """ 
     186        return a string representation of the object 
     187        """ 
     188        return self.asDate() 
     189 
  • twisted/names/test/test_client.py

     
    88from twisted.names import client, dns 
    99from twisted.names.error import DNSQueryTimeoutError 
    1010from twisted.trial import unittest 
    11 from twisted.names.common import ResolverBase 
     11from twisted.names.common import ResolverBase, DnssecConfig 
     12from twisted.names.dns import Query, Message 
    1213from twisted.internet import defer, error 
    1314from twisted.python import failure 
    1415from twisted.python.deprecate import getWarningMethod, setWarningMethod 
    1516from twisted.python.compat import set 
     17from twisted.names.test.test_rootresolve import MemoryReactor 
    1618 
    1719 
    1820class FakeResolver(ResolverBase): 
     
    430432        self.assertNotIn(protocol, resolver.connections) 
    431433 
    432434 
     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). 
    433440 
     441        In addition, check that the message flag bits (DO, CD, RC) agree 
     442        with the flags set in the resolver. 
     443         
     444        @since: 12.1 
     445        """ 
     446        # make sure EDNS is enabled 
     447        self.assertTrue(resolver.dnssecConfig.ednsEnabled) 
     448 
     449        d = resolver._query(('example.com', 53), 
     450                            [Query('foo.example.com',dns.A, dns.IN)], 
     451                            30) 
     452 
     453        # A UDP port should have been started 
     454        portNumber, transport = reactor.udpPorts.popitem() 
     455 
     456        # and a DNS packet sent 
     457        [(packet, address)] = transport._sentPackets 
     458 
     459        msg = Message() 
     460        msg.fromStr(packet) 
     461 
     462        # the query should have an additional OPT Header with 
     463        # version == 0 and payload_size as defined by the resolver's 
     464        # dnssecConfig and DO should be set 
     465        self.assertEqual(len(msg.additional), 1) 
     466        additional = msg.additional[0] 
     467        payload = additional.payload 
     468        dnssecConfig = resolver.dnssecConfig 
     469        self.assertEqual(additional.type, dns.OPT) 
     470        self.assertEqual(payload.version, dnssecConfig.version) 
     471        self.assertEqual(payload.payload_size, dnssecConfig.maxUdpPktSz) 
     472        # payload.flags bit 15 is DO, should equal resolver.dnssecOk 
     473        self.assertEqual(not not(payload.flags & 0x8000), dnssecConfig.dnssecOk) 
     474 
     475        # the rest of the query should be as above also 
     476        self.assertEqual(msg.queries, [Query('foo.example.com', dns.A, dns.IN)]) 
     477        self.assertEqual(msg.answers, []) 
     478        self.assertEqual(msg.authority, []) 
     479 
     480        # the message header flags should be set as per the resolver's 
     481        # dnssecConfig settings 
     482        self.assertEqual(msg.chkDis, dnssecConfig.chkDis) 
     483        self.assertEqual(msg.recDes, dnssecConfig.recDes) 
     484 
     485        response = [] 
     486        d.addCallback(response.append) 
     487        self.assertEqual(response, []) 
     488 
     489        # Once a reply is received, the Deferred should fire. 
     490        # Make the flag bits in the message agree with what you asked for 
     491        del msg.queries[:] 
     492        msg.answer = 1 
     493        msg.answers.append(dns.RRHeader('foo.example.com', 
     494                                        payload=dns.Record_A('5.8.13.21'))) 
     495        # if you requested DO, say you got AD 
     496        msg.authData = dnssecConfig.dnssecOk 
     497        msg.chkDis = dnssecConfig.chkDis 
     498        msg.recDes = dnssecConfig.recDes 
     499        transport._protocol.datagramReceived(msg.toStr(), ('1.1.2.4', 1053)) 
     500        return response[0] 
     501 
     502 
     503    def test_dnssecEnabled(self): 
     504        """ 
     505        A query sent with DNSSEC Enabled has an additional OPT record with 
     506        DO set. Such a query returns a 4-tuple as a result, with the 4th 
     507        member of the tuple being the message with the header bits set as 
     508        set in the original query. 
     509         
     510        @since: 12.1 
     511        """ 
     512        # Create a resolver with EDNS0, max packet size = 4096, 
     513        # and dnssecOk, chkDis and recDes = True 
     514        maxPacketSize = 4096 
     515        dsc = DnssecConfig(ednsEnabled=True, 
     516                           maxUdpPktSz=maxPacketSize, 
     517                           dnssecOk=True,  # DO 
     518                           chkDis=True,    # CD 
     519                           recDes=True)    # RC 
     520 
     521        reactor = MemoryReactor() 
     522        resolver = client.Resolver(servers=[('example.com', 53)], 
     523                                   reactor=reactor, 
     524                                   dnssecConfig=dsc) 
     525 
     526        message = self._edns0ConfigurationTest(reactor, resolver) 
     527 
     528        # check that a resolver with dnssecOk returns a 4-tuple with the 
     529        # header set as in the query 
     530        answer, authority, additional, message = resolver.filterAnswers(message) 
     531        self.assertEqual(answer, [dns.RRHeader('foo.example.com', 
     532                                  payload=dns.Record_A('5.8.13.21', ttl=0))]) 
     533        self.assertEqual(authority, []) 
     534        self.assertEqual(additional, []) 
     535        self.assertIsInstance(message, dns.Message) 
     536        self.assertTrue(message.authData) 
     537        self.assertTrue(message.chkDis) 
     538        self.assertTrue(message.recDes) 
     539 
     540 
     541    def test_dnssecDisabled(self): 
     542        """ 
     543        A query sent with DNSSEC Disabled but EDNS enabled has an additional 
     544        OPT record with DO clear. Such a query returns a 3-tuple as a result. 
     545        """ 
     546 
     547        # Create a resolver with EDNS0, max packet size = 4096, 
     548        # and dnssecOk = False, but recDes = True 
     549        maxPacketSize = 4096 
     550        dsc = DnssecConfig(ednsEnabled=True, 
     551                           maxUdpPktSz=maxPacketSize, 
     552                           dnssecOk=False, # not DO 
     553                           recDes=True)    # RC 
     554 
     555        reactor = MemoryReactor() 
     556        resolver = client.Resolver(servers=[('example.com', 53)], 
     557                                   reactor=reactor, 
     558                                   dnssecConfig=dsc) 
     559 
     560        message = self._edns0ConfigurationTest(reactor, resolver) 
     561 
     562        # check that a resolver with dnssecOk == False returns a 3-tuple 
     563        # containing the right stuff. 
     564        # Note - no access to header info in this case 
     565        answer, authority, additional = resolver.filterAnswers(message) 
     566        self.assertEqual(answer, 
     567                         [dns.RRHeader('foo.example.com', 
     568                                    payload=dns.Record_A('5.8.13.21', ttl=0))]) 
     569        self.assertEqual(authority, []) 
     570        self.assertEqual(additional, []) 
     571 
     572 
    434573class ClientTestCase(unittest.TestCase): 
    435574 
    436575    def setUp(self): 
     
    658797        return d 
    659798 
    660799 
     800    def test_lookupDNSKey(self): 
     801        """ 
     802        See L{test_lookupAddress} 
     803        """ 
     804        d = client.lookupDNSKey(self.hostname) 
     805        d.addCallback(self.checkResult, dns.DNSKEY) 
     806        return d 
     807 
     808 
     809    def test_lookupDS(self): 
     810        """ 
     811        See L{test_lookupAddress} 
     812         
     813        @since: 12.1 
     814        """ 
     815        d = client.lookupDS(self.hostname) 
     816        d.addCallback(self.checkResult, dns.DS) 
     817        return d 
     818 
     819 
     820    def test_lookupNSEC(self): 
     821        """ 
     822        See L{test_lookupAddress} 
     823         
     824        @since: 12.1 
     825        """ 
     826        d = client.lookupNSEC(self.hostname) 
     827        d.addCallback(self.checkResult, dns.NSEC) 
     828        return d 
     829 
     830 
     831    def test_lookupNSEC3(self): 
     832        """ 
     833        See L{test_lookupAddress} 
     834         
     835        @since: 12.1 
     836        """ 
     837        d = client.lookupNSEC3(self.hostname) 
     838        d.addCallback(self.checkResult, dns.NSEC3) 
     839        return d 
     840 
     841 
     842    def test_lookupNSEC3Param(self): 
     843        """ 
     844        See L{test_lookupAddress} 
     845         
     846        @since: 12.1 
     847        """ 
     848        d = client.lookupNSEC3Param(self.hostname) 
     849        d.addCallback(self.checkResult, dns.NSEC3PARAM) 
     850        return d 
     851 
     852 
     853    def test_lookupRRSIG(self): 
     854        """ 
     855        See L{test_lookupAddress} 
     856         
     857        @since: 12.1 
     858        """ 
     859        d = client.lookupRRSIG(self.hostname) 
     860        d.addCallback(self.checkResult, dns.RRSIG) 
     861        return d 
     862 
     863 
    661864class ThreadedResolverTests(unittest.TestCase): 
    662865    """ 
    663866    Tests for L{client.ThreadedResolver}. 
  • twisted/names/test/test_dns.py

     
    88 
    99from cStringIO import StringIO 
    1010 
     11import re 
    1112import struct 
    1213 
    1314from twisted.python.failure import Failure 
    1415from twisted.internet import address, task 
    1516from twisted.internet.error import CannotListenError, ConnectionDone 
    1617from twisted.trial import unittest 
    17 from twisted.names import dns 
     18from twisted.names import dns, common 
    1819 
    1920from twisted.test import proto_helpers 
    2021 
     
    2526    dns.Record_WKS, dns.Record_SRV, dns.Record_AFSDB, dns.Record_RP, 
    2627    dns.Record_HINFO, dns.Record_MINFO, dns.Record_MX, dns.Record_TXT, 
    2728    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, 
    2831    ] 
    2932 
    3033class NameTests(unittest.TestCase): 
     
    189192    """Encoding and then decoding various objects.""" 
    190193 
    191194    names = ["example.org", "go-away.fish.tv", "23strikesback.net"] 
     195    sigs = ["Qm12VZVaZgKS0/DZx35SGECDwPiTTf3ngChb7OkgSv5iupVmJGhPWudm " 
     196            "/18qBSXKyv9hxMlEXFFgpBieNqLfSBkP1bwKnlqPfr1Hx7ctDwDUpkT3 " 
     197            "cS8u/ms9yo3Fu1ybpO4Hfsb1HbA2N3zzQnjWKnyk26AAQSz8KgjNTFzD " 
     198            "tJM=", 
     199            "ZH2kahMD1g2WOieIotAcBwB0e/o30Zq6YR//M/xwP1ktkYuclmcR56iv " 
     200            "XiR3QFWqmN5Xz3YpgmM4tZkjIeSMp2doYa7XYORZ7OpzG7oyfo8IoXxc " 
     201            "j1VGDeAn1CeNCpBtoSGapRABG1gjY7oeRj/smPQPp2Gkf79+WZfuzRom " 
     202            "/t4=", 
     203            "AZpaboyNQAmbnBO1K66QmZ0c+VCdY/wu9QpEdRnMpnIOLPD28pNVu6hk " 
     204            "GQMz6eg5WYkPYDdJK+1D/oyAQkDmRgn10+O9EdeFDyLqYqq/htEAvDm4 " 
     205            "CziMSOpD/mkg1bSWCZ2mdln/GBk8WooCeeM7LEHmRjmHMMj0xb6N4SKa " 
     206            "MEc=", 
     207            "AwEAAbi5VQa3x+R3WQouBDNts+ZX2zIKZNoj9pzl7ew446kI/2omv3j6 " 
     208            "c/4RQ6VneYE3mK7r0fFIKhVagmiRroFO1rRUJ8sVidssZ35CldE0sju+ " 
     209            "E7wymVg3tV+ZUUO/+5v6Sfj+tw3rlp6eKqm7EGKKM88t+KuXiGYMu0Vw " 
     210            "Rm9OUO1n", 
     211            "AwEAAbmTL+kuV45kAxGN//iBKz93Y6lutgxoptp+I1+PZZMsBkhm/dZj " 
     212            "q57040Pz/Hr3f2zQX7z6fFu7/Ml3MHPH1eQDiVXDvOkeNq2x4IbCO7x+ " 
     213            "0p6bGYj4fw/tEfh/8dUzyzvMwfuAMsOvXza8Kh+UP4jvFc95cUuGgYus " 
     214            "uEjUOp40PsL7EtYvAks3UssA6/OZP4w/1Z5m/VFx4PzgY0dkEuc=", 
     215            "VGPxa8A81eV1dtUxVhz9b9Jsp6FF4M5H6J0QhzbNCUTHTHjLNR2VHYfE " 
     216            "fM+Akwo3/qKq3D6vzTfzqtyPAXP8CmGfdD8hfv0s7Hae9c7Is8usdlrk " 
     217            "ZpoXEFMW+YVG8G9OieYViq6tBIpUvKgMVZ+oXKo63KJ/tC/yBW0H0VQP " 
     218            "YwdzZ3ZvYRDmZDvrXoX7T0YNU+0HYHnb7g7nUECIJ/4HHg==", 
     219            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFE " 
     220            "h9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffp " 
     221            "Z9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55 " 
     222            "Y1k="] 
     223    type_bitmaps = ["A MX RRSIG NSEC TYPE1234", 
     224                    "AAAA NS CNAME MX TXT RRSIG NSEC3 DNAME", 
     225                    "NSEC3 A AAAA RRSIG DS NS " 
     226                    "TYPE5000 TYPE1000 TYPE2000 TYPE3000 TYPE4000", 
     227                    None] 
    192228 
    193229    def testName(self): 
    194230        for n in self.names: 
     
    276312            self.assertEqual(result.string, n) 
    277313 
    278314 
     315    def test_Sigstr(self): 
     316        """ 
     317        Test L{dns.Sigstr} encode and decode. 
     318         
     319        @since: 12.1 
     320        """ 
     321        for s in self.sigs: 
     322            # encode the signature/key 
     323            f = StringIO() 
     324            dns.Sigstr(s).encode(f) 
     325            l = f.tell() 
     326 
     327            # decode the signature/key 
     328            f.seek(0, 0) 
     329            result = dns.Sigstr() 
     330            result.decode(f,l) 
     331            # spaces are free, and dig sticks them in 
     332            self.assertEqual(result.string, s.replace(' ', '')) 
     333 
     334 
     335    def test_TypeBitmaps(self): 
     336        """ 
     337        Test L{dns.TypeBitmaps} encode and decode. 
     338         
     339        @since: 12.1 
     340        """ 
     341        typeRegex = re.compile('TYPE(\d+)') 
     342 
     343        for b in self.type_bitmaps: 
     344            # encode the type_bitmaps 
     345            f = StringIO() 
     346            dns.TypeBitmaps(b).encode(f) 
     347            l = f.tell() 
     348 
     349            # decode the type_bitmaps 
     350            f.seek(0, 0) 
     351            result = dns.TypeBitmaps() 
     352            result.decode(f,l) 
     353 
     354            def mnuVal(mnu): 
     355                mnuVal = dns.REV_TYPES.get(mnu, None) 
     356                if not mnuVal: 
     357                    m = typeRegex.match(mnu) 
     358                    if m.groups(): 
     359                        mnuVal = int(m.group(1)) 
     360                        assert mnuVal < 65536 
     361                    else: 
     362                        log.err("can't parse %s in %s" % (mnu, self.string, )) 
     363                        mnuVal = 0 
     364                return mnuVal 
     365 
     366            def sorttok(string): 
     367                if not string: 
     368                    return '' 
     369 
     370                toks = string.split(' ') 
     371                toks.sort(key = mnuVal) 
     372                return ' '.join(toks) 
     373 
     374            self.assertEqual(result.type_bitmaps, sorttok(b)) 
     375 
     376 
    279377    def test_NAPTR(self): 
    280378        """ 
    281379        Test L{dns.Record_NAPTR} encode and decode. 
     
    325423        msg = dns.Message() 
    326424        msg.fromStr( 
    327425            '\x01\x00' # Message ID 
    328             '\x00' # answer bit, opCode nibble, auth bit, trunc bit, recursive bit 
    329             '\x00' # recursion bit, empty bit, empty bit, empty bit, response code nibble 
     426            '\x00' # answer bit, opCode nibble, auth, trunc, recursive bits 
     427            '\x00' # recursion bit, 3 empty bits, response code nibble 
    330428            '\x00\x00' # number of queries 
    331429            '\x00\x00' # number of answers 
    332430            '\x00\x00' # number of authorities 
     
    439537        Initialize the controller: create a list of messages. 
    440538        """ 
    441539        self.messages = [] 
     540        self.dnssecConfig = common.DnssecConfig() 
    442541 
    443542 
    444543    def messageReceived(self, msg, proto, addr): 
     
    893992            repr(dns.UnknownRecord("foo\x1fbar", 12)), 
    894993            "<UNKNOWN data='foo\\x1fbar' ttl=12>") 
    895994 
     995    def test_dnskey(self): 
     996        """ 
     997        The repr of a L{dns.DNSKEY} instance includes the flags, protocol, 
     998        algo, pub_key and ttl fields of the record. 
     999         
     1000        @since: 12.1 
     1001        """ 
     1002        self.assertEqual( 
     1003            repr(dns.Record_DNSKEY(10, 20, 30, "foo\x1fbar", ttl=20)), 
     1004            "<DNSKEY flags=10 protocol=20 algo=30 pub_key=foo\x1fbar ttl=20>") 
    8961005 
     1006    def test_ds(self): 
     1007        """ 
     1008        The repr of a L{dns.DS} instance includes the key_tag, algo, digest_type, 
     1009        digest and ttl fields of the record. 
     1010         
     1011        @since: 12.1 
     1012        """ 
     1013        self.assertEqual( 
     1014            repr(dns.Record_DS(11, 22, 33, "foo\x1fbar1", ttl=21)), 
     1015            "<DS key_tag=11 algo=22 digest_type=33 digest=foo\x1fbar1 ttl=21>") 
    8971016 
     1017    def test_nsec(self): 
     1018        """ 
     1019        The repr of a L{dns.NSEC} instance includes the nxt_name, type_bitmaps 
     1020        and ttl fields of the record. 
     1021         
     1022        @since: 12.1 
     1023        """ 
     1024        self.assertEqual( 
     1025            repr(dns.Record_NSEC('bob', "\x1fabcd", ttl=31)), 
     1026            "<NSEC nxt_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     1027 
     1028    def test_nsec3param(self): 
     1029        """ 
     1030        The repr of a L{dns.NSEC3PARAM} instance includes the hash_algo, flags, 
     1031        iterations, salt and ttl fields of the record. 
     1032         
     1033        @since: 12.1 
     1034        """ 
     1035        self.assertEqual( 
     1036            repr(dns.Record_NSEC3PARAM(1, 2, 3, '\x12\x34', ttl=31)), 
     1037            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 ttl=31>") 
     1038 
     1039    def test_nsec3(self): 
     1040        """ 
     1041        The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, 
     1042        iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl fields 
     1043        of the record. 
     1044         
     1045        @since: 12.1 
     1046        """ 
     1047        self.assertEqual( 
     1048            repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', 
     1049                                  "\x1fabcd", ttl=31)), 
     1050            "<NSEC3 hash_algo=1 flags=2 iterations=3 " 
     1051            "salt=\x12\x34 nxt_hash_owner_name=bob " 
     1052            "type_bitmaps=\x1fabcd ttl=31>") 
     1053 
     1054    def test_opt(self): 
     1055        """ 
     1056        The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk 
     1057        flag, and version fields of the record. 
     1058        (The OPT record has no ttl field.) 
     1059         
     1060        @since: 12.1 
     1061        """ 
     1062        self.assertEqual( 
     1063            repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 
     1064                 "<OPT payload_size=1492 flags=0x8000 version=0>") 
     1065 
     1066    def test_rrsig(self): 
     1067        """ 
     1068        The repr of a L{dns.RRSIG} instance includes the algo, labels, 
     1069        original_ttl sig_expiration, sig_inception, key_tag, signers_name, 
     1070        signature and ttl fields of the record. 
     1071         
     1072        @since: 12.1 
     1073        """ 
     1074        self.assertEqual( 
     1075            repr(dns.Record_RRSIG(type_covered=dns.A, 
     1076                                  algo=2, 
     1077                                  labels=3, 
     1078                                  original_ttl=30, 
     1079                                  sig_expiration='20110101123456', 
     1080                                  sig_inception= '20110202112233', 
     1081                                  key_tag=60, 
     1082                                  signers_name='bob', 
     1083                                  signature='\x12\x34sig', 
     1084                                  ttl=70)), 
     1085        "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 
     1086        " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 
     1087        " signers_name=bob signature=\x12\x34sig ttl=70>") 
     1088 
    8981089class _Equal(object): 
    8991090    """ 
    9001091    A class the instances of which are equal to anything and everything. 
     
    9611152            cls('example.com', 123), 
    9621153            cls('example.org', 123)) 
    9631154 
     1155    def test_optheader(self): 
     1156        """ 
     1157        Two OptHeader instances comapare equal iff the have the same 
     1158        (Record_OPT) payload and auth bit. 
     1159        """ 
     1160        self._equalityTest( 
     1161            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, 
     1162                                                 dnssecOk=True, 
     1163                                                 version=0, 
     1164                                                 ttl=30)), 
     1165            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, 
     1166                                                 dnssecOk=True, 
     1167                                                 version=0, 
     1168                                                 ttl=30)), 
     1169            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492, 
     1170                                                 dnssecOk=False, 
     1171                                                 version=0, 
     1172                                                 ttl=40), auth=True)) 
    9641173 
    9651174    def test_rrheader(self): 
    9661175        """ 
     
    9681177        the same name, type, class, time to live, payload, and authoritative 
    9691178        bit. 
    9701179        """ 
     1180        aRec = dns.Record_A('1.2.3.4') 
     1181 
    9711182        # Vary the name 
    9721183        self._equalityTest( 
    973             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
    974             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
    975             dns.RRHeader('example.org', payload=dns.Record_A('1.2.3.4'))) 
     1184            dns.RRHeader('example.com', payload=aRec), 
     1185            dns.RRHeader('example.com', payload=aRec), 
     1186            dns.RRHeader('example.org', payload=aRec)) 
    9761187 
    9771188        # Vary the payload 
    9781189        self._equalityTest( 
    979             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
    980             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
     1190            dns.RRHeader('example.com', payload=aRec), 
     1191            dns.RRHeader('example.com', payload=aRec), 
    9811192            dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.5'))) 
    9821193 
    9831194        # Vary the type.  Leave the payload as None so that we don't have to 
     
    9891200 
    9901201        # Probably not likely to come up.  Most people use the internet. 
    9911202        self._equalityTest( 
    992             dns.RRHeader('example.com', cls=dns.IN, payload=dns.Record_A('1.2.3.4')), 
    993             dns.RRHeader('example.com', cls=dns.IN, payload=dns.Record_A('1.2.3.4')), 
    994             dns.RRHeader('example.com', cls=dns.CS, payload=dns.Record_A('1.2.3.4'))) 
     1203            dns.RRHeader('example.com', cls=dns.IN, payload=aRec), 
     1204            dns.RRHeader('example.com', cls=dns.IN, payload=aRec), 
     1205            dns.RRHeader('example.com', cls=dns.CS, payload=aRec)) 
    9951206 
    9961207        # Vary the ttl 
    9971208        self._equalityTest( 
    998             dns.RRHeader('example.com', ttl=60, payload=dns.Record_A('1.2.3.4')), 
    999             dns.RRHeader('example.com', ttl=60, payload=dns.Record_A('1.2.3.4')), 
    1000             dns.RRHeader('example.com', ttl=120, payload=dns.Record_A('1.2.3.4'))) 
     1209            dns.RRHeader('example.com', ttl=60, payload=aRec), 
     1210            dns.RRHeader('example.com', ttl=60, payload=aRec), 
     1211            dns.RRHeader('example.com', ttl=120, payload=aRec)) 
    10011212 
    10021213        # Vary the auth bit 
    10031214        self._equalityTest( 
    1004             dns.RRHeader('example.com', auth=1, payload=dns.Record_A('1.2.3.4')), 
    1005             dns.RRHeader('example.com', auth=1, payload=dns.Record_A('1.2.3.4')), 
    1006             dns.RRHeader('example.com', auth=0, payload=dns.Record_A('1.2.3.4'))) 
     1215            dns.RRHeader('example.com', auth=1, payload=aRec), 
     1216            dns.RRHeader('example.com', auth=1, payload=aRec), 
     1217            dns.RRHeader('example.com', auth=0, payload=aRec)) 
    10071218 
    10081219 
    10091220    def test_ns(self): 
     
    14831694            dns.UnknownRecord('foo', ttl=10), 
    14841695            dns.UnknownRecord('foo', ttl=10), 
    14851696            dns.UnknownRecord('foo', ttl=100)) 
     1697 
     1698    def test_rrsig(self): 
     1699        """ 
     1700        L(dns.RRSIG) instances compare equal iff they have the same 
     1701        type_covered, algo, labels, original_ttl, sig_expiration, sig_inception, 
     1702        key_tag, signers_name, signature, and ttl 
     1703         
     1704        @since: 12.1 
     1705        """ 
     1706        self._equalityTest( 
     1707            dns.Record_RRSIG(type_covered=dns.A), 
     1708            dns.Record_RRSIG(type_covered=dns.A), 
     1709            dns.Record_RRSIG(type_covered=dns.AAAA)) 
     1710        self._equalityTest( 
     1711            dns.Record_RRSIG(algo=1), 
     1712            dns.Record_RRSIG(algo=1), 
     1713            dns.Record_RRSIG(algo=2)) 
     1714        self._equalityTest( 
     1715            dns.Record_RRSIG(labels=3), 
     1716            dns.Record_RRSIG(labels=3), 
     1717            dns.Record_RRSIG(labels=4)) 
     1718        self._equalityTest( 
     1719            dns.Record_RRSIG(original_ttl=5), 
     1720            dns.Record_RRSIG(original_ttl=5), 
     1721            dns.Record_RRSIG(original_ttl=6)) 
     1722        self._equalityTest( 
     1723            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1724            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1725            dns.Record_RRSIG(sig_expiration='20110101000001')) 
     1726        self._equalityTest( 
     1727            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1728            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1729            dns.Record_RRSIG(sig_inception='20120101000001')) 
     1730        self._equalityTest( 
     1731            dns.Record_RRSIG(key_tag=11), 
     1732            dns.Record_RRSIG(key_tag=11), 
     1733            dns.Record_RRSIG(key_tag=12)) 
     1734        self._equalityTest( 
     1735            dns.Record_RRSIG(signers_name='bob'), 
     1736            dns.Record_RRSIG(signers_name='bob'), 
     1737            dns.Record_RRSIG(signers_name='joe')) 
     1738        self._equalityTest( 
     1739            dns.Record_RRSIG(signature='abcdef'), 
     1740            dns.Record_RRSIG(signature='abcdef'), 
     1741            dns.Record_RRSIG(signature='abcdefg')) 
     1742        self._equalityTest( 
     1743            dns.Record_RRSIG(ttl=10), 
     1744            dns.Record_RRSIG(ttl=10), 
     1745            dns.Record_RRSIG(ttl=20)) 
     1746 
     1747    def test_ds(self): 
     1748        """ 
     1749        L(dns.DS) instances compare equal iff they have the same 
     1750        key_tag, algo, digest_type, digest and ttl 
     1751         
     1752        @since: 12.1 
     1753        """ 
     1754        self._equalityTest( 
     1755            dns.Record_DS(key_tag=1), 
     1756            dns.Record_DS(key_tag=1), 
     1757            dns.Record_DS(key_tag=2)) 
     1758        self._equalityTest( 
     1759            dns.Record_DS(algo=3), 
     1760            dns.Record_DS(algo=3), 
     1761            dns.Record_DS(algo=4)) 
     1762        self._equalityTest( 
     1763            dns.Record_DS(digest_type=5), 
     1764            dns.Record_DS(digest_type=5), 
     1765            dns.Record_DS(digest_type=6)) 
     1766        self._equalityTest( 
     1767            dns.Record_DS(digest='abcdef-digest'), 
     1768            dns.Record_DS(digest='abcdef-digest'), 
     1769            dns.Record_DS(digest='abcdef-digest-f')) 
     1770        self._equalityTest( 
     1771            dns.Record_DS(ttl=10), 
     1772            dns.Record_DS(ttl=10), 
     1773            dns.Record_DS(ttl=20)) 
     1774 
     1775    def test_dnskey(self): 
     1776        """ 
     1777        L(dns.DNSKEY) instances compare equal iff they have the same 
     1778        flags, protocol, algo, pub_key and ttl 
     1779         
     1780        @since: 12.1 
     1781        """ 
     1782        self._equalityTest( 
     1783            dns.Record_DNSKEY(flags=1), 
     1784            dns.Record_DNSKEY(flags=1), 
     1785            dns.Record_DNSKEY(flags=2)) 
     1786        self._equalityTest( 
     1787            dns.Record_DNSKEY(protocol=3), 
     1788            dns.Record_DNSKEY(protocol=3), 
     1789            dns.Record_DNSKEY(protocol=4)) 
     1790        self._equalityTest( 
     1791            dns.Record_DNSKEY(algo=5), 
     1792            dns.Record_DNSKEY(algo=5), 
     1793            dns.Record_DNSKEY(algo=6)) 
     1794        self._equalityTest( 
     1795            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1796            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1797            dns.Record_DNSKEY(pub_key='abcdef-digest-f')) 
     1798        self._equalityTest( 
     1799            dns.Record_DNSKEY(ttl=10), 
     1800            dns.Record_DNSKEY(ttl=10), 
     1801            dns.Record_DNSKEY(ttl=20)) 
     1802 
     1803    def test_nsec(self): 
     1804        """ 
     1805        L(dns.DNSKEY) instances compare equal iff they have the same 
     1806        nxt_name, type_bitmaps and ttl 
     1807         
     1808        @since: 12.1 
     1809        """ 
     1810        self._equalityTest( 
     1811            dns.Record_NSEC(nxt_name="example.com"), 
     1812            dns.Record_NSEC(nxt_name="example.com"), 
     1813            dns.Record_NSEC(nxt_name="a.example.com")) 
     1814        self._equalityTest( 
     1815            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1816            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1817            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1818        self._equalityTest( 
     1819            dns.Record_NSEC(ttl=5), 
     1820            dns.Record_NSEC(ttl=5), 
     1821            dns.Record_NSEC(ttl=6)) 
     1822 
     1823    def test_nsec3param(self): 
     1824        """ 
     1825        L(dns.DNSKEY) instances compare equal iff they have the same 
     1826        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1827         
     1828        @since: 12.1 
     1829        """ 
     1830        self._equalityTest( 
     1831            dns.Record_NSEC3PARAM(hash_algo=1), 
     1832            dns.Record_NSEC3PARAM(hash_algo=1), 
     1833            dns.Record_NSEC3PARAM(hash_algo=2)) 
     1834        self._equalityTest( 
     1835            dns.Record_NSEC3PARAM(flags=1), 
     1836            dns.Record_NSEC3PARAM(flags=1), 
     1837            dns.Record_NSEC3PARAM(flags=2)) 
     1838        self._equalityTest( 
     1839            dns.Record_NSEC3PARAM(iterations=5), 
     1840            dns.Record_NSEC3PARAM(iterations=5), 
     1841            dns.Record_NSEC3PARAM(iterations=6)) 
     1842        self._equalityTest( 
     1843            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1844            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1845            dns.Record_NSEC3PARAM(salt="abcdefg")) 
     1846        self._equalityTest( 
     1847            dns.Record_NSEC3PARAM(ttl=5), 
     1848            dns.Record_NSEC3PARAM(ttl=5), 
     1849            dns.Record_NSEC3PARAM(ttl=6)) 
     1850 
     1851    def test_nsec3(self): 
     1852        """ 
     1853        L(dns.DNSKEY) instances compare equal iff they have the same 
     1854        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps 
     1855        and ttl 
     1856         
     1857        @since: 12.1 
     1858        """ 
     1859        self._equalityTest( 
     1860            dns.Record_NSEC3(hash_algo=1), 
     1861            dns.Record_NSEC3(hash_algo=1), 
     1862            dns.Record_NSEC3(hash_algo=2)) 
     1863        self._equalityTest( 
     1864            dns.Record_NSEC3(flags=1), 
     1865            dns.Record_NSEC3(flags=1), 
     1866            dns.Record_NSEC3(flags=2)) 
     1867        self._equalityTest( 
     1868            dns.Record_NSEC3(iterations=5), 
     1869            dns.Record_NSEC3(iterations=5), 
     1870            dns.Record_NSEC3(iterations=6)) 
     1871        self._equalityTest( 
     1872            dns.Record_NSEC3(salt="abcdef"), 
     1873            dns.Record_NSEC3(salt="abcdef"), 
     1874            dns.Record_NSEC3(salt="abcdefg")) 
     1875        self._equalityTest( 
     1876            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1877            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1878            dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 
     1879        self._equalityTest( 
     1880            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1881            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1882            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1883        self._equalityTest( 
     1884            dns.Record_NSEC3(ttl=5), 
     1885            dns.Record_NSEC3(ttl=5), 
     1886            dns.Record_NSEC3(ttl=6)) 
     1887 
     1888 
  • twisted/names/test/test_names.py

     
    9898                           '\x12\x01\x16\xfe\xc1\x00\x01'), 
    9999            dns.Record_NAPTR(100, 10, "u", "sip+E2U", 
    100100                             "!^.*$!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" 
     104                              "/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q" 
     105                              "845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBT" 
     106                              "AvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8" 
     107                              "LJ55Y1k=" 
     108                             )], 
    102109        'http.tcp.test-domain.com': [ 
    103110            dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') 
    104111        ], 
    105112        'host.test-domain.com': [ 
    106113            dns.Record_A('123.242.1.5'), 
    107114            dns.Record_A('0.255.0.255'), 
     115            dns.Record_RRSIG(dns.A, 5, 3, 86400, 
     116                             '20120101000000', '20120201000000', 
     117                             2642, 'test-domain.com', 
     118                            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K" 
     119                            "+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845K" 
     120                            "ya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTbo" 
     121                            "GmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=") 
    108122        ], 
    109123        'host-two.test-domain.com': [ 
    110124# 
     
    224238        """Test DNS 'A' record queries with multiple answers""" 
    225239        return self.namesTest( 
    226240            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)] 
     241            [dns.Record_A('123.242.1.5', ttl=19283784), 
     242             dns.Record_A('0.255.0.255', ttl=19283784)] 
    228243        ) 
    229244 
    230245 
     
    232247        """Test DNS 'A' record queries with edge cases""" 
    233248        return self.namesTest( 
    234249            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)] 
     250            [dns.Record_A('255.255.255.254', ttl=19283784), 
     251             dns.Record_A('0.0.0.0', ttl=19283784)] 
    236252        ) 
    237253 
    238254 
     
    264280        """Test DNS 'HINFO' record queries""" 
    265281        return self.namesTest( 
    266282            self.resolver.lookupHostInfo('test-domain.com'), 
    267             [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', ttl=19283784)] 
     283            [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', 
     284                              ttl=19283784)] 
    268285        ) 
    269286 
    270287    def testPTR(self): 
     
    286303        """Test additional processing for CNAME records""" 
    287304        return self.namesTest( 
    288305        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)] 
     306        [dns.Record_CNAME('test-domain.com', ttl=19283784), 
     307         dns.Record_A('127.0.0.1', ttl=19283784)] 
    290308    ) 
    291309 
    292310    def testMB(self): 
     
    317335        """Test DNS 'MINFO' record queries""" 
    318336        return self.namesTest( 
    319337            self.resolver.lookupMailboxInfo('test-domain.com'), 
    320             [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', ttl=19283784)] 
     338            [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', 
     339                              ttl=19283784)] 
    321340        ) 
    322341 
    323342 
     
    325344        """Test DNS 'SRV' record queries""" 
    326345        return self.namesTest( 
    327346            self.resolver.lookupService('http.tcp.test-domain.com'), 
    328             [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl=19283784)] 
     347            [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', 
     348                            ttl=19283784)] 
    329349        ) 
    330350 
    331351    def testAFSDB(self): 
    332352        """Test DNS 'AFSDB' record queries""" 
    333353        return self.namesTest( 
    334354            self.resolver.lookupAFSDatabase('test-domain.com'), 
    335             [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', ttl=19283784)] 
     355            [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', 
     356                              ttl=19283784)] 
    336357        ) 
    337358 
    338359 
     
    340361        """Test DNS 'RP' record queries""" 
    341362        return self.namesTest( 
    342363            self.resolver.lookupResponsibility('test-domain.com'), 
    343             [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', ttl=19283784)] 
     364            [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', 
     365                           ttl=19283784)] 
    344366        ) 
    345367 
    346368 
     
    348370        """Test DNS 'TXT' record queries""" 
    349371        return self.namesTest( 
    350372            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)] 
     373            [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', 
     374                            ttl=19283784), 
     375             dns.Record_TXT('Some more text, haha!  Yes.  \0  Still here?', 
     376                            ttl=19283784)] 
    353377        ) 
    354378 
    355379 
     
    359383        """ 
    360384        return self.namesTest( 
    361385            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)] 
     386            [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all', 
     387                            ttl=19283784), 
     388            dns.Record_SPF('v=spf1 +mx a:\0colo', 
     389                           '.example.com/28 -all not valid', 
     390                           ttl=19283784)] 
    364391        ) 
    365392 
    366393 
     
    368395        """Test DNS 'WKS' record queries""" 
    369396        return self.namesTest( 
    370397            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)] 
     398            [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, 
     399                            '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] 
    372400        ) 
    373401 
    374402 
     
    381409             dns.Record_A('1.2.3.4', ttl='1S'), 
    382410             dns.Record_NS('ns1.domain', ttl='2M'), 
    383411             dns.Record_NS('ns2.domain', ttl='3H'), 
    384              dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D')] 
     412             dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', 
     413                            ttl='4D')] 
    385414            ) 
    386415 
    387416 
     
    389418        """Test DNS 'AAAA' record queries (IPv6)""" 
    390419        return self.namesTest( 
    391420            self.resolver.lookupIPV6Address('test-domain.com'), 
    392             [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', ttl=19283784)] 
     421            [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', 
     422                             ttl=19283784)] 
    393423        ) 
    394424 
    395425    def testA6(self): 
     
    398428            self.resolver.lookupAddress6('test-domain.com'), 
    399429            [dns.Record_A6(0, 'ABCD::4321', '', ttl=19283784), 
    400430             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)] 
     431             dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 
     432                           'tra.la.la.net', ttl=19283784)] 
    402433         ) 
    403434 
    404435 
     
    407438        Test DNS 'AXFR' queries (Zone transfer) 
    408439        """ 
    409440        default_ttl = soa_record.expire 
    410         results = [copy.copy(r) for r in reduce(operator.add, test_domain_com.records.values())] 
     441        results = [copy.copy(r) 
     442                   for r in reduce(operator.add, 
     443                                   test_domain_com.records.values())] 
    411444        for r in results: 
    412445            if r.ttl is None: 
    413446                r.ttl = default_ttl 
     
    435468                              "!^.*$!sip:information@domain.tld!", 
    436469                              ttl=19283784)]) 
    437470 
     471    def test_DNSKEY(self): 
     472        """ 
     473        Test DNS 'DNSKEY' record queries. 
     474         
     475        @since: 12.1 
     476        """ 
     477        return self.namesTest( 
     478            self.resolver.lookupDNSKey('test-domain.com'), 
     479            [dns.Record_DNSKEY(0x10, 3, 5, 
     480                               "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9" 
     481                               "H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5" 
     482                               "Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9" 
     483                               "pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6" 
     484                               "fHR9eekIWis8LJ55Y1k=", 
     485                               ttl=19283784)]) 
    438486 
    439  
    440487class DNSServerFactoryTests(unittest.TestCase): 
    441488    """ 
    442489    Tests for L{server.DNSServerFactory}. 
     
    523570        self.d.addCallback(self._gotResults) 
    524571        self.controller = client.AXFRController('fooby.com', self.d) 
    525572 
    526         self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, ttl=86400, auth=False, 
     573        self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, 
     574                                ttl=86400, auth=False, 
    527575                                payload=dns.Record_SOA(mname='fooby.com', 
    528576                                                       rname='hooj.fooby.com', 
    529577                                                       serial=100, 
     
    535583 
    536584        self.records = [ 
    537585            self.soa, 
    538             dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, 
    539                          payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700)), 
     586            dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, 
     587                         auth=False, 
     588                         payload=dns.Record_NS(name='ns.twistedmatrix.com', 
     589                                               ttl=700)), 
    540590 
    541             dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, auth=False, 
    542                          payload=dns.Record_MX(preference=10, exchange='mail.mv3d.com', ttl=700)), 
     591            dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, 
     592                         auth=False, 
     593                         payload=dns.Record_MX(preference=10, 
     594                                               exchange='mail.mv3d.com', 
     595                                               ttl=700)), 
    543596 
    544             dns.RRHeader(name='fooby.com', type=dns.A, cls=dns.IN, ttl=700, auth=False, 
    545                          payload=dns.Record_A(address='64.123.27.105', ttl=700)), 
     597            dns.RRHeader(name='fooby.com', type=dns.A, cls=dns.IN, 
     598                         ttl=700, auth=False, 
     599                         payload=dns.Record_A(address='64.123.27.105', 
     600                                              ttl=700)), 
    546601            self.soa 
    547602            ] 
    548603 
    549604    def _makeMessage(self): 
    550605        # 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) 
     606        return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, 
     607                           auth=1, rCode=0, trunc=0, maxSize=0) 
    552608 
    553609    def testBindAndTNamesStyle(self): 
    554610        # Bind style = One big single message 
     
    890946        self.assertEqual(service.domains[1].domain, 'example.edu') 
    891947 
    892948 
    893  
    894949class SecondaryAuthorityTests(unittest.TestCase): 
    895950    """ 
    896951    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""" 
     5Test cases for L{twisted.names.ser_num_arith}. 
     6 
     7@since: 12.1 
     8""" 
     9 
     10from twisted.names.ser_num_arith import SNA, DateSNA 
     11from twisted.names.ser_num_arith import max as sna_max 
     12from twisted.trial import unittest 
     13 
     14class SNATest(unittest.TestCase): 
     15 
     16    def setUp(self): 
     17        self.s1 = SNA(1) 
     18        self.s1a = SNA(1) 
     19        self.s2 = SNA(2) 
     20        self.sMaxVal = SNA(SNA.HLFRNG+SNA.HLFRNG-1) 
     21 
     22    def test_equality(self): 
     23        """ 
     24        Test SNA equality 
     25        """ 
     26        self.assertEqual(self.s1, self.s1a) 
     27        self.assertNotIdentical(self.s1, self.s1a) 
     28        self.assertEqual(hash(self.s1), hash(self.s1a)) 
     29        self.assertNotEqual(hash(self.s1), hash(self.s2)) 
     30 
     31    def test_le(self): 
     32        """ 
     33        Test SNA less than or equal 
     34        """ 
     35        self.assertTrue(self.s1 <= self.s1) 
     36        self.assertTrue(self.s1 <= self.s1a) 
     37        self.assertTrue(self.s1 <= self.s2) 
     38        self.assertFalse(self.s2 <= self.s1) 
     39 
     40    def test_ge(self): 
     41        """ 
     42        Test SNA greater than or equal 
     43        """ 
     44        self.assertTrue(self.s1 >= self.s1) 
     45        self.assertTrue(self.s1 >= self.s1a) 
     46        self.assertFalse(self.s1 >= self.s2) 
     47        self.assertTrue(self.s2 >= self.s1) 
     48 
     49 
     50    def test_lt(self): 
     51        """ 
     52        Test SNA less than 
     53        """ 
     54        self.assertFalse(self.s1 < self.s1) 
     55        self.assertFalse(self.s1 < self.s1a) 
     56        self.assertTrue(self.s1 < self.s2) 
     57        self.assertFalse(self.s2 < self.s1) 
     58 
     59    def test_gt(self): 
     60        """ 
     61        Test SNA greater than 
     62        """ 
     63        self.assertFalse(self.s1 > self.s1) 
     64        self.assertFalse(self.s1 > self.s1a) 
     65        self.assertFalse(self.s1 > self.s2) 
     66        self.assertTrue(self.s2 > self.s1) 
     67 
     68    def test_add(self): 
     69        """ 
     70        Test SNA addition 
     71        """ 
     72        self.assertEqual(self.s1 + self.s1, self.s2) 
     73        self.assertEqual(self.s1 + SNA(SNA.MAXADD), SNA(SNA.MAXADD + 1)) 
     74        self.assertEqual(SNA(SNA.MAXADD) + SNA(SNA.MAXADD) + SNA(2), SNA(0)) 
     75 
     76    def test_maxval(self): 
     77        """ 
     78        Test SNA maxval 
     79        """ 
     80        smaxplus1 = self.sMaxVal + self.s1 
     81        self.assertTrue(smaxplus1 > self.sMaxVal) 
     82        self.assertEqual(smaxplus1, SNA(0)) 
     83 
     84    def test_max(self): 
     85        """ 
     86        Test the SNA max function 
     87        """ 
     88        self.assertEqual(sna_max([None, self.s1]), self.s1) 
     89        self.assertEqual(sna_max([self.s1, None]), self.s1) 
     90        self.assertEqual(sna_max([self.s1, self.s1a]), self.s1) 
     91        self.assertEqual(sna_max([self.s2, self.s1a, self.s1, None]), self.s2) 
     92        self.assertEqual(sna_max([SNA(SNA.MAXADD), self.s2, self.s1a, self.s1, None]), 
     93                          SNA(SNA.MAXADD)) 
     94        self.assertEqual(sna_max([self.s2, self.s1a, self.s1, None, self.sMaxVal]), 
     95                          self.s2) 
     96 
     97    def test_dateSNA(self): 
     98        """ 
     99        Test DateSNA construction and comparison 
     100        """ 
     101        date1 = DateSNA('20120101000000') 
     102        date2 = DateSNA('20130101000000') 
     103        self.assertTrue(date1 < date2) 
     104 
     105    def test_dateAdd(self): 
     106        """ 
     107        Test DateSNA addition 
     108        """ 
     109        date3 = DateSNA('20370101000000') 
     110        sna1  = SNA(365*24*60*60) 
     111        date4 = date3 + sna1 
     112        self.assertEqual(date4.asInt(),  date3.asInt() + sna1.asInt()) 
     113 
     114    def test_asDate(self): 
     115        """ 
     116        Test DateSNA conversion 
     117        """ 
     118        date1 = '20120101000000' 
     119        date1Sna = DateSNA(date1) 
     120        self.assertEqual(date1Sna.asDate(), date1) 
     121 
     122    def test_roundTrip(self): 
     123        """ 
     124        Test DateSNA conversion 
     125        """ 
     126        date1 = '20370101000000' 
     127        date1Sna = DateSNA(date1) 
     128        intval = date1Sna.asInt() 
     129        sna1a = SNA(intval) 
     130 
     131        dateSna1a = DateSNA.fromSNA(sna1a) 
     132        self.assertEqual(date1Sna, dateSna1a) 
     133 
     134        dateSna2 = DateSNA.fromInt(intval) 
     135        self.assertEqual(date1Sna, dateSna2) 
  • twisted/names/topfiles/5454.feature

     
     1Features 
     2-------- 
     3 - The main features introduced by this change are EDNS0 and support 
     4   for DNSSEC. Enabling EDNS0 adds to a query an OPT record that carries 
     5   two pieces of information. The first is the maximum size UDP packet  
     6   that the network can handle (see RFC2671.) The second is the DNSSEC  
     7   OK (DO) bit which tells an upstream resolver that the querying resolver  
     8   is able to accept DNSSEC security data (See RFC3225.) Although this 
     9   change fully implements EDNS0, it only enables twisted.names to  
     10   ask for DNSSEC data and pass that data to the user. The user may 
     11   check the Authentic Data (AD) bit in the message header to determine 
     12   if the upstream resolver validates the data. (See RFC 4035, Section  
     13   4.9.3 regarding only using the AD bit from a trusted resolver  
     14   on a secure channel.) 
     15 - Processing DNSSEC data and validating DNS answers requires doing  
     16   cryptographic processing using a library such as openssl. This may  
     17   be part of a future feature set but is not in the current feature. 
     18 - The new class twisted.names.common.DnssecConfig allows configuring 
     19   DNSSEC and EDNS0 parameters, as well as the recursion desired DNS 
     20   parameter, for a resolver. DnssecConfig is an optional input argument  
     21   to ResolverBase and is implemented for client.Resolver and  
     22   secondaryAuthority.Resolver 
     23 - ResolverBase now has new lookup methods for lookupDNSKey, lookupDS,  
     24   lookupNSEC, lookupNSEC3, lookupNSEC3Param and lookupRRSIG records. 
     25 - twisted.names.client.Resolver now returns a 4-tuple to a query when  
     26   configured with dnssecOk. The 4-tuple includes a new reference  
     27   to the message so that the caller can obtain the AD flag (and  
     28   any of the other flags) in the message. 
     29 - twisted.names.client now has new lookup methods for the six new  
     30   DNSSEC record types. 
     31 - twisted.names.dns now supports six new DNS record types - DNSKey, 
     32   DS, NSEC, NSEC3, NSEC3Param and RRSIG. 
     33 - The new twisted.names.dns.Sigstr class encodes/decodes signatures and keys. 
     34 - The new twisted.names.dns.TypeBitmaps class encodes/decoes the type bitmap 
     35   field in an NSEC3 resource record. 
     36 - The new OptHeader and Record_OPT classes support the EDNS and DNSSEC  
     37   options. 
     38 - twisted.names.dns now has new classes added for the six DNSSEC record types. 
     39 - The dns.Message class now has new AD and CD flags for AuthenticData and Checking Disabled. 
     40 - twisted.names.dns now adds the OPT record to EDNS queries. 
     41 - twisted.names.dns.Message.startListening now listens for larger UDP  
     42   packets, as set by maxUdpPktSz. 
     43 - The new twisted.names.ser_num_arith class implements DNS Serial Number 
     44   Arithmetic (SNA) and Date SNA for handling numbers and dates that 
     45   roll through a 32-bit integer. 
     46 - New tests are added for all new features. 
     47 No newline at end of file