Ticket #5454: addEdsn0AndDnssec5454V02.patch

File addEdsn0AndDnssec5454V02.patch, 95.3 KB (added by BobNovas, 3 years ago)

patch for ticket 5454

  • doc/names/examples/dnssecTest.py

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

     
    1515        <li><a href="testdns.py">testdns.py</a></li> 
    1616        <li><a href="dns-service.py">dns-service.py</a></li> 
    1717        <li><a href="gethostbyname.py">gethostbyname.py</a></li> 
     18        <li><a href="dnssecTest.py">dnssecTest.py</a></li> 
    1819    </ul> 
    1920</body> 
    2021</html> 
  • 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 RFC4033.) To use DNSSEC requires EDNS0, because to enable DNSSEC requires setting the DNSSEC OK (DO) bit which is in the EDNS0 OPT Record. RFC4035 discusses how a non-validating security aware resolver (which is what twisted.names is with the DNSSEC change) should handle the DO, CD and AD bits. 
     55</p> 
     56 
     57<p><a href="../../../doc/names/examples/dnssecTest.py" class="py-listings">dnssecTest.py</a> is an example of using DNSSEC to check the AD bit of a domain that should validate. 
     58</p> 
     59 
    5260</body></html> 
  • NEWS

     
    11Ticket numbers in this file can be looked up by visiting 
    22http://twistedmatrix.com/trac/ticket/<number> 
    33 
     4 
     5Twisted Names 12.1.0 (2012-03-13) 
     6================================= 
     7 
     8Features 
     9-------- 
     10 - The main features introduced by this change are EDNS0 and support 
     11   for DNSSEC. Enabling EDNS0 adds to a query an OPT record that carries 
     12   two pieces of information. The first is the maximum size UDP packet  
     13   that the network can handle (see RFC2671.) The second is the DNSSEC  
     14   OK (DO) bit which tells an upstream resolver that the querying resolver  
     15   is able to accept DNSSEC security data (See RFC3225.) Although this 
     16   change fully implements EDNS0, it only enables twisted.names to  
     17   ask for DNSSEC data and pass that data to the user. The user may 
     18   check the Authentic Data (AD) bit in the message header to determine 
     19   if the upstream resolver validates the data. (See RFC 4035, Section  
     20   4.9.3 regarding only using the AD bit from a trusted resolver  
     21   on a secure channel.) 
     22 - Processing DNSSEC data and validating DNS answers requires doing  
     23   cryptographic processing using a library such as openssl. This may  
     24   be part of a future feature set but is not in the current feature. 
     25 - The new class twisted.names.common.DnssecConfig allows configuring 
     26   DNSSEC and EDNS0 parameters, as well as the recursion desired DNS 
     27   parameter, for a resolver. DnssecConfig is an optional input argument  
     28   to ResolverBase and is implemented for client.Resolver and  
     29   secondaryAuthority.Resolver 
     30 - ResolverBase has new lookup methods for lookupDNSKey, lookupDS,  
     31   lookupNSEC, lookupNSEC3, lookupNSEC3Param and lookupRRSIG records. 
     32 - twisted.names.client.Resolver returns a 4-tuple to a query when  
     33   configured with dnssecOk. The 4-tuple includes a new reference  
     34   to the message so that the caller can obtain the AD flag (and  
     35   any of the other flags) in the message. 
     36 - twisted.names.client has new lookup methods for the six new  
     37   DNSSEC record types. 
     38 - twisted.names.dns supports six new DNS record types - DNSKey, 
     39   DS, NSEC, NSEC3, NSEC3Param and RRSIG. 
     40 - Class twisted.names.dns.Sigstr encodes/decodes signatures and keys. 
     41 - Class twisted.names.dns.TypeBitmaps encodes/decoes the type bitmap 
     42   field in an NSEC3 resource record. 
     43 - Class OptHeader and class Record_OPT supports the EDNS and DNSSEC  
     44   options. 
     45 - twisted.names.dns has new classes added for the six DNSSEC record types. 
     46 - AD and CD flags are added to the dns.Message class. 
     47 - twisted.names.dns adds the OPT record to EDNS queries. 
     48 - twisted.names.dns.Message.startListening listens for larger UDP  
     49   packets, as set by maxUdpPktSz. 
     50 - Class twisted.names.ser_num_arith implements DNS Serial Number 
     51   Arithmetic (SNA) and Date SNA for handling numbers and dates that 
     52   roll through a 32-bit integer. 
     53 - new tests are added for all new features. 
     54    
     55 
    456Twisted Core 12.0.0 (2012-02-10) 
    557================================ 
    658 
  • 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 
     
    98103            L{IReactorTCP} which will be used to establish connections, listen 
    99104            for DNS datagrams, and enforce timeouts.  If not provided, the 
    100105            global reactor will be used. 
     106             
     107        @param dnssecConfig: An L{DnssecConfig} - see common.DnssecConfig() 
    101108 
    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) 
     391         
     392        #if dnssecOk is enabled, return a reference to the message as the  
     393        #4th member of the tuple, so the caller can access the message header  
     394        #flags. There are more flags than just AD (authentic Data) that are  
     395        #set in a response that may be of interest (e.g., Truncate-TC). 
     396        if self.dnssecConfig.dnssecOk: 
     397            return (message.answers, message.authority, message.additional, message) 
     398        else: 
     399            #dnssecOk was not requested - return a legacy 3-tuple 
     400            return (message.answers, message.authority, message.additional) 
    385401 
    386402 
    387403    def _lookup(self, name, cls, type, timeout): 
     
    953969    @rtype: C{Deferred} 
    954970    """ 
    955971    return getResolver().lookupNamingAuthorityPointer(name, timeout) 
     972 
     973 
     974def lookupDNSKey(name, timeout=None): 
     975    """ 
     976    DNSKEY lookup.     
     977 
     978    @type name: C{str} 
     979    @param name: DNS name to resolve. 
     980 
     981    @type timeout: Sequence of C{int} 
     982    @param timeout: Number of seconds after which to reissue the query. 
     983        When the last timeout expires, the query is considered failed. 
     984 
     985    @rtype: C{Deferred} 
     986    """ 
     987    return getResolver().lookupDNSKey(name, timeout) 
     988 
     989 
     990def lookupDS(name, timeout=None): 
     991    """ 
     992    DS lookup.     
     993 
     994    @type name: C{str} 
     995    @param name: DNS name to resolve. 
     996 
     997    @type timeout: Sequence of C{int} 
     998    @param timeout: Number of seconds after which to reissue the query. 
     999        When the last timeout expires, the query is considered failed. 
     1000 
     1001    @rtype: C{Deferred} 
     1002    """ 
     1003    return getResolver().lookupDS(name, timeout) 
     1004 
     1005 
     1006def lookupNSEC(name, timeout=None): 
     1007    """ 
     1008    NSEC lookup.     
     1009 
     1010    @type name: C{str} 
     1011    @param name: DNS name to resolve. 
     1012 
     1013    @type timeout: Sequence of C{int} 
     1014    @param timeout: Number of seconds after which to reissue the query. 
     1015        When the last timeout expires, the query is considered failed. 
     1016 
     1017    @rtype: C{Deferred} 
     1018    """ 
     1019    return getResolver().lookupNSEC(name, timeout) 
     1020 
     1021 
     1022def lookupNSEC3(name, timeout=None): 
     1023    """ 
     1024    NSEC3 lookup.     
     1025 
     1026    @type name: C{str} 
     1027    @param name: DNS name to resolve. 
     1028 
     1029    @type timeout: Sequence of C{int} 
     1030    @param timeout: Number of seconds after which to reissue the query. 
     1031        When the last timeout expires, the query is considered failed. 
     1032 
     1033    @rtype: C{Deferred} 
     1034    """ 
     1035    return getResolver().lookupNSEC3(name, timeout) 
     1036 
     1037 
     1038def lookupNSEC3Param(name, timeout=None): 
     1039    """ 
     1040    NSEC3 Param lookup.     
     1041 
     1042    @type name: C{str} 
     1043    @param name: DNS name to resolve. 
     1044 
     1045    @type timeout: Sequence of C{int} 
     1046    @param timeout: Number of seconds after which to reissue the query. 
     1047        When the last timeout expires, the query is considered failed. 
     1048 
     1049    @rtype: C{Deferred} 
     1050    """ 
     1051    return getResolver().lookupNSEC3Param(name, timeout) 
     1052 
     1053 
     1054def lookupRRSIG(name, timeout=None): 
     1055    """ 
     1056    RRSIG lookup.     
     1057 
     1058    @type name: C{str} 
     1059    @param name: DNS name to resolve. 
     1060 
     1061    @type timeout: Sequence of C{int} 
     1062    @param timeout: Number of seconds after which to reissue the query. 
     1063        When the last timeout expires, the query is considered failed. 
     1064 
     1065    @rtype: C{Deferred} 
     1066    """ 
     1067    return getResolver().lookupRRSIG(name, timeout) 
  • twisted/names/common.py

     
    1818 
    1919EMPTY_RESULT = (), (), () 
    2020 
     21class DnssecConfig(): 
     22    """ 
     23    Sets recDes and the DNSSEC parameters. See RFC's 4033, 4034 and 4035. 
     24 
     25    recDes (RD)   - Recursion Desired. Not a DNSSEC parameter and does not  
     26                    require ednsEnabled, but still nice to be able to control  
     27                    whether or not you're asking for recursion. 
     28                    (bool) 
     29 
     30    ednsEnabled   - EDNS Enabled adds an OPT record to the query. The OPT record 
     31                    contains a version field that indicates the version of EDNS  
     32                    that you can handle.  
     33                    (bool) 
     34                     
     35    maxUdpPktSz   - The max size UDP packet (bytes) that your end-to-end network 
     36                    can handle (on a modern network a reliable size is 1492,  
     37                    although up to 65535 is possible). Requires ednsEnabled. 
     38                    (int) 
     39                     
     40    dnssecOK (DO) - Dnssec Ok. A bit that indicates you want DNSSEC RR's and  
     41                    validation if the resolver validates. If DO is set, AD  
     42                    will be set in the response if the answer validates.  
     43                    Requires ednsEnabled. 
     44                    (bool) 
     45 
     46    chkDis (CD)   - Checking Disabled. If DO and CD are set, a validating  
     47                    resolver won't do validation but will return the DNSSEC  
     48                    RR's so that YOU can. 
     49                    (bool) 
     50                     
     51    version       - sets the edns version level. Currently, only version 0 is  
     52                    defined and supported by RFC2671. 
     53                    (int)                     
     54    """ 
     55    def __init__(self,  
     56                 recDes=True, 
     57                 ednsEnabled=False,  
     58                 maxUdpPktSz=512,  
     59                 dnssecOk=False, 
     60                 chkDis=False, 
     61                 version=0): 
     62 
     63        self.recDes = recDes 
     64        self.ednsEnabled = ednsEnabled 
     65        self.maxUdpPktSz = maxUdpPktSz 
     66        self.dnssecOk = dnssecOk 
     67        self.chkDis = chkDis 
     68        self.version = version 
     69 
     70        assert not self.ednsEnabled or 512 <= self.maxUdpPktSz <= 65535 
     71        assert version == 0 
     72 
    2173class ResolverBase: 
    2274    """ 
    2375    L{ResolverBase} is a base class for L{IResolver} implementations which 
     
    3688 
    3789    typeToMethod = None 
    3890 
    39     def __init__(self): 
     91    def __init__(self, dnssecConfig=None): 
    4092        self.typeToMethod = {} 
    4193        for (k, v) in typeToMethod.items(): 
    4294            self.typeToMethod[k] = getattr(self, v) 
     95        self.dnssecConfig = dnssecConfig 
     96        if self.dnssecConfig == None: 
     97            self.dnssecConfig = DnssecConfig() 
    4398 
    44  
    4599    def exceptionForCode(self, responseCode): 
    46100        """ 
    47101        Convert a response code (one of the possible values of 
     
    200254        @see: twisted.names.client.lookupAllRecords 
    201255        """ 
    202256        return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) 
     257     
    203258 
     259    def lookupDNSKey(self, name, timeout=None): 
     260        """ 
     261        @see: twisted.names.client.lookupDNSKey 
     262        """ 
     263        return self._lookup(name, dns.IN, dns.DNSKEY, timeout) 
     264     
     265 
     266    def lookupDS(self, name, timeout=None): 
     267        """ 
     268        @see: twisted.names.client.lookupDS 
     269        """ 
     270        return self._lookup(name, dns.IN, dns.DS, timeout) 
     271     
     272 
     273    def lookupNSEC(self, name, timeout=None): 
     274        """ 
     275        @see: twisted.names.client.lookupNSEC 
     276        """ 
     277        return self._lookup(name, dns.IN, dns.NSEC, timeout) 
     278     
     279 
     280    def lookupNSEC3(self, name, timeout=None): 
     281        """ 
     282        @see: twisted.names.client.lookupNSEC3 
     283        """ 
     284        return self._lookup(name, dns.IN, dns.NSEC3, timeout) 
     285     
     286 
     287    def lookupNSEC3Param(self, name, timeout=None): 
     288        """ 
     289        @see: twisted.names.client.lookupNSEC3Param 
     290        """ 
     291        return self._lookup(name, dns.IN, dns.NSEC3PARAM, timeout) 
     292     
     293 
     294    def lookupRRSIG(self, name, timeout=None): 
     295        """ 
     296        @see: twisted.names.client.lookupRRSIG 
     297        """ 
     298        return self._lookup(name, dns.IN, dns.RRSIG, timeout) 
     299 
     300 
    204301    def getHostByName(self, name, timeout = None, effort = 10): 
    205302        """ 
    206303        @see: twisted.names.client.getHostByName 
     
    268365    dns.MX:    'lookupMailExchange', 
    269366    dns.TXT:   'lookupText', 
    270367    dns.SPF:   'lookupSenderPolicy', 
     368    dns.DNSKEY:'lookupDNSKey', 
     369    dns.DS:    'lookupDS', 
     370    dns.NSEC:  'lookupNSEC', 
     371    dns.NSEC3: 'lookupNSEC3', 
     372    dns.NSEC3PARAM: 'lookupNSEC3Param', 
     373    dns.RRSIG: 'lookupRRSIG', 
    271374 
    272375    dns.RP:    'lookupResponsibility', 
    273376    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', 'Record_PTR', 'Record_RP', 'Record_RRSIG',  
     34    'Record_SOA', 'Record_SPF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 
    3335 
    3436    'QUERY_CLASSES', 'QUERY_TYPES', 'REV_CLASSES', 'REV_TYPES', 'EXT_QUERIES', 
    3537 
    36     'Charstr', 'Message', 'Name', 'Query', 'RRHeader', 'SimpleRecord', 
     38    'Charstr', 'Message', 'Name', 'OPTHeader', 'Query', 'RRHeader', 'SimpleRecord', 
    3739    'DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', 
    3840 
    3941    'OK', 'OP_INVERSE', 'OP_NOTIFY', 'OP_QUERY', 'OP_STATUS', 'OP_UPDATE', 
     
    4648# System imports 
    4749import warnings 
    4850 
     51import re 
    4952import struct, random, types, socket 
    5053 
    5154import cStringIO as StringIO 
     
    5457 
    5558from zope.interface import implements, Interface, Attribute 
    5659 
     60from base64 import b64decode, b64encode 
    5761 
    5862# Twisted imports 
    5963from twisted.internet import protocol, defer 
     
    6165from twisted.python import log, failure 
    6266from twisted.python import util as tputil 
    6367from twisted.python import randbytes 
     68from twisted.names.ser_num_arith import SNA, DateSNA 
    6469 
    6570 
    6671def randomSource(): 
     
    7984NAPTR = 35 
    8085A6 = 38 
    8186DNAME = 39 
     87OPT = 41 
     88DS = 43 
     89RRSIG = 46 
     90NSEC = 47 
     91DNSKEY = 48 
     92NSEC3 = 50 
     93NSEC3PARAM = 51 
    8294SPF = 99 
    8395 
    8496QUERY_TYPES = { 
     
    108120    NAPTR: 'NAPTR', 
    109121    A6: 'A6', 
    110122    DNAME: 'DNAME', 
    111     SPF: 'SPF' 
     123    OPT: 'OPT', 
     124    DS: 'DS', 
     125    RRSIG: 'RRSIG', 
     126    NSEC: 'NSEC', 
     127    DNSKEY: 'DNSKEY', 
     128    NSEC3: 'NSEC3',  
     129    NSEC3PARAM: 'NSEC3PARAM', 
     130    SPF: 'SPF', 
    112131} 
    113132 
    114133IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) 
     
    370389 
    371390    def __str__(self): 
    372391        return self.name 
     392     
     393class Sigstr(object): 
     394    ''' 
     395    for signatures and keys. display as b64 encoded 
     396    ''' 
     397    implements(IEncodable) 
     398     
     399    def __init__(self, string=''): 
     400        if not isinstance(string, str): 
     401            raise ValueError("%r is not a string" % (string, )) 
     402        self.string = string #b64encoded string 
     403         
     404    def encode(self, strio, compDict=None): 
     405        ''' 
     406        Write the byte representation (the un-b64-encoded string) 
     407        to the file. 
     408         
     409        @type strio: file 
     410        @param srio: The byte representation of this signature or key 
     411        will be written to this file 
     412         
     413        @type compDict: dict 
     414        @param compDict: not used. 
     415        ''' 
     416        strio.write(b64decode(self.string)) 
     417         
     418    def decode(self, strio, length=None): 
     419        ''' 
     420        Decode a signature or a key. 
    373421 
     422        @type strio: file 
     423        @param strio: Exactly length bytes will be read from this file  
     424        to decode the full signature or key 
     425         
     426        @type length: int 
     427        @param lenth: length must always be given. A signature or key 
     428        is always the last thing in an RR and so you can always determine 
     429        its length.  
     430        ''' 
     431        self.string = '' 
     432        if length == None: 
     433            return 
     434         
     435        assert isinstance(length, int) 
     436        buff = readPrecisely(strio, length) 
     437        self.string = b64encode(buff) 
     438 
     439    def __eq__(self, other): 
     440        if isinstance(other, Sigstr): 
     441            return self.string == other.string 
     442        return False 
     443 
     444    def __hash__(self): 
     445        return hash(self.string) 
     446 
     447    def __str__(self): 
     448        return self.string 
     449     
     450 
     451class TypeBitmaps(object): 
     452    ''' 
     453    bitmap encoding scheme used by NSEC and NSEC3 RR's 
     454    to indicate the RRset types that exist at the  
     455    NSEC/NSEC3 RR's original owner name or hashed name.   
     456    See RFC 4034 and RFC 5155. 
     457    ''' 
     458    fmt = 'BB' 
     459    typeRegex = re.compile('TYPE(\d+)') 
     460     
     461    def __init__(self, string=''): 
     462        self.string = string 
     463         
     464    def encode(self, strio, compDict=None): 
     465        """ 
     466        Encode the string field, which consists of a set  
     467        of type names, into an NSEC/NSEC3 type bitmap. 
     468         
     469        @type strio: file 
     470        @param strio: the byte representation of the type bitmap 
     471        will be written to this file. 
     472         
     473        @type compDict: dict 
     474        @param compDict: not used. 
     475        """ 
     476        if not self.string: 
     477            return; 
     478         
     479        #get a sorted list of RR Type Values 
     480        mnus = self.string.split(' ') 
     481        mnuVals = [] 
     482        for mnu in mnus: 
     483            mnuVal = REV_TYPES.get(mnu, None) 
     484            if not mnuVal: 
     485                m = self.typeRegex.match(mnu) 
     486                if m.groups(): 
     487                    mnuVal = int(m.group(1)) 
     488                    assert mnuVal < 65536 
     489                else: 
     490                    log.err("can't parse %s in %s" % (mnu, self.string, )) 
     491                    continue; 
     492            mnuVals.append(mnuVal) 
     493        mnuVals.sort() 
     494         
     495        #convert that to a dict of windows and lists 
     496        windDict = {} 
     497        for v in mnuVals: 
     498            window = (v >> 8) & 0xFF 
     499            if window not in windDict: 
     500                windDict[window] = [] 
     501            windDict[window].append(v & 0xFF) 
     502         
     503        #have to sort the keys - they're not in order! 
     504        windows = windDict.keys() 
     505        windows.sort() 
     506 
     507        #create the bitmaps 
     508        bmap = bytearray() 
     509        for w in windows: 
     510            bmapseg = bytearray(32) 
     511            maxoff = 0 
     512            for v in windDict[w]: 
     513                vm1 = v - 1 
     514                off = vm1 >> 3 
     515                bit = vm1 & 0x7 
     516                msk = 1 << bit 
     517                bmapseg[off] |= msk 
     518                maxoff = max(off, maxoff) 
     519            bmapseg = bmapseg[0:maxoff+1] 
     520            bmap += chr(w) + chr(maxoff+1) + bmapseg 
     521         
     522        strio.write(str(bmap)) 
     523     
     524    def decode(self, strio, length=None): 
     525        """ 
     526        Decode an NSEC/NSEC3 type bitmap into a string 
     527        representation of type names. 
     528        """ 
     529        self.type_bitmaps = "" 
     530        if length == None: 
     531            return 
     532 
     533        type_bitmaps = bytearray() 
     534        l = struct.calcsize(self.fmt) 
     535        parsed_length = 0 
     536        while parsed_length < length: 
     537            buff = readPrecisely(strio, l) 
     538            wb_num, bm_len = struct.unpack(self.fmt, buff) 
     539            assert parsed_length + 2 + bm_len <= length 
     540            bm = readPrecisely(strio, bm_len) 
     541            byteNum = -1 
     542            for b in bm: 
     543                byteNum += 1 
     544                ob = ord(b) 
     545                if ob == 0: 
     546                    continue 
     547                 
     548                for v in range(8): 
     549                    msk = 1<<v 
     550                    if ob & msk: 
     551                        val = wb_num*256 + byteNum*8 + v + 1 
     552                        mnu = QUERY_TYPES.get(val, None) 
     553                        if not mnu: 
     554                            mnu = 'TYPE' + str(val) 
     555                        type_bitmaps += (mnu + ' ')                         
     556             
     557            parsed_length += 2 + bm_len 
     558             
     559        self.type_bitmaps = str(type_bitmaps[0:-1]) 
     560 
     561    def __eq__(self, other): 
     562        if isinstance(other, TypeBitmaps): 
     563            return self.string == other.string 
     564        return False 
     565 
     566    def __hash__(self): 
     567        return hash(self.string) 
     568 
     569    def __str__(self): 
     570        return self.string 
     571 
    374572class Query: 
    375573    """ 
    376574    Represent a single DNS query. 
     
    434632        return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 
    435633 
    436634 
    437 class RRHeader(tputil.FancyEqMixin): 
     635     
     636class OPTHeader(tputil.FancyEqMixin): 
    438637    """ 
     638    A OPT record header. 
     639 
     640    @cvar fmt: C{str} specifying the byte format of an OPT Header. 
     641 
     642    @ivar name: Root (0, 8-bits) 
     643    @ivar type: 41 (OPT Record) 
     644    @ivar payload: An object that implements the IEncodable interface 
     645    @ivar auth: Whether this header is authoritative or not. 
     646    """ 
     647 
     648    implements(IEncodable) 
     649 
     650    compareAttributes = ('name', 'type', 'payload', 'auth') 
     651 
     652    fmt = "!H" 
     653 
     654    name = None 
     655    type = None 
     656    payload = None 
     657 
     658    #OPTHeader _really_ has no ttl or rdlength, but the 
     659    #existence of the attributes is required. 
     660    ttl = None 
     661    rdlength = None 
     662 
     663    cachedResponse = None 
     664 
     665    def __init__(self, payload=None, auth=False): 
     666        """ 
     667        @type name: C{str} 
     668        @param name: Root (0) 
     669 
     670        @type type: C{int} 
     671        @param type: Query type 41. 
     672 
     673        @type payload: An object implementing C{IEncodable} 
     674        @param payload: The OPT payload 
     675        """ 
     676        assert (payload is None) or (payload.TYPE == OPT) 
     677 
     678        self.name = 0 
     679        self.type = OPT 
     680        self.payload = payload 
     681        self.auth = auth 
     682 
     683    def encode(self, strio, compDict=None): 
     684        strio.write(struct.pack('!B', 0)) 
     685        strio.write(struct.pack(self.fmt, self.type)) 
     686        if self.payload: 
     687            prefix = strio.tell() 
     688            self.payload.encode(strio, compDict) 
     689            aft = strio.tell() 
     690            strio.seek(prefix - 2, 0) 
     691            strio.write(struct.pack('!H', aft - prefix)) 
     692            strio.seek(aft, 0) 
     693 
     694    def decode(self, strio, length = None): 
     695        self.name.decode(strio) 
     696        l = struct.calcsize(self.fmt) 
     697        buff = readPrecisely(strio, l) 
     698        r = struct.unpack(self.fmt, buff) 
     699        self.type = r[0] 
     700 
     701    def isAuthoritative(self): 
     702        return self.auth 
     703 
     704    def __str__(self): 
     705        return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 
     706 
     707    @staticmethod 
     708    def factory(strio, auth=False): 
     709        ''' 
     710        reads enough of the stream to figure out if what is there is 
     711        an OPTHeader or an RRHeader 
     712        ''' 
     713        beginPos = strio.tell() 
     714        name = Name() 
     715        name.decode(strio) 
     716        type = struct.unpack(OPTHeader.fmt, readPrecisely(strio, 2))[0] 
     717         
     718        if len(name.name) == 0 and type == OPT: 
     719            return OPTHeader() 
     720        else: 
     721            #back up to the beginning and try again 
     722            strio.seek(beginPos, 0) 
     723            rrh = RRHeader(auth=auth) 
     724            rrh.decode(strio) 
     725            return rrh 
     726         
     727    __repr__ = __str__ 
     728     
     729     
     730class RRHeader(OPTHeader): 
     731    """ 
    439732    A resource record header. 
    440733 
    441734    @cvar fmt: C{str} specifying the byte format of an RR. 
     
    445738    @ivar cls: The query class of the original request. 
    446739    @ivar ttl: The time-to-live for this record. 
    447740    @ivar payload: An object that implements the IEncodable interface 
    448  
    449     @ivar auth: A C{bool} indicating whether this C{RRHeader} was parsed from an 
    450         authoritative message. 
     741    @ivar auth: Whether this header is authoritative or not. 
    451742    """ 
    452743 
    453744    implements(IEncodable) 
     
    10501341 
    10511342    fancybasename = 'SRV' 
    10521343    compareAttributes = ('priority', 'weight', 'target', 'port', 'ttl') 
    1053     showAttributes = ('priority', 'weight', ('target', 'target', '%s'), 'port', 'ttl') 
     1344    showAttributes = ('priority', 'weight',  
     1345                      ('target', 'target', '%s'), 'port', 'ttl') 
    10541346 
    10551347    def __init__(self, priority=0, weight=0, port=0, target='', ttl=None): 
    10561348        self.priority = int(priority) 
     
    14691761        return hash(tuple(self.data)) 
    14701762 
    14711763 
     1764class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1765    """ 
     1766    EDNS0 Option record. 
     1767     
     1768    @type payload_size: C{int} 
     1769    @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 
     1770        network can handle. 
     1771     
     1772    @type dnssecOk: C{bool} 
     1773    @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 
     1774        validation (and set the AD bit if the response validates). 
     1775         
     1776    @type version: C{int} 
     1777    @ivar version: The version of DNSSEC used. Currently only version 0  
     1778        is defined. 
     1779    """ 
     1780    implements(IEncodable, IRecord) 
     1781    TYPE = OPT 
     1782    fmt = '!HBBHH' 
     1783     
     1784    fancybasename = 'OPT' 
     1785    showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 
     1786    compareAttributes = ('payload_size', 'flags', 'version') 
     1787     
     1788    def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 
     1789        self.payload_size = payload_size 
     1790        self.version = version 
     1791        self.flags = (dnssecOk & 1) << 15 
     1792         
     1793    def encode(self, strio, compDict = None): 
     1794        OPTHeader().encode(strio) 
     1795        strio.write(struct.pack('!H', self.payload_size)) 
     1796        strio.write(struct.pack('!B', 0)) # high order 0 
     1797        strio.write(struct.pack('!B', self.version)) 
     1798        strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 
     1799        strio.write(struct.pack('!H', 0)) # Data length: 0 
     1800         
     1801    def decode(self, strio, length=None): 
     1802        ''' 
     1803        are OPT Records always 0 rdlength? 
     1804        ''' 
     1805        l = struct.calcsize(self.fmt) 
     1806        buff = readPrecisely(strio, l) 
     1807        r = struct.unpack(self.fmt, buff) 
     1808        self.payload_size, z, self.version, self.flags, length = r 
     1809        assert length == 0 
     1810         
     1811    def __hash__(self): 
     1812        return hash((self.payload_size, self.version, self.flags)) 
    14721813 
     1814class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1815    """ 
     1816    DNSSEC RRSIG record.  See RFC 4034 for details. 
     1817     
     1818    @type type_covered: C{int} 
     1819    @ivar type_covered: Identifies the type of the RRset that this RRSIG covers.  
     1820     
     1821    @type algo: C{int} 
     1822    @ivar algo: Identifies the crypto algorithm type used to create the signature. 
     1823        (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 
     1824     
     1825    @type labels: C{int} 
     1826    @ivar labels: Specifies the number of labels in the original RRSIG RR  
     1827        owner name. A validator can use this to determine whether the answer  
     1828        was synthesized from a wildcard. 
     1829     
     1830    @type original_ttl: C{int} 
     1831    @ivar original_ttl: Specifies the TTL of the covered RRset as it appears  
     1832        in the authoritative zone. 
     1833     
     1834    @type sig_expiration: C{int}  
     1835    @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 
     1836        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1837     
     1838    @type sig_inception: C{int}  
     1839    @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 
     1840        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1841     
     1842    @type key_tag: C{int} 
     1843    @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates  
     1844        this signature, in network byte order. See RFC 4034 App B. 
     1845     
     1846    @type signers_name: L{Name} 
     1847    @ivar signers_name: Identifies the owner name of the DNSKEY RR that a  
     1848        validator should use to validate this signature. Must not use DNS  
     1849        name compression. 
     1850     
     1851    @type signature: L{Sigstr} 
     1852    @ivar signature: Contains the cryptographic signature that covers the RRSIG 
     1853        RDATA (excluding the Signature field and the RRset specified by the  
     1854        RRSIG owner name, RRSIG class and RRSIG Type Covered fields. 
     1855     
     1856    @type ttl: C{int} 
     1857    @ivar ttl: The maximum number of seconds which this record should be 
     1858        cached. 
     1859    """ 
     1860    implements(IEncodable, IRecord) 
     1861    TYPE = RRSIG 
     1862    fmt = '!HBBIIIH' 
     1863     
     1864    fancybasename = 'RRSIG' 
     1865    showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1866                         ('_sig_expiration', 'sig_expiration', '%s'), 
     1867                         ('_sig_inception', 'sig_inception', '%s'), 
     1868                         'key_tag',  
     1869                         ('signers_name', 'signers_name', '%s'),  
     1870                         ('_signature', 'signature', '%s'), 'ttl') 
     1871    compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1872                         'sig_expiration', 'sig_inception', 'key_tag',  
     1873                         'signers_name', 'signature', 'ttl') 
     1874     
     1875    _sig_expiration = property(lambda self: str(self.sig_expiration)) 
     1876    _sig_inception = property(lambda self: str(self.sig_inception)) 
     1877    _signature = property(lambda self: self.signature.string) 
     1878     
     1879    def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0,  
     1880                 sig_expiration='', sig_inception='', key_tag=0,  
     1881                 signers_name='', signature='', ttl=None): 
     1882        self.type_covered = type_covered 
     1883        self.algo = algo 
     1884        self.labels = labels 
     1885        self.original_ttl = original_ttl 
     1886        self.sig_expiration = DateSNA(sig_expiration) 
     1887        self.sig_inception = DateSNA(sig_inception) 
     1888        self.key_tag = key_tag 
     1889        self.signers_name = Name(signers_name) 
     1890        self.signature = Sigstr(signature) 
     1891        self.ttl = str2time(ttl) 
     1892         
     1893    def encode(self, strio, compDict = None): 
     1894        strio.write(struct.pack(self.fmt,  
     1895                                self.type_covered, 
     1896                                self.algo,  
     1897                                self.labels, 
     1898                                self.original_ttl, 
     1899                                self.sig_expiration.asInt(), 
     1900                                self.sig_inception.asInt(), 
     1901                                self.key_tag)) 
     1902        self.signers_name.encode(strio, None) 
     1903        self.signature.encode(strio, compDict)         
     1904         
     1905    def decode(self, strio, length=None): 
     1906        start = strio.tell() 
     1907        l = struct.calcsize(self.fmt) 
     1908        buff = readPrecisely(strio, l) 
     1909        r = struct.unpack(self.fmt, buff)         
     1910        self.type_covered, self.algo, self.labels, self.original_ttl, \ 
     1911            sig_expiration, sig_inception, self.key_tag = r  
     1912        self.sig_expiration = DateSNA.fromInt(sig_expiration) 
     1913        self.sig_inception = DateSNA.fromInt(sig_inception) 
     1914        self.signers_name.decode(strio) 
     1915        here = strio.tell() 
     1916        self.signature.decode(strio, length + start - here if length else None) 
     1917                 
     1918    def __hash__(self): 
     1919        return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 
     1920                     self.sig_expiration, self.sig_inception, self.key_tag, 
     1921                     self.signers_name, self.signature))     
     1922 
     1923class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1924    """ 
     1925    A DNSSEC DS record. 
     1926     
     1927    @type key_tag: C{int} 
     1928    @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS  
     1929        record. 
     1930     
     1931    @type algo: C{int} 
     1932    @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this  
     1933        DS record.     
     1934 
     1935    @type digest_type: C{int} 
     1936    @ivar digest_type: Identifies the algorithm used to construct the digest  
     1937        field. 
     1938     
     1939    @type digest: L{Sigstr} 
     1940    @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by  
     1941        the algorithm identified by the digest_type field. 
     1942 
     1943    @type ttl: C{int} 
     1944    @ivar ttl: The maximum number of seconds which this record should be 
     1945        cached.     
     1946    """ 
     1947    implements(IEncodable, IRecord) 
     1948    TYPE = DS 
     1949    fmt = '!HBB' 
     1950     
     1951    fancybasename = 'DS' 
     1952    showAttributes = ('key_tag', 'algo', 'digest_type', ('_digest', 'digest', '%s'), 'ttl') 
     1953    compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 
     1954     
     1955    _digest = property(lambda self: self.digest.string) 
     1956 
     1957    def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 
     1958        self.key_tag = key_tag 
     1959        self.algo = algo 
     1960        self.digest_type = digest_type 
     1961        self.digest = Sigstr(digest) 
     1962        self.ttl = str2time(ttl) 
     1963         
     1964    def encode(self, strio, compDict = None): 
     1965        strio.write(struct.pack(self.fmt,  
     1966                                self.key_tag, 
     1967                                self.algo,  
     1968                                self.digest_type)) 
     1969        self.digest.encode(strio, None) 
     1970         
     1971    def decode(self, strio, length=None): 
     1972        start = strio.tell() 
     1973        l = struct.calcsize(self.fmt) 
     1974        buff = readPrecisely(strio, l) 
     1975        r = struct.unpack(self.fmt, buff)         
     1976        self.key_tag, self.algo, self.digest_type = r         
     1977        here = strio.tell() 
     1978        self.digest.decode(strio, length + start - here if length else None) 
     1979                 
     1980    def __hash__(self): 
     1981        return hash((self.key_tag, self.algo, self.digest_type, self.digest))     
     1982 
     1983class Record_DNSKEY(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1984    """ 
     1985    A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 
     1986     
     1987    @type flags: C{int} 
     1988    @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 
     1989        DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 
     1990        the name of a zone.  If bit 7 has value 0, then the DNSKEY record 
     1991        holds some other type of DNS public key and MUST NOT be used to  
     1992        verify RRSIGs that cover RRsets.   
     1993        Bit 15 is the Secure Entry Point flag. See RFC 3757.)  
     1994        All other bits are reserved and must be zero. 
     1995         
     1996    @type protocol: C{int} 
     1997    @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 
     1998        if this field does not contain 3. 
     1999     
     2000    @type algo: C{int} 
     2001    @ivar algo: Identifies the public key's cryptographic algorithm and determines 
     2002        the format of the pub_key field.  See RFC 4034 App A. 
     2003     
     2004    @type pub_key: L{Sigstr} 
     2005    @ivar pub_key: Holds the public key material. 
     2006 
     2007    @type ttl: C{int} 
     2008    @ivar ttl: The maximum number of seconds which this record should be 
     2009        cached.     
     2010    """ 
     2011    implements(IEncodable, IRecord) 
     2012    TYPE = DNSKEY 
     2013    fmt = '!HBB' 
     2014     
     2015    fancybasename = 'DNSKEY' 
     2016    showAttributes = ('flags', 'protocol', 'algo', ('_pub_key', 'pub_key', '%s'), 'ttl') 
     2017    compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 
     2018     
     2019    _pub_key = property(lambda self: self.pub_key.string) 
     2020     
     2021    def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 
     2022        self.flags = flags 
     2023        self.protocol = protocol 
     2024        self.algo = algo 
     2025        self.pub_key = Sigstr(pub_key) 
     2026        self.ttl = str2time(ttl) 
     2027         
     2028    def encode(self, strio, compDict = None): 
     2029        strio.write(struct.pack(self.fmt,  
     2030                                self.flags, 
     2031                                self.protocol,  
     2032                                self.algo)) 
     2033        self.pub_key.encode(strio, None) 
     2034         
     2035    def decode(self, strio, length=None): 
     2036        start = strio.tell() 
     2037        l = struct.calcsize(self.fmt) 
     2038        buff = readPrecisely(strio, l) 
     2039        r = struct.unpack(self.fmt, buff)         
     2040        self.flags, self.protocol, self.algo = r         
     2041        here = strio.tell() 
     2042        self.pub_key.decode(strio, length + start - here if length else None) 
     2043                 
     2044    def __hash__(self): 
     2045        return hash((self.flags, self.protocol, self.algo, self.pub_key)) 
     2046 
     2047class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2048    """ 
     2049    A DNSSEC NSEC record provides authenticated denial of existance for DNS data.  
     2050 
     2051    A DNSSEC NSEC record lists: 
     2052     
     2053        1) the next owner name in canonical ordering of the zone that contains  
     2054           authoritative data or a delegation point NS RRset. 
     2055         
     2056        2) the set of RR types present at the NSEC RR's owner name. 
     2057 
     2058    @type nxt_name: L{Name} 
     2059    @ivar nxt_name: The next owner name that has authoritative data or contains 
     2060        a delegation point NS RRset. 
     2061     
     2062    @type type_bitmaps: L{TypeBitmaps} 
     2063    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's  
     2064        owner name. 
     2065     
     2066    @type ttl: C{int} 
     2067    @ivar ttl: The maximum number of seconds which this record should be 
     2068        cached. 
     2069    """ 
     2070    implements(IEncodable, IRecord) 
     2071    TYPE = NSEC 
     2072     
     2073    fancybasename = 'NSEC' 
     2074    showAttributes = (('nxt_name', 'nxt_name', '%s'),  
     2075                      ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2076    compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 
     2077     
     2078    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2079     
     2080    def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 
     2081        self.nxt_name = Name(nxt_name) 
     2082        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2083        self.ttl = str2time(ttl) 
     2084         
     2085    def encode(self, strio, compDict = None): 
     2086        self.nxt_name.encode(strio, None) 
     2087        self.type_bitmaps.encode(strio, None) 
     2088         
     2089    def decode(self, strio, length=None): 
     2090        start = strio.tell() 
     2091        self.nxt_name.decode(strio, None) 
     2092        here = strio.tell() 
     2093        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2094                 
     2095    def __hash__(self): 
     2096        return hash((self.nxt_name, self.type_bitmaps)) 
     2097 
     2098class Record_NSEC3PARAM(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2099    """ 
     2100    A DNSSEC NSEC3PARAM record contains the NSEC3 parameters (hash algorithm, 
     2101    flags, iterations and salt) needed by authoritative servers to calculate 
     2102    hashed owner names.  The presence of an NSEC3PARAM RR at a zone apex 
     2103    indicates that the specified parameters may be used by authoritative  
     2104    servers to choose an appropriate set of NSEC3 RRs for negative responses.  
     2105 
     2106    @type hash_algo: C{int} 
     2107    @ivar hash_algo: Identifies the cryptographic hash algorithm used to  
     2108        construct the hash value. 
     2109     
     2110    @type flags: C{int} 
     2111    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is  
     2112        the opt-out flag. If the opt-out flag is set, the NSEC3 record covers  
     2113        zero or more unsigned delegations. If the opt-out flag is clear, the  
     2114        NSEC3 record covers zero unsigned delegations. 
     2115     
     2116    @type iterations: C{int} 
     2117    @ivar iterations: Defines the nubmer of additional times the hash algorithm  
     2118        has been performed. 
     2119     
     2120    @type salt: L{Charset} 
     2121    @ivar salt: Identifies the salt value provided to the hash. 
     2122 
     2123    @type ttl: C{int} 
     2124    @ivar ttl: The maximum number of seconds which this record should be 
     2125        cached. 
     2126    """ 
     2127    implements(IEncodable, IRecord) 
     2128    TYPE = NSEC3 
     2129    fmt = '!BBH' 
     2130     
     2131    fancybasename = 'NSEC3' 
     2132    showAttributes = ('hash_algo', 'flags', 'iterations',  
     2133                      ('_salt', 'salt', '%s'), 'ttl') 
     2134    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'ttl') 
     2135     
     2136    _salt = property(lambda self: self.salt.string) 
     2137     
     2138    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', ttl=None): 
     2139        self.hash_algo = hash_algo 
     2140        self.flags = flags 
     2141        self.iterations = iterations 
     2142        self.salt = Charstr(salt) 
     2143        self.ttl = str2time(ttl) 
     2144         
     2145    def encode(self, strio, compDict = None): 
     2146        strio.write(struct.pack(self.fmt, 
     2147                                self.hash_algo, 
     2148                                self.flags, 
     2149                                self.iterations)) 
     2150        self.salt.encode(strio, None) 
     2151         
     2152    def decode(self, strio, length=None): 
     2153        start = strio.tell() 
     2154        l = struct.calcsize(self.fmt) 
     2155        buff = readPrecisely(strio, l) 
     2156        r = struct.unpack(self.fmt, buff)         
     2157        self.hash_algo, self.flags, self.iterations = r    
     2158        self.salt.decode(strio) 
     2159        here = strio.tell() 
     2160                 
     2161    def __hash__(self): 
     2162        return hash((self.hash_algo, self.flags, self.iterations, self.salt)) 
     2163     
     2164class Record_NSEC3(Record_NSEC3PARAM): 
     2165    """ 
     2166    A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of  
     2167    existence for DNS data and permits a gradual expansion of delegation-centric 
     2168    zones.  
     2169 
     2170    A DNSSEC NSEC3 record lists: 
     2171     
     2172        1) the set of RR types present at the original owner name of the NSEC RR. 
     2173 
     2174        2) the next hashed owner name in the hash order of the zone. 
     2175 
     2176    @type hash_algo: C{int} 
     2177    @ivar hash_algo: Identifies the cryptographic hash algorithm used to  
     2178        construct the hash value. 
     2179     
     2180    @type flags: C{int} 
     2181    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined  
     2182        is the opt-out flag. If the opt-out flag is set, the NSEC3 record  
     2183        covers zero or more unsigned delegations. If the opt-out flag is  
     2184        clear, the NSEC3 record covers zero unsigned delegations. 
     2185     
     2186    @type iterations: C{int} 
     2187    @ivar iterations: Defines the nubmer of additional times the hash algorithm  
     2188        has been performed. 
     2189     
     2190    @type salt: L{Charset} 
     2191    @ivar salt: Identifies the salt value provided to the hash. 
     2192     
     2193    @type nxt_hash_owner_name: L{Charset} 
     2194    @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone  
     2195        in hash order. 
     2196     
     2197    @type type_bitmaps: L{TypeBitmaps} 
     2198    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's  
     2199        original owner name. 
     2200     
     2201    @type ttl: C{int} 
     2202    @ivar ttl: The maximum number of seconds which this record should be 
     2203        cached. 
     2204    """ 
     2205    implements(IEncodable, IRecord) 
     2206    TYPE = NSEC3 
     2207    fmt = '!BBH' 
     2208     
     2209    fancybasename = 'NSEC3' 
     2210    showAttributes = ('hash_algo', 'flags', 'iterations',  
     2211                      ('_salt', 'salt', '%s'),  
     2212                      ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'),  
     2213                      ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2214    compareAttributes = ('hash_algo', 'flags', 'iterations',  
     2215                         'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 
     2216     
     2217    _salt = property(lambda self: self.salt.string) 
     2218    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2219     
     2220    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='',  
     2221                 nxt_hash_owner='', type_bitmaps=None, ttl=None): 
     2222        Record_NSEC3PARAM.__init__(self, hash_algo, flags, iterations, salt, ttl) 
     2223        self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 
     2224        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2225         
     2226    def encode(self, strio, compDict = None): 
     2227        Record_NSEC3PARAM.encode(self, strio, compDict) 
     2228        self.nxt_hash_owner_name.encode(strio, None) 
     2229        self.type_bitmaps.encode(strio, None) 
     2230         
     2231    def decode(self, strio, length=None): 
     2232        start = strio.tell() 
     2233        Record_NSEC3PARAM.decode(self, strio, compDict) 
     2234        self.nxt_hash_owner_name.decode(strio) 
     2235        here = strio.tell() 
     2236        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2237                 
     2238    def __hash__(self): 
     2239        return hash((self.hash_algo, self.flags, self.iterations, self.salt, 
     2240                     self.nxt_hash_owner_name, self.type_bitmaps)) 
     2241 
    14732242# This is a fallback record 
    14742243class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 
    14752244    """ 
     
    15462315    queries = answers = add = ns = None 
    15472316 
    15482317    def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 
    1549                        auth=0, rCode=OK, trunc=0, maxSize=512): 
     2318                 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 
    15502319        self.maxSize = maxSize 
    15512320        self.id = id 
    15522321        self.answer = answer 
    15532322        self.opCode = opCode 
    1554         self.auth = auth 
    1555         self.trunc = trunc 
    1556         self.recDes = recDes 
    1557         self.recAv = recAv 
     2323        self.auth = auth            #AA - Authoritative Answer 
     2324        self.trunc = trunc          #TC - TrunCated 
     2325        self.recDes = recDes        #RD - Recursion Desired 
     2326        self.recAv = recAv          #RA - Recursion Available 
     2327        self.authData = authData    #AD - Authentic Data 
     2328        self.chkDis = chkDis        #CD - Checking Disabled 
    15582329        self.rCode = rCode 
    15592330        self.queries = [] 
    15602331        self.answers = [] 
     
    15992370                 | ((self.auth & 1 ) << 2 ) 
    16002371                 | ((self.trunc & 1 ) << 1 ) 
    16012372                 | ( self.recDes & 1 ) ) 
    1602         byte4 = ( ( (self.recAv & 1 ) << 7 ) 
     2373        byte4 = (  ((self.recAv & 1 ) << 7 ) 
     2374                  |((self.authData & 1 ) << 5 ) 
     2375                  |((self.chkDis & 1 ) << 4 ) 
    16032376                  | (self.rCode & 0xf ) ) 
    16042377 
    16052378        strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, 
     
    16192392        self.trunc = ( byte3 >> 1 ) & 1 
    16202393        self.recDes = byte3 & 1 
    16212394        self.recAv = ( byte4 >> 7 ) & 1 
     2395        self.authData = ( byte4 >> 5 ) & 1 
     2396        self.chkDis = ( byte4 >> 4 ) & 1 
    16222397        self.rCode = byte4 & 0xf 
    16232398 
    16242399        self.queries = [] 
     
    16372412 
    16382413    def parseRecords(self, list, num, strio): 
    16392414        for i in range(num): 
    1640             header = RRHeader(auth=self.auth) 
    16412415            try: 
    1642                 header.decode(strio) 
     2416                header = OPTHeader.factory(strio, auth=self.auth) 
    16432417            except EOFError: 
    16442418                return 
    16452419            t = self.lookupRecordType(header.type) 
     
    17492523            query, or errbacked with any errors that could happen (exceptions 
    17502524            during writing of the query, timeout errors, ...). 
    17512525        """ 
    1752         m = Message(id, recDes=1) 
     2526        dnssecConfig = self.controller.dnssecConfig 
     2527        chkDis = dnssecConfig.chkDis 
     2528        m = Message(id, recDes=dnssecConfig.recDes, chkDis=chkDis) 
    17532529        m.queries = queries 
     2530        if dnssecConfig.ednsEnabled: 
     2531            m.additional = [Record_OPT(payload_size = dnssecConfig.maxUdpPktSz, 
     2532                                       version = dnssecConfig.version, 
     2533                                       dnssecOk = dnssecConfig.dnssecOk)] 
    17542534 
    17552535        try: 
    17562536            writeMessage(m) 
     
    18042584        self.transport.write(message.toStr(), address) 
    18052585 
    18062586    def startListening(self): 
    1807         self._reactor.listenUDP(0, self, maxPacketSize=512) 
     2587        maxPacketSize = 512 
     2588        if self.controller.dnssecConfig.ednsEnabled: 
     2589            maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 
     2590        self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 
    18082591 
    18092592    def datagramReceived(self, data, addr): 
    18102593        """ 
  • 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 
  • 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 
     13bob.novas@shinkuro.com 
     14""" 
     15 
     16import calendar, time 
     17 
     18class SNA(object): 
     19    """ 
     20    implements RFC 1982 - DNS Serial Number Arithmetic 
     21    """ 
     22    SERIAL_BITS = 32 
     23    MODULOVAL = 2**SERIAL_BITS 
     24    HLFRNG = 2**(SERIAL_BITS-1) 
     25    MAXADD = (2**(SERIAL_BITS-1)-1) 
     26     
     27    def __init__(self, number): 
     28        self._number = int(number)%self.MODULOVAL 
     29         
     30    def __repr__(self): 
     31        return str(self._number) 
     32     
     33    def asInt(self): 
     34        return self._number 
     35         
     36    def eq(self, sna2): 
     37        assert isinstance(sna2, SNA) 
     38        return sna2._number == self._number 
     39     
     40    def lt(self, sna2): 
     41        assert isinstance(sna2, SNA) 
     42        return (not self.eq(sna2) and  
     43               ((self._number < sna2._number) and  
     44                ((sna2._number - self._number) < self.HLFRNG) or 
     45               (self._number > sna2._number) and  
     46                ((self._number - sna2._number) > self.HLFRNG))) 
     47 
     48    def gt(self, sna2): 
     49        assert isinstance(sna2, SNA) 
     50        return (not self.eq(sna2) and  
     51               ((self._number < sna2._number) and  
     52               ((sna2._number - self._number) > self.HLFRNG) or  
     53               (self._number > sna2._number) and  
     54               ((self._number - sna2._number) < self.HLFRNG))) 
     55     
     56    def le(self, sna2): 
     57        return self.eq(sna2) or self.lt(sna2) 
     58     
     59    def ge(self, sna2): 
     60        return self.eq(sna2) or self.gt(sna2) 
     61 
     62    def add(self, sna2): 
     63        assert isinstance(sna2, SNA) 
     64        if sna2.le(SNA(self.MAXADD)): 
     65            return SNA( (self._number + sna2._number)%self.MODULOVAL ) 
     66        else: 
     67            raise ArithmeticError 
     68         
     69    def __hash__(self): 
     70        return hash(self._number) 
     71     
     72    __eq__  = eq 
     73    __lt__  = lt 
     74    __gt__  = gt 
     75    __le__  = le 
     76    __ge__  = ge 
     77    __add__ = add 
     78         
     79    @staticmethod 
     80    def max(snaList): 
     81        """ 
     82        this takes a list of sna's from which it will pick the sn  
     83        with the highest value 
     84        """ 
     85        if len(snaList) == 0: 
     86            return None 
     87        trialMax = snaList[0] 
     88        for s in snaList[1:]: 
     89            if not trialMax: 
     90                trialMax = s 
     91            elif s and s > trialMax: 
     92                trialMax = s 
     93        return trialMax 
     94 
     95class DateSNA(SNA): 
     96    """ 
     97    implements DNS Serial Number Arithmetic 
     98    for dates 'YYYYMMDDHHMMSS' per RFC 4034 P3.1.5 
     99    """ 
     100    fmt = '%Y%m%d%H%M%S' 
     101 
     102    def __init__(self, utcDateTime=''): 
     103        ''' 
     104        accept a UTC date/time string as YYMMDDHHMMSS 
     105        and convert it to seconds since the epoch 
     106        ''' 
     107        if not utcDateTime: 
     108            utcDateTime = '19700101000000' 
     109        dtstruct = time.strptime(utcDateTime, DateSNA.fmt) 
     110        assert dtstruct.tm_year < 1970+136 
     111        secondsSinceE = calendar.timegm(dtstruct) 
     112        super(DateSNA, self).__init__(secondsSinceE) 
     113     
     114    def add(self, sna2): 
     115        if not isinstance(sna2, SNA): 
     116            return NotImplemented 
     117         
     118        if (sna2.le(SNA(self.MAXADD)) and  
     119            (self._number + sna2._number < self.MODULOVAL)): 
     120            sna = SNA((self._number + sna2._number)%self.MODULOVAL) 
     121            return DateSNA.fromSNA(sna) 
     122        else: 
     123            raise ArithmeticError 
     124     
     125    def asDate(self): 
     126        dtstruct = time.gmtime(self._number) 
     127        return time.strftime(DateSNA.fmt, dtstruct) 
     128     
     129    @staticmethod 
     130    def fromSNA(sna): 
     131        assert isinstance(sna, SNA) 
     132        d = DateSNA() 
     133        d._number = sna._number 
     134        return d 
     135     
     136    @staticmethod 
     137    def fromInt(i): 
     138        return DateSNA.fromSNA(SNA(i)) 
     139         
     140    def __str__(self): 
     141        return self.asDate() 
     142 
  • twisted/names/test/test_client.py

     
    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): 
     
    428430        # Disconnecting should remove the protocol from the connection list: 
    429431        protocol.connectionLost(None) 
    430432        self.assertNotIn(protocol, resolver.connections) 
     433         
     434         
     435    def _edns0ConfigurationTest(self, reactor, resolver): 
     436        """ 
     437        A Resolver created with edns0 sends an OPT record as part of the  
     438        query indicating the maxUdpPktSz and EDNS version supported  
     439        (only EDNS version 0 - the default - is defined by spec). 
     440         
     441        In addition, check that the message flag bits (DO, CD, RC) agree 
     442        with the flags set in the resolver. 
     443        """ 
     444        #make sure EDNS is enabled 
     445        self.assertTrue(resolver.dnssecConfig.ednsEnabled) 
     446         
     447        d = resolver._query(('example.com', 53), 
     448                            [Query('foo.example.com',dns.A, dns.IN)],  
     449                            30) 
     450                    
     451        # A UDP port should have been started 
     452        portNumber, transport = reactor.udpPorts.popitem() 
     453         
     454        # and a DNS packet sent 
     455        [(packet, address)] = transport._sentPackets 
     456         
     457        msg = Message() 
     458        msg.fromStr(packet) 
     459         
     460        # the query should have an additional OPT Header with  
     461        # version == 0 and payload_size as defined by the resolver's  
     462        # dnssecConfig and DO should be set 
     463        self.assertEqual(len(msg.additional), 1) 
     464        additional = msg.additional[0] 
     465        payload = additional.payload 
     466        dnssecConfig = resolver.dnssecConfig 
     467        self.assertEqual(additional.type, dns.OPT) 
     468        self.assertEqual(payload.version, dnssecConfig.version) 
     469        self.assertEqual(payload.payload_size, dnssecConfig.maxUdpPktSz) 
     470        #payload.flags bit 15 is DO, should equal resolver.dnssecOk 
     471        self.assertEqual(not not(payload.flags & 0x8000), dnssecConfig.dnssecOk) 
     472         
     473        # the rest of the query should be as above also 
     474        self.assertEqual(msg.queries, [Query('foo.example.com', dns.A, dns.IN)]) 
     475        self.assertEqual(msg.answers, []) 
     476        self.assertEqual(msg.authority, []) 
    431477 
     478        # the message header flags should be set as per the resolver's  
     479        # dnssecConfig settings 
     480        self.assertEqual(msg.chkDis, dnssecConfig.chkDis) 
     481        self.assertEqual(msg.recDes, dnssecConfig.recDes) 
     482         
     483        response = [] 
     484        d.addCallback(response.append) 
     485        self.assertEqual(response, []) 
     486         
     487        # Once a reply is received, the Deferred should fire. 
     488        # Make the flag bits in the message agree with what you asked for 
     489        del msg.queries[:] 
     490        msg.answer = 1 
     491        msg.answers.append(dns.RRHeader('foo.example.com',  
     492                                        payload=dns.Record_A('5.8.13.21'))) 
     493        #if you requested DO, say you got AD 
     494        msg.authData = dnssecConfig.dnssecOk  
     495        msg.chkDis = dnssecConfig.chkDis 
     496        msg.recDes = dnssecConfig.recDes 
     497        transport._protocol.datagramReceived(msg.toStr(), ('1.1.2.4', 1053)) 
     498        return response[0] 
    432499 
     500     
     501    def test_dnssecEnabled(self): 
     502        """ 
     503        A query sent with DNSSEC Enabled has an additional OPT record with  
     504        DO set. Such a query returns a 4-tuple as a result, with the 4th 
     505        member of the tuple being the message with the header bits set as 
     506        set in the original query. 
     507        """ 
     508        # Create a resolver with EDNS0, max packet size = 4096,  
     509        # and dnssecOk, chkDis and recDes = True 
     510        maxPacketSize = 4096 
     511        dsc = DnssecConfig(ednsEnabled=True,  
     512                           maxUdpPktSz=maxPacketSize, 
     513                           dnssecOk=True,  # DO 
     514                           chkDis=True,    # CD 
     515                           recDes=True)    # RC 
    433516 
     517        reactor = MemoryReactor() 
     518        resolver = client.Resolver(servers=[('example.com', 53)],  
     519                                   reactor=reactor,  
     520                                   dnssecConfig=dsc) 
     521          
     522        message = self._edns0ConfigurationTest(reactor, resolver) 
     523         
     524        #check that a resolver with dnssecOk returns a 4-tuple with the  
     525        #header set as in the query 
     526        answer, authority, additional, message = resolver.filterAnswers(message) 
     527        self.assertEqual(answer, [dns.RRHeader('foo.example.com',  
     528                                  payload=dns.Record_A('5.8.13.21', ttl=0))]) 
     529        self.assertEqual(authority, []) 
     530        self.assertEqual(additional, []) 
     531        self.assertIsInstance(message, dns.Message) 
     532        self.assertTrue(message.authData) 
     533        self.assertTrue(message.chkDis) 
     534        self.assertTrue(message.recDes) 
     535     
     536     
     537    def test_dnssecDisabled(self): 
     538        """ 
     539        A query sent with DNSSEC Disabled but EDNS enabled has an additional  
     540        OPT record with DO clear. Such a query returns a 3-tuple as a result. 
     541        """ 
     542         
     543        # Create a resolver with EDNS0, max packet size = 4096,  
     544        # and dnssecOk = False, but recDes = True 
     545        maxPacketSize = 4096 
     546        dsc = DnssecConfig(ednsEnabled=True,  
     547                           maxUdpPktSz=maxPacketSize, 
     548                           dnssecOk=False, # not DO 
     549                           recDes=True)    # RC 
     550 
     551        reactor = MemoryReactor() 
     552        resolver = client.Resolver(servers=[('example.com', 53)],  
     553                                   reactor=reactor,  
     554                                   dnssecConfig=dsc) 
     555          
     556        message = self._edns0ConfigurationTest(reactor, resolver) 
     557         
     558        #check that a resolver with dnssecOk == False returns a 3-tuple 
     559        #containing the right stuff. Note - no access to header info in this case 
     560        answer, authority, additional = resolver.filterAnswers(message) 
     561        self.assertEqual(answer,  
     562                         [dns.RRHeader('foo.example.com',  
     563                                    payload=dns.Record_A('5.8.13.21', ttl=0))]) 
     564        self.assertEqual(authority, []) 
     565        self.assertEqual(additional, []) 
     566         
     567 
    434568class ClientTestCase(unittest.TestCase): 
    435569 
    436570    def setUp(self): 
     
    658792        return d 
    659793 
    660794 
     795    def test_lookupDNSKey(self): 
     796        """ 
     797        See L{test_lookupAddress} 
     798        """ 
     799        d = client.lookupDNSKey(self.hostname) 
     800        d.addCallback(self.checkResult, dns.DNSKEY) 
     801        return d 
     802 
     803 
     804    def test_lookupDS(self): 
     805        """ 
     806        See L{test_lookupAddress} 
     807        """ 
     808        d = client.lookupDS(self.hostname) 
     809        d.addCallback(self.checkResult, dns.DS) 
     810        return d 
     811 
     812 
     813    def test_lookupNSEC(self): 
     814        """ 
     815        See L{test_lookupAddress} 
     816        """ 
     817        d = client.lookupNSEC(self.hostname) 
     818        d.addCallback(self.checkResult, dns.NSEC) 
     819        return d 
     820 
     821 
     822    def test_lookupNSEC3(self): 
     823        """ 
     824        See L{test_lookupAddress} 
     825        """ 
     826        d = client.lookupNSEC3(self.hostname) 
     827        d.addCallback(self.checkResult, dns.NSEC3) 
     828        return d 
     829 
     830 
     831    def test_lookupNSEC3Param(self): 
     832        """ 
     833        See L{test_lookupAddress} 
     834        """ 
     835        d = client.lookupNSEC3Param(self.hostname) 
     836        d.addCallback(self.checkResult, dns.NSEC3PARAM) 
     837        return d 
     838 
     839 
     840    def test_lookupRRSIG(self): 
     841        """ 
     842        See L{test_lookupAddress} 
     843        """ 
     844        d = client.lookupRRSIG(self.hostname) 
     845        d.addCallback(self.checkResult, dns.RRSIG) 
     846        return d 
     847 
     848 
    661849class ThreadedResolverTests(unittest.TestCase): 
    662850    """ 
    663851    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"] 
    192  
     195    sigs = ["Qm12VZVaZgKS0/DZx35SGECDwPiTTf3ngChb7OkgSv5iupVmJGhPWudm /18qBSXKyv9hxMlEXFFgpBieNqLfSBkP1bwKnlqPfr1Hx7ctDwDUpkT3 cS8u/ms9yo3Fu1ybpO4Hfsb1HbA2N3zzQnjWKnyk26AAQSz8KgjNTFzD tJM=", 
     196            "ZH2kahMD1g2WOieIotAcBwB0e/o30Zq6YR//M/xwP1ktkYuclmcR56iv XiR3QFWqmN5Xz3YpgmM4tZkjIeSMp2doYa7XYORZ7OpzG7oyfo8IoXxc j1VGDeAn1CeNCpBtoSGapRABG1gjY7oeRj/smPQPp2Gkf79+WZfuzRom /t4=",  
     197            "AZpaboyNQAmbnBO1K66QmZ0c+VCdY/wu9QpEdRnMpnIOLPD28pNVu6hk GQMz6eg5WYkPYDdJK+1D/oyAQkDmRgn10+O9EdeFDyLqYqq/htEAvDm4 CziMSOpD/mkg1bSWCZ2mdln/GBk8WooCeeM7LEHmRjmHMMj0xb6N4SKa MEc=",  
     198            "AwEAAbi5VQa3x+R3WQouBDNts+ZX2zIKZNoj9pzl7ew446kI/2omv3j6 c/4RQ6VneYE3mK7r0fFIKhVagmiRroFO1rRUJ8sVidssZ35CldE0sju+ E7wymVg3tV+ZUUO/+5v6Sfj+tw3rlp6eKqm7EGKKM88t+KuXiGYMu0Vw Rm9OUO1n",     
     199            "AwEAAbmTL+kuV45kAxGN//iBKz93Y6lutgxoptp+I1+PZZMsBkhm/dZj q57040Pz/Hr3f2zQX7z6fFu7/Ml3MHPH1eQDiVXDvOkeNq2x4IbCO7x+ 0p6bGYj4fw/tEfh/8dUzyzvMwfuAMsOvXza8Kh+UP4jvFc95cUuGgYus uEjUOp40PsL7EtYvAks3UssA6/OZP4w/1Z5m/VFx4PzgY0dkEuc=",     
     200            "VGPxa8A81eV1dtUxVhz9b9Jsp6FF4M5H6J0QhzbNCUTHTHjLNR2VHYfE fM+Akwo3/qKq3D6vzTfzqtyPAXP8CmGfdD8hfv0s7Hae9c7Is8usdlrk ZpoXEFMW+YVG8G9OieYViq6tBIpUvKgMVZ+oXKo63KJ/tC/yBW0H0VQP YwdzZ3ZvYRDmZDvrXoX7T0YNU+0HYHnb7g7nUECIJ/4HHg==", 
     201            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFE h9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffp Z9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55 Y1k="] 
     202    type_bitmaps = ["A MX RRSIG NSEC TYPE1234", 
     203                    "AAAA NS CNAME MX TXT RRSIG NSEC3 DNAME", 
     204                    "NSEC3 A AAAA RRSIG DS NS TYPE5000 TYPE1000 TYPE2000 TYPE3000 TYPE4000", 
     205                    None] 
     206                     
    193207    def testName(self): 
    194208        for n in self.names: 
    195209            # encode the name 
     
    276290            self.assertEqual(result.string, n) 
    277291 
    278292 
     293    def test_Sigstr(self): 
     294        """ 
     295        Test L{dns.Sigstr} encode and decode. 
     296        """ 
     297        for s in self.sigs: 
     298            # encode the signature/key 
     299            f = StringIO() 
     300            dns.Sigstr(s).encode(f) 
     301            l = f.tell() 
     302 
     303            # decode the signature/key 
     304            f.seek(0, 0) 
     305            result = dns.Sigstr() 
     306            result.decode(f,l) 
     307            #spaces are free, and dig sticks them in 
     308            self.assertEqual(result.string, s.replace(' ', '')) 
     309 
     310 
     311    def test_TypeBitmaps(self): 
     312        """ 
     313        Test L{dns.TypeBitmaps} encode and decode. 
     314        """ 
     315        typeRegex = re.compile('TYPE(\d+)') 
     316         
     317        for b in self.type_bitmaps: 
     318            # encode the type_bitmaps 
     319            f = StringIO() 
     320            dns.TypeBitmaps(b).encode(f) 
     321            l = f.tell() 
     322 
     323            # decode the type_bitmaps 
     324            f.seek(0, 0) 
     325            result = dns.TypeBitmaps() 
     326            result.decode(f,l) 
     327             
     328            def mnuVal(mnu): 
     329                mnuVal = dns.REV_TYPES.get(mnu, None) 
     330                if not mnuVal: 
     331                    m = typeRegex.match(mnu) 
     332                    if m.groups(): 
     333                        mnuVal = int(m.group(1)) 
     334                        assert mnuVal < 65536 
     335                    else: 
     336                        log.err("can't parse %s in %s" % (mnu, self.string, )) 
     337                        mnuVal = 0 
     338                return mnuVal 
     339             
     340            def sorttok(string): 
     341                if not string: 
     342                    return '' 
     343                 
     344                toks = string.split(' ') 
     345                toks.sort(key = mnuVal) 
     346                return ' '.join(toks) 
     347             
     348            self.assertEqual(result.type_bitmaps, sorttok(b)) 
     349 
     350 
    279351    def test_NAPTR(self): 
    280352        """ 
    281353        Test L{dns.Record_NAPTR} encode and decode. 
     
    439511        Initialize the controller: create a list of messages. 
    440512        """ 
    441513        self.messages = [] 
     514        self.dnssecConfig = common.DnssecConfig() 
    442515 
    443516 
    444517    def messageReceived(self, msg, proto, addr): 
     
    893966            repr(dns.UnknownRecord("foo\x1fbar", 12)), 
    894967            "<UNKNOWN data='foo\\x1fbar' ttl=12>") 
    895968 
     969    def test_dnskey(self): 
     970        """ 
     971        The repr of a L{dns.DNSKEY} instance includes the flags, protocol, 
     972        algo, pub_key and ttl fields of the record. 
     973        """ 
     974        self.assertEqual( 
     975            repr(dns.Record_DNSKEY(10, 20, 30, "foo\x1fbar", ttl=20)), 
     976            "<DNSKEY flags=10 protocol=20 algo=30 pub_key=foo\x1fbar ttl=20>") 
     977     
     978    def test_ds(self): 
     979        """ 
     980        The repr of a L{dns.DS} instance includes the key_tag, algo, digest_type, 
     981        digest and ttl fields of the record. 
     982        """ 
     983        self.assertEqual( 
     984            repr(dns.Record_DS(11, 22, 33, "foo\x1fbar1", ttl=21)), 
     985            "<DS key_tag=11 algo=22 digest_type=33 digest=foo\x1fbar1 ttl=21>") 
     986     
     987    def test_nsec(self): 
     988        """ 
     989        The repr of a L{dns.NSEC} instance includes the nxt_name, type_bitmaps 
     990        and ttl fields of the record. 
     991        """ 
     992        self.assertEqual( 
     993            repr(dns.Record_NSEC('bob', "\x1fabcd", ttl=31)), 
     994            "<NSEC nxt_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     995     
     996    def test_nsec3param(self): 
     997        """ 
     998        The repr of a L{dns.NSEC3PARAM} instance includes the hash_algo, flags,  
     999        iterations, salt and ttl fields of the record. 
     1000        """ 
     1001        self.assertEqual( 
     1002            repr(dns.Record_NSEC3PARAM(1, 2, 3, '\x12\x34', ttl=31)), 
     1003            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 ttl=31>") 
     1004     
     1005    def test_nsec3(self): 
     1006        """ 
     1007        The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, iterations, 
     1008        salt, nxt_hash_owner_name, type_bitmaps and ttl fields of the record. 
     1009        """ 
     1010        self.assertEqual( 
     1011            repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', "\x1fabcd", ttl=31)), 
     1012            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 nxt_hash_owner_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     1013     
     1014    def test_opt(self): 
     1015        """ 
     1016        The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk flag,  
     1017        and version fields of the record. (The OPT record has no ttl field.) 
     1018        """ 
     1019        self.assertEqual( 
     1020            repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 
     1021                 "<OPT payload_size=1492 flags=0x8000 version=0>") 
    8961022 
     1023    def test_rrsig(self): 
     1024        """ 
     1025        The repr of a L{dns.RRSIG} instance includes the algo, labels, original_ttl 
     1026        sig_expiration, sig_inception, key_tag, signers_name, signature and ttl  
     1027        fields of the record. 
     1028        """ 
     1029        self.assertEqual( 
     1030            repr(dns.Record_RRSIG(type_covered=dns.A, 
     1031                                  algo=2, 
     1032                                  labels=3, 
     1033                                  original_ttl=30, 
     1034                                  sig_expiration='20110101123456', 
     1035                                  sig_inception= '20110202112233', 
     1036                                  key_tag=60, 
     1037                                  signers_name='bob', 
     1038                                  signature='\x12\x34sig', 
     1039                                  ttl=70)), 
     1040                 "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 
     1041                + " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 
     1042                + " signers_name=bob signature=\x12\x34sig ttl=70>") 
    8971043 
    8981044class _Equal(object): 
    8991045    """ 
     
    9611107            cls('example.com', 123), 
    9621108            cls('example.org', 123)) 
    9631109 
     1110    def test_optheader(self): 
     1111        """ 
     1112        Two OptHeader instances comapare equal iff the have the same 
     1113        (Record_OPT) payload and auth bit. 
     1114        """ 
     1115        self._equalityTest( 
     1116            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024,  
     1117                                                 dnssecOk=True,  
     1118                                                 version=0,  
     1119                                                 ttl=30)), 
     1120            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024,  
     1121                                                 dnssecOk=True,  
     1122                                                 version=0,  
     1123                                                 ttl=30)), 
     1124            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492,  
     1125                                                 dnssecOk=False,  
     1126                                                 version=0,  
     1127                                                 ttl=40), auth=True)) 
    9641128 
    9651129    def test_rrheader(self): 
    9661130        """ 
     
    14831647            dns.UnknownRecord('foo', ttl=10), 
    14841648            dns.UnknownRecord('foo', ttl=10), 
    14851649            dns.UnknownRecord('foo', ttl=100)) 
     1650 
     1651    def test_rrsig(self): 
     1652        """ 
     1653        L(dns.RRSIG) instances compare equal iff they have the same 
     1654        type_covered, algo, labels, original_ttl, sig_expiration, sig_inception,  
     1655        key_tag, signers_name, signature, and ttl 
     1656        """ 
     1657        self._equalityTest( 
     1658            dns.Record_RRSIG(type_covered=dns.A), 
     1659            dns.Record_RRSIG(type_covered=dns.A), 
     1660            dns.Record_RRSIG(type_covered=dns.AAAA)) 
     1661        self._equalityTest( 
     1662            dns.Record_RRSIG(algo=1), 
     1663            dns.Record_RRSIG(algo=1), 
     1664            dns.Record_RRSIG(algo=2)) 
     1665        self._equalityTest( 
     1666            dns.Record_RRSIG(labels=3), 
     1667            dns.Record_RRSIG(labels=3), 
     1668            dns.Record_RRSIG(labels=4)) 
     1669        self._equalityTest( 
     1670            dns.Record_RRSIG(original_ttl=5), 
     1671            dns.Record_RRSIG(original_ttl=5), 
     1672            dns.Record_RRSIG(original_ttl=6)) 
     1673        self._equalityTest( 
     1674            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1675            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1676            dns.Record_RRSIG(sig_expiration='20110101000001')) 
     1677        self._equalityTest( 
     1678            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1679            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1680            dns.Record_RRSIG(sig_inception='20120101000001')) 
     1681        self._equalityTest( 
     1682            dns.Record_RRSIG(key_tag=11), 
     1683            dns.Record_RRSIG(key_tag=11), 
     1684            dns.Record_RRSIG(key_tag=12)) 
     1685        self._equalityTest( 
     1686            dns.Record_RRSIG(signers_name='bob'), 
     1687            dns.Record_RRSIG(signers_name='bob'), 
     1688            dns.Record_RRSIG(signers_name='joe')) 
     1689        self._equalityTest( 
     1690            dns.Record_RRSIG(signature='abcdef'), 
     1691            dns.Record_RRSIG(signature='abcdef'), 
     1692            dns.Record_RRSIG(signature='abcdefg')) 
     1693        self._equalityTest( 
     1694            dns.Record_RRSIG(ttl=10), 
     1695            dns.Record_RRSIG(ttl=10), 
     1696            dns.Record_RRSIG(ttl=20)) 
     1697         
     1698    def test_ds(self): 
     1699        """ 
     1700        L(dns.DS) instances compare equal iff they have the same 
     1701        key_tag, algo, digest_type, digest and ttl 
     1702        """ 
     1703        self._equalityTest( 
     1704            dns.Record_DS(key_tag=1), 
     1705            dns.Record_DS(key_tag=1), 
     1706            dns.Record_DS(key_tag=2)) 
     1707        self._equalityTest( 
     1708            dns.Record_DS(algo=3), 
     1709            dns.Record_DS(algo=3), 
     1710            dns.Record_DS(algo=4)) 
     1711        self._equalityTest( 
     1712            dns.Record_DS(digest_type=5), 
     1713            dns.Record_DS(digest_type=5), 
     1714            dns.Record_DS(digest_type=6)) 
     1715        self._equalityTest( 
     1716            dns.Record_DS(digest='abcdef-digest'), 
     1717            dns.Record_DS(digest='abcdef-digest'), 
     1718            dns.Record_DS(digest='abcdef-digest-f')) 
     1719        self._equalityTest( 
     1720            dns.Record_DS(ttl=10), 
     1721            dns.Record_DS(ttl=10), 
     1722            dns.Record_DS(ttl=20)) 
     1723 
     1724    def test_dnskey(self): 
     1725        """ 
     1726        L(dns.DNSKEY) instances compare equal iff they have the same 
     1727        flags, protocol, algo, pub_key and ttl 
     1728        """ 
     1729        self._equalityTest( 
     1730            dns.Record_DNSKEY(flags=1), 
     1731            dns.Record_DNSKEY(flags=1), 
     1732            dns.Record_DNSKEY(flags=2)) 
     1733        self._equalityTest( 
     1734            dns.Record_DNSKEY(protocol=3), 
     1735            dns.Record_DNSKEY(protocol=3), 
     1736            dns.Record_DNSKEY(protocol=4)) 
     1737        self._equalityTest( 
     1738            dns.Record_DNSKEY(algo=5), 
     1739            dns.Record_DNSKEY(algo=5), 
     1740            dns.Record_DNSKEY(algo=6)) 
     1741        self._equalityTest( 
     1742            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1743            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1744            dns.Record_DNSKEY(pub_key='abcdef-digest-f')) 
     1745        self._equalityTest( 
     1746            dns.Record_DNSKEY(ttl=10), 
     1747            dns.Record_DNSKEY(ttl=10), 
     1748            dns.Record_DNSKEY(ttl=20)) 
     1749 
     1750    def test_nsec(self): 
     1751        """ 
     1752        L(dns.DNSKEY) instances compare equal iff they have the same 
     1753        nxt_name, type_bitmaps and ttl 
     1754        """ 
     1755        self._equalityTest( 
     1756            dns.Record_NSEC(nxt_name="example.com"), 
     1757            dns.Record_NSEC(nxt_name="example.com"), 
     1758            dns.Record_NSEC(nxt_name="a.example.com")) 
     1759        self._equalityTest( 
     1760            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1761            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1762            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1763        self._equalityTest( 
     1764            dns.Record_NSEC(ttl=5), 
     1765            dns.Record_NSEC(ttl=5), 
     1766            dns.Record_NSEC(ttl=6)) 
     1767 
     1768    def test_nsec3param(self): 
     1769        """ 
     1770        L(dns.DNSKEY) instances compare equal iff they have the same 
     1771        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1772        """ 
     1773        self._equalityTest( 
     1774            dns.Record_NSEC3PARAM(hash_algo=1), 
     1775            dns.Record_NSEC3PARAM(hash_algo=1), 
     1776            dns.Record_NSEC3PARAM(hash_algo=2)) 
     1777        self._equalityTest( 
     1778            dns.Record_NSEC3PARAM(flags=1), 
     1779            dns.Record_NSEC3PARAM(flags=1), 
     1780            dns.Record_NSEC3PARAM(flags=2)) 
     1781        self._equalityTest( 
     1782            dns.Record_NSEC3PARAM(iterations=5), 
     1783            dns.Record_NSEC3PARAM(iterations=5), 
     1784            dns.Record_NSEC3PARAM(iterations=6)) 
     1785        self._equalityTest( 
     1786            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1787            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1788            dns.Record_NSEC3PARAM(salt="abcdefg")) 
     1789        self._equalityTest( 
     1790            dns.Record_NSEC3PARAM(ttl=5), 
     1791            dns.Record_NSEC3PARAM(ttl=5), 
     1792            dns.Record_NSEC3PARAM(ttl=6)) 
     1793 
     1794    def test_nsec3(self): 
     1795        """ 
     1796        L(dns.DNSKEY) instances compare equal iff they have the same 
     1797        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1798        """ 
     1799        self._equalityTest( 
     1800            dns.Record_NSEC3(hash_algo=1), 
     1801            dns.Record_NSEC3(hash_algo=1), 
     1802            dns.Record_NSEC3(hash_algo=2)) 
     1803        self._equalityTest( 
     1804            dns.Record_NSEC3(flags=1), 
     1805            dns.Record_NSEC3(flags=1), 
     1806            dns.Record_NSEC3(flags=2)) 
     1807        self._equalityTest( 
     1808            dns.Record_NSEC3(iterations=5), 
     1809            dns.Record_NSEC3(iterations=5), 
     1810            dns.Record_NSEC3(iterations=6)) 
     1811        self._equalityTest( 
     1812            dns.Record_NSEC3(salt="abcdef"), 
     1813            dns.Record_NSEC3(salt="abcdef"), 
     1814            dns.Record_NSEC3(salt="abcdefg")) 
     1815        self._equalityTest( 
     1816            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1817            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1818            dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 
     1819        self._equalityTest( 
     1820            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1821            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1822            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1823        self._equalityTest( 
     1824            dns.Record_NSEC3(ttl=5), 
     1825            dns.Record_NSEC3(ttl=5), 
     1826            dns.Record_NSEC3(ttl=6)) 
     1827 
     1828 
     1829                 
     1830 No newline at end of file 
  • twisted/names/test/test_names.py

     
    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/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=" 
     104                             )], 
    102105        'http.tcp.test-domain.com': [ 
    103106            dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') 
    104107        ], 
    105108        'host.test-domain.com': [ 
    106109            dns.Record_A('123.242.1.5'), 
    107110            dns.Record_A('0.255.0.255'), 
     111            dns.Record_RRSIG(dns.A, 5, 3, 86400, '20120101000000', '20120201000000', 2642, 'test-domain.com',  
     112                            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=") 
    108113        ], 
    109114        'host-two.test-domain.com': [ 
    110115# 
     
    224229        """Test DNS 'A' record queries with multiple answers""" 
    225230        return self.namesTest( 
    226231            self.resolver.lookupAddress('host.test-domain.com'), 
    227             [dns.Record_A('123.242.1.5', ttl=19283784), dns.Record_A('0.255.0.255', ttl=19283784)] 
     232            [dns.Record_A('123.242.1.5', ttl=19283784),  
     233             dns.Record_A('0.255.0.255', ttl=19283784)] 
    228234        ) 
    229235 
    230236 
     
    232238        """Test DNS 'A' record queries with edge cases""" 
    233239        return self.namesTest( 
    234240            self.resolver.lookupAddress('host-two.test-domain.com'), 
    235             [dns.Record_A('255.255.255.254', ttl=19283784), dns.Record_A('0.0.0.0', ttl=19283784)] 
     241            [dns.Record_A('255.255.255.254', ttl=19283784),  
     242             dns.Record_A('0.0.0.0', ttl=19283784)] 
    236243        ) 
    237244 
    238245 
     
    264271        """Test DNS 'HINFO' record queries""" 
    265272        return self.namesTest( 
    266273            self.resolver.lookupHostInfo('test-domain.com'), 
    267             [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', ttl=19283784)] 
     274            [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know',  
     275                              ttl=19283784)] 
    268276        ) 
    269277 
    270278    def testPTR(self): 
     
    286294        """Test additional processing for CNAME records""" 
    287295        return self.namesTest( 
    288296        self.resolver.lookupAddress('cname.test-domain.com'), 
    289         [dns.Record_CNAME('test-domain.com', ttl=19283784), dns.Record_A('127.0.0.1', ttl=19283784)] 
     297        [dns.Record_CNAME('test-domain.com', ttl=19283784),  
     298         dns.Record_A('127.0.0.1', ttl=19283784)] 
    290299    ) 
    291300 
    292301    def testMB(self): 
     
    317326        """Test DNS 'MINFO' record queries""" 
    318327        return self.namesTest( 
    319328            self.resolver.lookupMailboxInfo('test-domain.com'), 
    320             [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', ttl=19283784)] 
     329            [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box',  
     330                              ttl=19283784)] 
    321331        ) 
    322332 
    323333 
     
    325335        """Test DNS 'SRV' record queries""" 
    326336        return self.namesTest( 
    327337            self.resolver.lookupService('http.tcp.test-domain.com'), 
    328             [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl=19283784)] 
     338            [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool',  
     339                            ttl=19283784)] 
    329340        ) 
    330341 
    331342    def testAFSDB(self): 
    332343        """Test DNS 'AFSDB' record queries""" 
    333344        return self.namesTest( 
    334345            self.resolver.lookupAFSDatabase('test-domain.com'), 
    335             [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', ttl=19283784)] 
     346            [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com',  
     347                              ttl=19283784)] 
    336348        ) 
    337349 
    338350 
     
    340352        """Test DNS 'RP' record queries""" 
    341353        return self.namesTest( 
    342354            self.resolver.lookupResponsibility('test-domain.com'), 
    343             [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', ttl=19283784)] 
     355            [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text',  
     356                           ttl=19283784)] 
    344357        ) 
    345358 
    346359 
     
    348361        """Test DNS 'TXT' record queries""" 
    349362        return self.namesTest( 
    350363            self.resolver.lookupText('test-domain.com'), 
    351             [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', ttl=19283784), 
    352              dns.Record_TXT('Some more text, haha!  Yes.  \0  Still here?', ttl=19283784)] 
     364            [dns.Record_TXT('A First piece of Text', 'a SecoNd piece',  
     365                            ttl=19283784), 
     366             dns.Record_TXT('Some more text, haha!  Yes.  \0  Still here?',  
     367                            ttl=19283784)] 
    353368        ) 
    354369 
    355370 
     
    359374        """ 
    360375        return self.namesTest( 
    361376            self.resolver.lookupSenderPolicy('test-domain.com'), 
    362             [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all', ttl=19283784), 
    363             dns.Record_SPF('v=spf1 +mx a:\0colo', '.example.com/28 -all not valid', ttl=19283784)] 
     377            [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all',  
     378                            ttl=19283784), 
     379            dns.Record_SPF('v=spf1 +mx a:\0colo',  
     380                           '.example.com/28 -all not valid',  
     381                           ttl=19283784)] 
    364382        ) 
    365383 
    366384 
     
    368386        """Test DNS 'WKS' record queries""" 
    369387        return self.namesTest( 
    370388            self.resolver.lookupWellKnownServices('test-domain.com'), 
    371             [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] 
     389            [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP,  
     390                            '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] 
    372391        ) 
    373392 
    374393 
     
    381400             dns.Record_A('1.2.3.4', ttl='1S'), 
    382401             dns.Record_NS('ns1.domain', ttl='2M'), 
    383402             dns.Record_NS('ns2.domain', ttl='3H'), 
    384              dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D')] 
     403             dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool',  
     404                            ttl='4D')] 
    385405            ) 
    386406 
    387407 
     
    389409        """Test DNS 'AAAA' record queries (IPv6)""" 
    390410        return self.namesTest( 
    391411            self.resolver.lookupIPV6Address('test-domain.com'), 
    392             [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', ttl=19283784)] 
     412            [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF',  
     413                             ttl=19283784)] 
    393414        ) 
    394415 
    395416    def testA6(self): 
     
    398419            self.resolver.lookupAddress6('test-domain.com'), 
    399420            [dns.Record_A6(0, 'ABCD::4321', '', ttl=19283784), 
    400421             dns.Record_A6(12, '0:0069::0', 'some.network.tld', ttl=19283784), 
    401              dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net', ttl=19283784)] 
     422             dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF',  
     423                           'tra.la.la.net', ttl=19283784)] 
    402424         ) 
    403425 
    404426 
     
    407429        Test DNS 'AXFR' queries (Zone transfer) 
    408430        """ 
    409431        default_ttl = soa_record.expire 
    410         results = [copy.copy(r) for r in reduce(operator.add, test_domain_com.records.values())] 
     432        results = [copy.copy(r)  
     433                   for r in reduce(operator.add,  
     434                                   test_domain_com.records.values())] 
    411435        for r in results: 
    412436            if r.ttl is None: 
    413437                r.ttl = default_ttl 
     
    434458            [dns.Record_NAPTR(100, 10, "u", "sip+E2U", 
    435459                              "!^.*$!sip:information@domain.tld!", 
    436460                              ttl=19283784)]) 
     461     
     462    def test_DNSKEY(self): 
     463        """Test DNS 'DNSKEY' record queries.""" 
     464        return self.namesTest( 
     465            self.resolver.lookupDNSKey('test-domain.com'), 
     466            [dns.Record_DNSKEY(0x10, 3, 5,  
     467                               "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=", 
     468                               ttl=19283784)]) 
    437469 
    438  
    439  
    440470class DNSServerFactoryTests(unittest.TestCase): 
    441471    """ 
    442472    Tests for L{server.DNSServerFactory}. 
     
    523553        self.d.addCallback(self._gotResults) 
    524554        self.controller = client.AXFRController('fooby.com', self.d) 
    525555 
    526         self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, ttl=86400, auth=False, 
     556        self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN,  
     557                                ttl=86400, auth=False, 
    527558                                payload=dns.Record_SOA(mname='fooby.com', 
    528559                                                       rname='hooj.fooby.com', 
    529560                                                       serial=100, 
     
    535566 
    536567        self.records = [ 
    537568            self.soa, 
    538             dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, 
     569            dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700,  
     570                         auth=False,  
    539571                         payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700)), 
    540572 
    541573            dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, auth=False, 
     
    548580 
    549581    def _makeMessage(self): 
    550582        # hooray they all have the same message format 
    551         return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, auth=1, rCode=0, trunc=0, maxSize=0) 
     583        return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1,  
     584                           auth=1, rCode=0, trunc=0, maxSize=0) 
    552585 
    553586    def testBindAndTNamesStyle(self): 
    554587        # Bind style = One big single message 
     
    890923        self.assertEqual(service.domains[1].domain, 'example.edu') 
    891924 
    892925 
    893  
    894926class SecondaryAuthorityTests(unittest.TestCase): 
    895927    """ 
    896928    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 
     8from twisted.names.ser_num_arith import SNA, DateSNA 
     9from twisted.trial import unittest 
     10 
     11class SNATest(unittest.TestCase): 
     12 
     13    def setUp(self): 
     14        self.s1 = SNA(1) 
     15        self.s1a = SNA(1) 
     16        self.s2 = SNA(2) 
     17        self.sMaxVal = SNA(SNA.HLFRNG+SNA.HLFRNG-1) 
     18 
     19    def test_equality(self): 
     20        """ 
     21        Test SNA equality 
     22        """ 
     23        self.assertEqual(self.s1, self.s1a) 
     24        self.assertNotIdentical(self.s1, self.s1a) 
     25        self.assertEqual(hash(self.s1), hash(self.s1a)) 
     26        self.assertNotEqual(hash(self.s1), hash(self.s2)) 
     27         
     28    def test_le(self): 
     29        """ 
     30        Test SNA less than or equal 
     31        """ 
     32        self.assertTrue( self.s1 <= self.s1 ) 
     33        self.assertTrue( self.s1 <= self.s1a ) 
     34        self.assertTrue( self.s1 <= self.s2 ) 
     35        self.assertFalse( self.s2 <= self.s1 ) 
     36         
     37    def test_ge(self): 
     38        """ 
     39        Test SNA greater than or equal 
     40        """ 
     41        self.assertTrue( self.s1 >= self.s1 ) 
     42        self.assertTrue( self.s1 >= self.s1a ) 
     43        self.assertFalse( self.s1 >= self.s2 ) 
     44        self.assertTrue( self.s2 >= self.s1 ) 
     45         
     46         
     47    def test_lt(self): 
     48        """ 
     49        Test SNA less than 
     50        """ 
     51        self.assertFalse( self.s1 < self.s1 ) 
     52        self.assertFalse( self.s1 < self.s1a ) 
     53        self.assertTrue( self.s1 < self.s2 ) 
     54        self.assertFalse( self.s2 < self.s1 ) 
     55         
     56    def test_gt(self): 
     57        """ 
     58        Test SNA greater than 
     59        """ 
     60        self.assertFalse( self.s1 > self.s1 ) 
     61        self.assertFalse( self.s1 > self.s1a ) 
     62        self.assertFalse( self.s1 > self.s2 ) 
     63        self.assertTrue( self.s2 > self.s1 ) 
     64 
     65    def test_add(self): 
     66        """ 
     67        Test SNA addition 
     68        """ 
     69        self.assertEqual( self.s1 + self.s1, self.s2) 
     70        self.assertEqual( self.s1 + SNA(SNA.MAXADD), SNA(SNA.MAXADD + 1) ) 
     71        self.assertEqual( SNA(SNA.MAXADD) + SNA(SNA.MAXADD) + SNA(2), SNA(0) ) 
     72         
     73    def test_maxval(self): 
     74        """ 
     75        Test SNA maxval 
     76        """ 
     77        smaxplus1 = self.sMaxVal + self.s1 
     78        self.assertTrue( smaxplus1 > self.sMaxVal ) 
     79        self.assertEqual( smaxplus1, SNA(0) ) 
     80         
     81    def test_max(self): 
     82        """ 
     83        Test the SNA max function 
     84        """ 
     85        self.assertEqual( SNA.max([None, self.s1]), self.s1 ) 
     86        self.assertEqual( SNA.max([self.s1, None]), self.s1 ) 
     87        self.assertEqual( SNA.max([self.s1, self.s1a]), self.s1 ) 
     88        self.assertEqual( SNA.max([self.s2, self.s1a, self.s1, None]), self.s2 ) 
     89        self.assertEqual( SNA.max([SNA(SNA.MAXADD), self.s2, self.s1a, self.s1, None]),  
     90                          SNA(SNA.MAXADD) ) 
     91        self.assertEqual( SNA.max([self.s2, self.s1a, self.s1, None, self.sMaxVal]),  
     92                          self.s2 ) 
     93 
     94    def test_dateSNA(self): 
     95        """ 
     96        Test DateSNA construction and comparison 
     97        """ 
     98        date1 = DateSNA('20120101000000')  
     99        date2 = DateSNA('20130101000000') 
     100        self.assertTrue( date1 < date2 ) 
     101         
     102    def test_dateAdd(self): 
     103        """ 
     104        Test DateSNA addition 
     105        """ 
     106        date3 = DateSNA('20370101000000') 
     107        sna1  = SNA(365*24*60*60) 
     108        date4 = date3 + sna1 
     109        self.assertEqual( date4.asInt(),  date3.asInt() + sna1.asInt()) 
     110 
     111    def test_asDate(self): 
     112        """ 
     113        Test DateSNA conversion 
     114        """ 
     115        date1 = '20120101000000' 
     116        date1Sna = DateSNA(date1) 
     117        self.assertEqual(date1Sna.asDate(), date1) 
     118         
     119    def test_roundTrip(self): 
     120        """ 
     121        Test DateSNA conversion 
     122        """ 
     123        date1 = '20370101000000' 
     124        date1Sna = DateSNA(date1) 
     125        intval = date1Sna.asInt() 
     126        sna1a = SNA(intval) 
     127         
     128        dateSna1a = DateSNA.fromSNA(sna1a) 
     129        self.assertEqual(date1Sna, dateSna1a) 
     130         
     131        dateSna2 = DateSNA.fromInt(intval) 
     132        self.assertEqual(date1Sna, dateSna2) 
     133         
     134 No newline at end of file