Ticket #5450: dnssec-security-aware-nonvalidating-client-v2.patch

File dnssec-security-aware-nonvalidating-client-v2.patch, 65.6 KB (added by BobNovas, 3 years ago)

replaces previous patch in its entirety.

  • names/authority.py

     
    8282        additional = [] 
    8383        default_ttl = max(self.soa[1].minimum, self.soa[1].expire) 
    8484 
    85         domain_records = self.records.get(name.lower()) 
     85        #a record in self.records has a trailing dot if it was created with one, but is never 
     86        #queried with a trailing dot. So, if the get fails with no trailing dot, try it with  
     87        #a trailing dot.  (You could do a better job, and trim the trailing dot, but that's hard.) 
     88        domain_records = self.records.get(name.lower(), self.records.get(name.lower() + '.')) 
    8689 
    8790        if domain_records: 
    8891            for record in domain_records: 
     
    208211 
    209212    def stripComments(self, lines): 
    210213        return [ 
    211             a.find(';') == -1 and a or a[:a.find(';')] for a in [ 
    212                 b.strip() for b in lines 
    213             ] 
     214            #leading whitespace is significant - don't strip it! 
     215            a.find(';') == -1 and a or a[:a.find(';')] for a in lines 
    214216        ] 
    215217 
    216218 
     
    233235        lines = L 
    234236        L = [] 
    235237        for line in lines: 
    236             L.append(line.split()) 
     238            if not line: 
     239                continue 
     240             
     241            if line[0] in [' ', '\t']: 
     242                L.append([''] + line.split()) 
     243            else: 
     244                L.append(line.split()) 
    237245        return filter(None, L) 
    238246 
    239247 
     
    242250        ORIGIN = self.origin 
    243251 
    244252        self.records = {} 
     253        self.previousDomain = None 
    245254 
    246255        for (line, index) in zip(lines, range(len(lines))): 
    247256            if line[0] == '$TTL': 
     
    275284            r.ttl = ttl 
    276285            self.records.setdefault(domain.lower(), []).append(r) 
    277286 
    278             print 'Adding IN Record', domain, ttl, r 
     287            #print 'Adding IN Record', domain, ttl, r 
    279288            if type == 'SOA': 
    280289                self.soa = (domain, r) 
    281290        else: 
     
    283292 
    284293 
    285294    # 
    286     # This file ends here.  Read no further. 
     295    # parse a bind format line. 
    287296    # 
    288297    def parseRecordLine(self, origin, ttl, line): 
    289         MARKERS = dns.QUERY_CLASSES.values() + dns.QUERY_TYPES.values() 
    290298        cls = 'IN' 
    291         owner = origin 
    292  
     299         
    293300        if line[0] == '@': 
    294             line = line[1:] 
    295301            owner = origin 
    296 #            print 'default owner' 
    297         elif not line[0].isdigit() and line[0] not in MARKERS: 
     302        elif line[0]: 
    298303            owner = line[0] 
    299             line = line[1:] 
    300 #            print 'owner is ', owner 
     304        else: 
     305            owner = self.previousDomain 
    301306 
    302         if line[0].isdigit() or line[0] in MARKERS: 
     307        #if the line starts with whitespace, it's not a name 
     308        if not line[0]: 
    303309            domain = owner 
    304310            owner = origin 
    305 #            print 'woops, owner is ', owner, ' domain is ', domain 
     311            line = line[1:] 
    306312        else: 
    307313            domain = line[0] 
    308314            line = line[1:] 
    309 #            print 'domain is ', domain 
    310  
     315         
     316        if line[0].isdigit(): 
     317            ttl = int(line[0]) 
     318            line = line[1:] 
     319             
    311320        if line[0] in dns.QUERY_CLASSES.values(): 
    312321            cls = line[0] 
    313322            line = line[1:] 
    314 #            print 'cls is ', cls 
    315             if line[0].isdigit(): 
    316                 ttl = int(line[0]) 
    317                 line = line[1:] 
    318 #                print 'ttl is ', ttl 
    319         elif line[0].isdigit(): 
    320             ttl = int(line[0]) 
     323             
     324        if line[0] in dns.QUERY_TYPES.values(): 
     325            type = line[0] 
    321326            line = line[1:] 
    322 #            print 'ttl is ', ttl 
    323             if line[0] in dns.QUERY_CLASSES.values(): 
    324                 cls = line[0] 
    325                 line = line[1:] 
    326 #                print 'cls is ', cls 
    327  
    328         type = line[0] 
    329 #        print 'type is ', type 
    330         rdata = line[1:] 
    331 #        print 'rdata is ', rdata 
    332  
     327         
     328        if type == dns.QUERY_TYPES[dns.RRSIG] and len(line) > 9: 
     329            line[8] = ''.join(line[8:]) 
     330            line = line[0:9] 
     331        elif type == dns.QUERY_TYPES[dns.DS] and len(line) > 4: 
     332            line[3] = ''.join(line[3:]) 
     333            line = line[0:3] 
     334        elif type == dns.QUERY_TYPES[dns.DNSKEY] and len(line) > 4: 
     335            line[3] = ''.join(line[3:]) 
     336            line = line[0:3] 
     337             
     338        rdata = line 
     339         
    333340        self.addRecord(owner, ttl, type, domain, cls, rdata) 
     341         
     342        self.previousDomain = domain 
  • 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: A provider of DNSSEC parameters - 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 
     
    129136 
    130137        self.maybeParseConfig() 
    131138 
    132  
    133139    def __getstate__(self): 
    134140        d = self.__dict__.copy() 
    135141        d['connections'] = [] 
     
    240246        for (d, q, t) in self.pending: 
    241247            self.queryTCP(q, t).chainDeferred(d) 
    242248        del self.pending[:] 
     249         
     250    def connectionLost(self, protocol): 
     251        """ 
     252        Called on UDP protocol when a DNS UDP query times out and is retried 
     253        on the TCP protocol. 30 seconds after the TCP query completes, this 
     254        method is called on the UDP protocol. 
     255        """ 
     256        self.connections.remove(protocol) 
     257        del protocol 
    243258 
    244  
    245259    def messageReceived(self, message, protocol, address = None): 
    246260        log.msg("Unexpected message (%d) received from %r" % (message.id, address)) 
    247261 
     
    370384            return self.queryTCP(message.queries).addCallback(self.filterAnswers) 
    371385        if message.rCode != dns.OK: 
    372386            return failure.Failure(self.exceptionForCode(message.rCode)(message)) 
    373         return (message.answers, message.authority, message.additional) 
     387         
     388        #if edns0 is enabled, return a reference to the message as the 4th member of  
     389        #the tuple, so the caller can access AD. You could just return AD, but if you 
     390        #return message, the caller can also access a reference to the query and you 
     391        #never know when that might come in handy. 
     392        if self.dnssecConfig.ednsEnabled: 
     393            return (message.answers, message.authority, message.additional, message) 
     394        else: 
     395            #not edns0Enabled - return a legacy 3-tuple 
     396            return (message.answers, message.authority, message.additional) 
    374397 
    375  
    376398    def _lookup(self, name, cls, type, timeout): 
    377399        """ 
    378400        Build a L{dns.Query} for the given parameters and dispatch it via UDP. 
     
    942964    @rtype: C{Deferred} 
    943965    """ 
    944966    return getResolver().lookupNamingAuthorityPointer(name, timeout) 
     967 
     968def lookupDNSKey(name, timeout=None): 
     969    """ 
     970    DNSKEY lookup.     
     971 
     972    @type name: C{str} 
     973    @param name: DNS name to resolve. 
     974 
     975    @type timeout: Sequence of C{int} 
     976    @param timeout: Number of seconds after which to reissue the query. 
     977        When the last timeout expires, the query is considered failed. 
     978 
     979    @rtype: C{Deferred} 
     980    """ 
     981    return getResolver().lookupDNSKey(name, timeout) 
     982 No newline at end of file 
  • names/common.py

     
    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 require ednsEnabled, 
     26                    but still nice to be able to control whether or not you're asking for recursion. 
     27                    (bool) 
     28 
     29    ednsEnabled   - EDNS Enabled adds an OPT record to the query. The OPT record contains a 
     30                    version field that indicates the version of EDNS that you can handle. 
     31                    Presently, only EDNS Version 0 is defined. 
     32                    (bool) 
     33                     
     34    maxUdpPktSz   - The max size UDP packet (bytes) that your end-to-end network can handle 
     35                    (on a modern network a reliable size is 1492, although up to 65535 is possible). 
     36                    Requires ednsEnabled. 
     37                    (int) 
     38                     
     39    dnssecOK (DO) - Dnssec Ok. A bit that indicates you want DNSSEC RR's and validation  
     40                    if the resolver validates. If DO is set, AD will be set in the response  
     41                    if the answer validates. Requires ednsEnabled. 
     42                    (bool) 
     43 
     44    chkDis (CD)   - Checking Disabled. If DO and CD are set, a validating resolver won't do 
     45                    validation but will return the DNSSEC RR's so that YOU can. 
     46                    (bool) 
     47                     
     48    version       - sets the edns version level. Currently, only 0 is defined and supported. 
     49                    (int) 
     50                     
     51    authData (AD) - Authentic Data. If set in a response from a validating resolver that you can 
     52                    trust, indicates that the validating resolver validated the answer. Requires  
     53                    ednsEnabled and DO set. (See note below.) 
     54                    (bool) 
     55                     
     56    Note - RFC-4035 does not define AD for a query. However, most validating resolvers seem  
     57    to honor it set in a query and return AD set in a response to a query that validates. But  
     58    you should not to rely on this behavior - set DO instead. 
     59    """ 
     60    def __init__(self,  
     61                 recDes=True, 
     62                 ednsEnabled=False,  
     63                 maxUdpPktSz=512,  
     64                 dnssecOk=False, 
     65                 chkDis=False, 
     66                 version=0, 
     67                 authData=False): 
     68 
     69        self.recDes = recDes 
     70        self.ednsEnabled = ednsEnabled 
     71        self.maxUdpPktSz = maxUdpPktSz 
     72        self.dnssecOk = dnssecOk 
     73        self.chkDis = chkDis 
     74        self.version = version 
     75        self.authData = authData 
     76 
     77        assert not self.ednsEnabled or 512 <= self.maxUdpPktSz <= 65535 
     78        assert version == 0 
     79 
    2180class ResolverBase: 
    2281    """ 
    2382    L{ResolverBase} is a base class for L{IResolver} implementations which 
     
    3695 
    3796    typeToMethod = None 
    3897 
    39     def __init__(self): 
     98    def __init__(self, dnssecConfig=None): 
    4099        self.typeToMethod = {} 
    41100        for (k, v) in typeToMethod.items(): 
    42101            self.typeToMethod[k] = getattr(self, v) 
     102        self.dnssecConfig = dnssecConfig 
     103        if self.dnssecConfig == None: 
     104            self.dnssecConfig = DnssecConfig() 
    43105 
    44  
    45106    def exceptionForCode(self, responseCode): 
    46107        """ 
    47108        Convert a response code (one of the possible values of 
     
    200261        @see: twisted.names.client.lookupAllRecords 
    201262        """ 
    202263        return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) 
     264     
     265    def lookupDNSKey(self, name, timeout=None): 
     266        """ 
     267        @see: twisted.names.client.lookupDNSKey 
     268        """ 
     269        return self._lookup(name, dns.IN, dns.DNSKEY, timeout) 
    203270 
    204271    def getHostByName(self, name, timeout = None, effort = 10): 
    205272        """ 
     
    268335    dns.MX:    'lookupMailExchange', 
    269336    dns.TXT:   'lookupText', 
    270337    dns.SPF:   'lookupSenderPolicy', 
     338    dns.DNSKEY:'lookupDNSKey', 
    271339 
    272340    dns.RP:    'lookupResponsibility', 
    273341    dns.AFSDB: 'lookupAFSDatabase', 
  • 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 
     52 
    4953import struct, random, types, socket 
    5054 
    5155import cStringIO as StringIO 
     
    5458 
    5559from zope.interface import implements, Interface, Attribute 
    5660 
     61from base64 import b64decode, b64encode 
    5762 
     63 
    5864# Twisted imports 
    5965from twisted.internet import protocol, defer 
    6066from twisted.internet.error import CannotListenError 
    6167from twisted.python import log, failure 
    6268from twisted.python import util as tputil 
    6369from twisted.python import randbytes 
     70from twisted.names.serialNumberArithmetic import SNA, DateSNA 
    6471 
    6572 
    6673def randomSource(): 
     
    7986NAPTR = 35 
    8087A6 = 38 
    8188DNAME = 39 
     89OPT = 41 
     90DS = 43 
     91RRSIG = 46 
     92NSEC = 47 
     93DNSKEY = 48 
     94NSEC3 = 50 
     95NSEC3PARAM = 51 
     96 
    8297SPF = 99 
    8398 
    8499QUERY_TYPES = { 
     
    108123    NAPTR: 'NAPTR', 
    109124    A6: 'A6', 
    110125    DNAME: 'DNAME', 
    111     SPF: 'SPF' 
     126    OPT: 'OPT', 
     127    DS: 'DS', 
     128    RRSIG: 'RRSIG', 
     129    NSEC: 'NSEC', 
     130    DNSKEY: 'DNSKEY', 
     131    NSEC3: 'NSEC3',  
     132    NSEC3PARAM: 'NSEC3PARAM', 
     133    SPF: 'SPF', 
    112134} 
    113135 
    114136IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) 
     
    277299    def __str__(self): 
    278300        return self.string 
    279301 
    280  
    281  
    282302class Name: 
    283303    implements(IEncodable) 
    284304 
     
    370390 
    371391    def __str__(self): 
    372392        return self.name 
     393     
     394class Sigstr(object): 
     395    ''' 
     396    for signatures and keys. display as b64 encoded 
     397    ''' 
     398    implements(IEncodable) 
     399     
     400    def __init__(self, string=''): 
     401        if not isinstance(string, str): 
     402            raise ValueError("%r is not a string" % (string, )) 
     403        self.string = string #b64encoded string 
     404         
     405    def encode(self, strio, compDict=None): 
     406        ''' 
     407        Write the byte representation (the un-b64-encoded string) 
     408        to the file. 
     409         
     410        @type strio: file 
     411        @param srio: The byte representation of this signature or key 
     412        will be written to this file 
     413         
     414        @type compDict: dict 
     415        @param compDict: not used. 
     416        ''' 
     417        strio.write(b64decode(self.string)) 
     418         
     419    def decode(self, strio, length=None): 
     420        ''' 
     421        Decode a signature or a key. 
    373422 
     423        @type strio: file 
     424        @param strio: Exactly length bytes will be read from this file  
     425        to decode the full signature or key 
     426         
     427        @type length: int 
     428        @param lenth: length must always be given. A signature or key 
     429        is always the last thing in an RR and so you can always determine 
     430        its length.  
     431        ''' 
     432        self.string = '' 
     433        if length == None: 
     434            return 
     435         
     436        assert isinstance(length, int) 
     437        buff = readPrecisely(strio, length) 
     438        self.string = b64encode(buff) 
     439 
     440    def __eq__(self, other): 
     441        if isinstance(other, Sigstr): 
     442            return self.string == other.string 
     443        return False 
     444 
     445    def __hash__(self): 
     446        return hash(self.string) 
     447 
     448    def __str__(self): 
     449        return self.string 
     450     
     451 
     452class TypeBitmaps(object): 
     453    ''' 
     454    bitmap encoding scheme used by NSEC and NSEC3 RR's 
     455    to indicate the RRset types that exist at the  
     456    NSEC/NSEC3 RR's original owner name or hashed name.   
     457    See RFC 4034 and RFC 5155. 
     458    ''' 
     459    fmt = 'BB' 
     460    typeRegex = re.compile('TYPE(\d+)') 
     461     
     462    def __init__(self, string=''): 
     463        self.string = string 
     464         
     465    def encode(self, strio, compDict=None): 
     466        """ 
     467        Encode the string field, which consists of a set  
     468        of type names, into an NSEC/NSEC3 type bitmap. 
     469         
     470        @type strio: file 
     471        @param strio: the byte representation of the type bitmap 
     472        will be written to this file. 
     473         
     474        @type compDict: dict 
     475        @param compDict: not used. 
     476        """ 
     477        if not self.string: 
     478            return; 
     479         
     480        #get a sorted list of RR Type Values 
     481        mnus = self.string.split(' ') 
     482        mnuVals = [] 
     483        for mnu in mnus: 
     484            mnuVal = REV_TYPES.get(mnu, None) 
     485            if not mnuVal: 
     486                m = self.typeRegex.match(mnu) 
     487                if m.groups(): 
     488                    mnuVal = int(m.group(1)) 
     489                    assert mnuVal < 65536 
     490                else: 
     491                    log.err("can't parse %s in %s" % (mnu, self.string, )) 
     492                    continue; 
     493            mnuVals.append(mnuVal) 
     494        mnuVals.sort() 
     495         
     496        #convert that to a dict of windows and lists 
     497        windDict = {} 
     498        for v in mnuVals: 
     499            window = (v >> 8) & 0xFF 
     500            if window not in windDict: 
     501                windDict[window] = [] 
     502            windDict[window].append(v & 0xFF) 
     503         
     504        #have to sort the keys - they're not in order! 
     505        windows = windDict.keys() 
     506        windows.sort() 
     507 
     508        #create the bitmaps 
     509        bmap = bytearray() 
     510        for w in windows: 
     511            bmapseg = bytearray(32) 
     512            maxoff = 0 
     513            for v in windDict[w]: 
     514                vm1 = v - 1 
     515                off = vm1 >> 3 
     516                bit = vm1 & 0x7 
     517                msk = 1 << bit 
     518                bmapseg[off] |= msk 
     519                maxoff = max(off, maxoff) 
     520            bmapseg = bmapseg[0:maxoff+1] 
     521            bmap += chr(w) + chr(maxoff+1) + bmapseg 
     522         
     523        strio.write(str(bmap)) 
     524     
     525    def decode(self, strio, length=None): 
     526        """ 
     527        Decode an NSEC/NSEC3 type bitmap into a string 
     528        representation of type names. 
     529        """ 
     530        self.type_bitmaps = "" 
     531        if length == None: 
     532            return 
     533 
     534        type_bitmaps = bytearray() 
     535        l = struct.calcsize(self.fmt) 
     536        parsed_length = 0 
     537        while parsed_length < length: 
     538            buff = readPrecisely(strio, l) 
     539            wb_num, bm_len = struct.unpack(self.fmt, buff) 
     540            assert parsed_length + 2 + bm_len <= length 
     541            bm = readPrecisely(strio, bm_len) 
     542            byteNum = -1 
     543            for b in bm: 
     544                byteNum += 1 
     545                ob = ord(b) 
     546                if ob == 0: 
     547                    continue 
     548                 
     549                for v in range(8): 
     550                    msk = 1<<v 
     551                    if ob & msk: 
     552                        val = wb_num*256 + byteNum*8 + v + 1 
     553                        mnu = QUERY_TYPES.get(val, None) 
     554                        if not mnu: 
     555                            mnu = 'TYPE' + str(val) 
     556                        type_bitmaps += (mnu + ' ')                         
     557             
     558            parsed_length += 2 + bm_len 
     559             
     560        self.type_bitmaps = str(type_bitmaps[0:-1]) 
     561 
     562    def __eq__(self, other): 
     563        if isinstance(other, TypeBitmaps): 
     564            return self.string == other.string 
     565        return False 
     566 
     567    def __hash__(self): 
     568        return hash(self.string) 
     569 
     570    def __str__(self): 
     571        return self.string 
     572 
     573 
    374574class Query: 
    375575    """ 
    376576    Represent a single DNS query. 
     
    434634        return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 
    435635 
    436636 
    437 class RRHeader(tputil.FancyEqMixin): 
     637     
     638class OPTHeader(tputil.FancyEqMixin): 
    438639    """ 
     640    A OPT record header. 
     641 
     642    @cvar fmt: C{str} specifying the byte format of an OPT Header. 
     643 
     644    @ivar name: Root (0, 8-bits) 
     645    @ivar type: 41 (OPT Record) 
     646    @ivar payload: An object that implements the IEncodable interface 
     647    @ivar auth: Whether this header is authoritative or not. 
     648    """ 
     649 
     650    implements(IEncodable) 
     651 
     652    compareAttributes = ('name', 'type', 'payload', 'auth') 
     653 
     654    fmt = "!H" 
     655 
     656    name = None 
     657    type = None 
     658    payload = None 
     659 
     660    #OPTHeader _really_ has no ttl or rdlength, but the 
     661    #existence of the attributes is required. 
     662    ttl = None 
     663    rdlength = None 
     664 
     665    cachedResponse = None 
     666 
     667    def __init__(self, payload=None, auth=False): 
     668        """ 
     669        @type name: C{str} 
     670        @param name: Root (0) 
     671 
     672        @type type: C{int} 
     673        @param type: Query type 41. 
     674 
     675        @type payload: An object implementing C{IEncodable} 
     676        @param payload: The OPT payload 
     677        """ 
     678        assert (payload is None) or (payload.TYPE == OPT) 
     679 
     680        self.name = 0 
     681        self.type = OPT 
     682        self.payload = payload 
     683        self.auth = auth 
     684 
     685    def encode(self, strio, compDict=None): 
     686        strio.write(struct.pack('!B', 0)) 
     687        strio.write(struct.pack(self.fmt, self.type)) 
     688        if self.payload: 
     689            prefix = strio.tell() 
     690            self.payload.encode(strio, compDict) 
     691            aft = strio.tell() 
     692            strio.seek(prefix - 2, 0) 
     693            strio.write(struct.pack('!H', aft - prefix)) 
     694            strio.seek(aft, 0) 
     695 
     696    def decode(self, strio, length = None): 
     697        self.name.decode(strio) 
     698        l = struct.calcsize(self.fmt) 
     699        buff = readPrecisely(strio, l) 
     700        r = struct.unpack(self.fmt, buff) 
     701        self.type = r[0] 
     702 
     703    def isAuthoritative(self): 
     704        return self.auth 
     705 
     706    def __str__(self): 
     707        return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 
     708 
     709    @staticmethod 
     710    def factory(strio): 
     711        ''' 
     712        reads enough of the stream to figure out if what is there is 
     713        an OPTHeader or an RRHeader 
     714        ''' 
     715        beginPos = strio.tell() 
     716        name = Name() 
     717        name.decode(strio) 
     718        type = struct.unpack(OPTHeader.fmt, readPrecisely(strio, 2))[0] 
     719         
     720        if len(name.name) == 0 and type == OPT: 
     721            return OPTHeader() 
     722        else: 
     723            #back up to the beginning and try again 
     724            strio.seek(beginPos, 0) 
     725            rrh = RRHeader() 
     726            rrh.decode(strio) 
     727            return rrh 
     728         
     729    __repr__ = __str__ 
     730     
     731     
     732class RRHeader(OPTHeader): 
     733    """ 
    439734    A resource record header. 
    440735 
    441736    @cvar fmt: C{str} specifying the byte format of an RR. 
     
    14671762        return hash(tuple(self.data)) 
    14681763 
    14691764 
     1765class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1766    """ 
     1767    EDNS0 Option record. 
     1768     
     1769    @type payload_size: C{int} 
     1770    @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 
     1771        network can handle. 
     1772     
     1773    @type dnssecOk: C{bool} 
     1774    @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 
     1775        validation (and set the AD bit if the response validates). 
     1776         
     1777    @type version: C{int} 
     1778    @ivar version: The version of DNSSEC used. Currently only version 0  
     1779        is defined. 
     1780    """ 
     1781    implements(IEncodable, IRecord) 
     1782    TYPE = OPT 
     1783    fmt = '!HBBHH' 
     1784     
     1785    fancybasename = 'OPT' 
     1786    showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 
     1787    compareAttributes = ('payload_size', 'flags', 'version') 
     1788     
     1789    def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 
     1790        self.payload_size = payload_size 
     1791        self.version = version 
     1792        self.flags = (dnssecOk & 1) << 15 
     1793         
     1794    def encode(self, strio, compDict = None): 
     1795        OPTHeader().encode(strio) 
     1796        strio.write(struct.pack('!H', self.payload_size)) 
     1797        strio.write(struct.pack('!B', 0)) # high order 0 
     1798        strio.write(struct.pack('!B', self.version)) 
     1799        strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 
     1800        strio.write(struct.pack('!H', 0)) # Data length: 0 
     1801         
     1802    def decode(self, strio, length=None): 
     1803        ''' 
     1804        are OPT Records always 0 rdlength? 
     1805        ''' 
     1806        l = struct.calcsize(self.fmt) 
     1807        buff = readPrecisely(strio, l) 
     1808        r = struct.unpack(self.fmt, buff) 
     1809        self.payload_size, z, self.version, self.flags, length = r 
     1810        assert length == 0 
     1811         
     1812    def __hash__(self): 
     1813        return hash((self.payload_size, self.version, self.flags)) 
    14701814 
     1815class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1816    """ 
     1817    DNSSEC RRSIG record.  See RFC 4034 for details. 
     1818     
     1819    @type type_covered: C{int} 
     1820    @ivar type_covered: Identifies the type of the RRset that this RRSIG covers.  
     1821     
     1822    @type algo: C{int} 
     1823    @ivar algo: Identifies the crypto algorithm type used to create the signature. 
     1824        (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 
     1825     
     1826    @type labels: C{int} 
     1827    @ivar labels: Specifies the number of labels in the original RRSIG RR owner name. 
     1828        A validator can use this to determine whether the answer was synthesized from 
     1829        a wildcard. 
     1830     
     1831    @type original_ttl: C{int} 
     1832    @ivar original_ttl: Specifies the TTL of the covered RRset as it appears in the  
     1833        authoritative zone. 
     1834     
     1835    @type sig_expiration: C{int}  
     1836    @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 
     1837        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1838     
     1839    @type sig_inception: C{int}  
     1840    @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 
     1841        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1842     
     1843    @type key_tag: C{int} 
     1844    @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates this 
     1845        signature, in network byte order. See RFC 4034 App B. 
     1846     
     1847    @type signers_name: L{Name} 
     1848    @ivar signers_name: Identifies the owner name of the DNSKEY RR that a validator 
     1849        should use to validate this signature. Must not use DNS 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  RRSIG 
     1854        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 record. 
     1929     
     1930    @type algo: C{int} 
     1931    @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this DS record.     
     1932 
     1933    @type digest_type: C{int} 
     1934    @ivar digest_type: Identifies the algorithm used to construct the digest field. 
     1935     
     1936    @type digest: L{Sigstr} 
     1937    @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by the 
     1938        algorithm identified by the digest_type field. 
     1939 
     1940    @type ttl: C{int} 
     1941    @ivar ttl: The maximum number of seconds which this record should be 
     1942        cached.     
     1943    """ 
     1944    implements(IEncodable, IRecord) 
     1945    TYPE = DS 
     1946    fmt = '!HBB' 
     1947     
     1948    fancybasename = 'DS' 
     1949    showAttributes = ('key_tag', 'algo', 'digest_type', ('_digest', 'digest', '%s'), 'ttl') 
     1950    compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 
     1951     
     1952    _digest = property(lambda self: self.digest.string) 
     1953 
     1954    def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 
     1955        self.key_tag = key_tag 
     1956        self.algo = algo 
     1957        self.digest_type = digest_type 
     1958        self.digest = Sigstr(digest) 
     1959        self.ttl = str2time(ttl) 
     1960         
     1961    def encode(self, strio, compDict = None): 
     1962        strio.write(struct.pack(self.fmt,  
     1963                                self.key_tag, 
     1964                                self.algo,  
     1965                                self.digest_type)) 
     1966        self.digest.encode(strio, None) 
     1967         
     1968    def decode(self, strio, length=None): 
     1969        start = strio.tell() 
     1970        l = struct.calcsize(self.fmt) 
     1971        buff = readPrecisely(strio, l) 
     1972        r = struct.unpack(self.fmt, buff)         
     1973        self.key_tag, self.algo, self.digest_type = r         
     1974        here = strio.tell() 
     1975        self.digest.decode(strio, length + start - here if length else None) 
     1976                 
     1977    def __hash__(self): 
     1978        return hash((self.key_tag, self.algo, self.digest_type, self.digest))     
     1979 
     1980class Record_DNSKEY(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1981    """ 
     1982    A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 
     1983     
     1984    @type flags: C{int} 
     1985    @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 
     1986        DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 
     1987        the name of a zone.  If bit 7 has value 0, then the DNSKEY record 
     1988        holds some other type of DNS public key and MUST NOT be used to  
     1989        verify RRSIGs that cover RRsets.   
     1990        Bit 15 is the Secure Entry Point flag. See RFC 3757.)  
     1991        All other bits are reserved and must be zero. 
     1992         
     1993    @type protocol: C{int} 
     1994    @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 
     1995        if this field does not contain 3. 
     1996     
     1997    @type algo: C{int} 
     1998    @ivar algo: Identifies the public key's cryptographic algorithm and determines 
     1999        the format of the pub_key field.  See RFC 4034 App A. 
     2000     
     2001    @type pub_key: L{Sigstr} 
     2002    @ivar pub_key: Holds the public key material. 
     2003 
     2004    @type ttl: C{int} 
     2005    @ivar ttl: The maximum number of seconds which this record should be 
     2006        cached.     
     2007    """ 
     2008    implements(IEncodable, IRecord) 
     2009    TYPE = DNSKEY 
     2010    fmt = '!HBB' 
     2011     
     2012    fancybasename = 'DNSKEY' 
     2013    showAttributes = ('flags', 'protocol', 'algo', ('_pub_key', 'pub_key', '%s'), 'ttl') 
     2014    compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 
     2015     
     2016    _pub_key = property(lambda self: self.pub_key.string) 
     2017     
     2018    def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 
     2019        self.flags = flags 
     2020        self.protocol = protocol 
     2021        self.algo = algo 
     2022        self.pub_key = Sigstr(pub_key) 
     2023        self.ttl = str2time(ttl) 
     2024         
     2025    def encode(self, strio, compDict = None): 
     2026        strio.write(struct.pack(self.fmt,  
     2027                                self.flags, 
     2028                                self.protocol,  
     2029                                self.algo)) 
     2030        self.pub_key.encode(strio, None) 
     2031         
     2032    def decode(self, strio, length=None): 
     2033        start = strio.tell() 
     2034        l = struct.calcsize(self.fmt) 
     2035        buff = readPrecisely(strio, l) 
     2036        r = struct.unpack(self.fmt, buff)         
     2037        self.flags, self.protocol, self.algo = r         
     2038        here = strio.tell() 
     2039        self.pub_key.decode(strio, length + start - here if length else None) 
     2040                 
     2041    def __hash__(self): 
     2042        return hash((self.flags, self.protocol, self.algo, self.pub_key)) 
     2043 
     2044class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2045    """ 
     2046    A DNSSEC NSEC record provides authenticated denial of existance for DNS data.  
     2047 
     2048    A DNSSEC NSEC record lists: 
     2049     
     2050        1) the next owner name in canonical ordering of the zone that contains authoritataive 
     2051           data or a delegation point NS RRset. 
     2052         
     2053        2) the set of RR types present at the NSEC RR's owner name. 
     2054 
     2055    @type nxt_name: L{Name} 
     2056    @ivar nxt_name: The next owner name that has authoritative data or contains a 
     2057        delegation point NS RRset. 
     2058     
     2059    @type type_bitmaps: L{TypeBitmaps} 
     2060    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's owner name. 
     2061     
     2062    @type ttl: C{int} 
     2063    @ivar ttl: The maximum number of seconds which this record should be 
     2064        cached. 
     2065    """ 
     2066    implements(IEncodable, IRecord) 
     2067    TYPE = NSEC 
     2068     
     2069    fancybasename = 'NSEC' 
     2070    showAttributes = (('nxt_name', 'nxt_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2071    compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 
     2072     
     2073    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2074     
     2075    def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 
     2076        self.nxt_name = Name(nxt_name) 
     2077        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2078        self.ttl = str2time(ttl) 
     2079         
     2080    def encode(self, strio, compDict = None): 
     2081        self.nxt_name.encode(strio, None) 
     2082        self.type_bitmaps.encode(strio, None) 
     2083         
     2084    def decode(self, strio, length=None): 
     2085        start = strio.tell() 
     2086        self.nxt_name.decode(strio, None) 
     2087        here = strio.tell() 
     2088        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2089                 
     2090    def __hash__(self): 
     2091        return hash((self.nxt_name, self.type_bitmaps)) 
     2092 
     2093class Record_NSEC3PARAM(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2094    """ 
     2095    A DNSSEC NSEC3PARAM record contains the NSEC3 parameters (hash algorithm, 
     2096    flags, iterations and salt) needed by authoritative servers to calculate 
     2097    hashed owner names.  The presence of an NSEC3PARAM RR at a zone apex 
     2098    indicates that the specified parameters may be used by authoritative  
     2099    servers to choose an appropriate set of NSEC3 RRs for negative responses.  
     2100 
     2101    @type hash_algo: C{int} 
     2102    @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 
     2103     
     2104    @type flags: C{int} 
     2105    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the  
     2106        opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 
     2107        delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 
     2108     
     2109    @type iterations: C{int} 
     2110    @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 
     2111     
     2112    @type salt: L{Charset} 
     2113    @ivar salt: Identifies the salt value provided to the hash. 
     2114 
     2115    @type ttl: C{int} 
     2116    @ivar ttl: The maximum number of seconds which this record should be 
     2117        cached. 
     2118    """ 
     2119    implements(IEncodable, IRecord) 
     2120    TYPE = NSEC3 
     2121    fmt = '!BBH' 
     2122     
     2123    fancybasename = 'NSEC3' 
     2124    showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), 'ttl') 
     2125    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'ttl') 
     2126     
     2127    _salt = property(lambda self: self.salt.string) 
     2128     
     2129    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', ttl=None): 
     2130        self.hash_algo = hash_algo 
     2131        self.flags = flags 
     2132        self.iterations = iterations 
     2133        self.salt = Charstr(salt) 
     2134        self.ttl = str2time(ttl) 
     2135         
     2136    def encode(self, strio, compDict = None): 
     2137        strio.write(struct.pack(self.fmt, 
     2138                                self.hash_algo, 
     2139                                self.flags, 
     2140                                self.iterations)) 
     2141        self.salt.encode(strio, None) 
     2142         
     2143    def decode(self, strio, length=None): 
     2144        start = strio.tell() 
     2145        l = struct.calcsize(self.fmt) 
     2146        buff = readPrecisely(strio, l) 
     2147        r = struct.unpack(self.fmt, buff)         
     2148        self.hash_algo, self.flags, self.iterations = r    
     2149        self.salt.decode(strio) 
     2150        here = strio.tell() 
     2151                 
     2152    def __hash__(self): 
     2153        return hash((self.hash_algo, self.flags, self.iterations, self.salt)) 
     2154     
     2155class Record_NSEC3(Record_NSEC3PARAM): 
     2156    """ 
     2157    A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of existance  
     2158    for DNS data and permits a gradual expansion of delegation-centric zones.  
     2159 
     2160    A DNSSEC NSEC3 record lists: 
     2161     
     2162        1) the set of RR types present at the original owner name of the NSEC RR. 
     2163 
     2164        2) the next hashed owner name in the hash order of the zone. 
     2165 
     2166    @type hash_algo: C{int} 
     2167    @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 
     2168     
     2169    @type flags: C{int} 
     2170    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the  
     2171        opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 
     2172        delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 
     2173     
     2174    @type iterations: C{int} 
     2175    @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 
     2176     
     2177    @type salt: L{Charset} 
     2178    @ivar salt: Identifies the salt value provided to the hash. 
     2179     
     2180    @type nxt_hash_owner_name: L{Charset} 
     2181    @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone in hash order. 
     2182     
     2183    @type type_bitmaps: L{TypeBitmaps} 
     2184    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's original owner name. 
     2185     
     2186    @type ttl: C{int} 
     2187    @ivar ttl: The maximum number of seconds which this record should be 
     2188        cached. 
     2189    """ 
     2190    implements(IEncodable, IRecord) 
     2191    TYPE = NSEC3 
     2192    fmt = '!BBH' 
     2193     
     2194    fancybasename = 'NSEC3' 
     2195    showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2196    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 
     2197     
     2198    _salt = property(lambda self: self.salt.string) 
     2199    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2200     
     2201    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', nxt_hash_owner='', type_bitmaps=None, ttl=None): 
     2202        Record_NSEC3PARAM.__init__( self, hash_algo, flags, iterations, salt, ttl) 
     2203        self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 
     2204        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2205         
     2206    def encode(self, strio, compDict = None): 
     2207        Record_NSEC3PARAM.encode(self, strio, compDict) 
     2208        self.nxt_hash_owner_name.encode(strio, None) 
     2209        self.type_bitmaps.encode(strio, None) 
     2210         
     2211    def decode(self, strio, length=None): 
     2212        start = strio.tell() 
     2213        Record_NSEC3PARAM.decode(self, strio, compDict) 
     2214        self.nxt_hash_owner_name.decode(strio) 
     2215        here = strio.tell() 
     2216        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2217                 
     2218    def __hash__(self): 
     2219        return hash((self.hash_algo, self.flags, self.iterations, self.salt, 
     2220                     self.nxt_hash_owner_name, self.type_bitmaps)) 
     2221 
    14712222# This is a fallback record 
    14722223class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 
    14732224    """ 
     
    15442295    queries = answers = add = ns = None 
    15452296 
    15462297    def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 
    1547                        auth=0, rCode=OK, trunc=0, maxSize=512): 
     2298                 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 
    15482299        self.maxSize = maxSize 
    15492300        self.id = id 
    15502301        self.answer = answer 
    15512302        self.opCode = opCode 
    1552         self.auth = auth 
    1553         self.trunc = trunc 
    1554         self.recDes = recDes 
    1555         self.recAv = recAv 
     2303        self.auth = auth            #AA - Authoritative Answer 
     2304        self.trunc = trunc          #TC - TrunCated 
     2305        self.recDes = recDes        #RD - Recursion Desired 
     2306        self.recAv = recAv          #RA - Recursion Available 
     2307        self.authData = authData    #AD - Authentic Data 
     2308        self.chkDis = chkDis        #CD - Checking Disabled 
    15562309        self.rCode = rCode 
    15572310        self.queries = [] 
    15582311        self.answers = [] 
     
    15972350                 | ((self.auth & 1 ) << 2 ) 
    15982351                 | ((self.trunc & 1 ) << 1 ) 
    15992352                 | ( self.recDes & 1 ) ) 
    1600         byte4 = ( ( (self.recAv & 1 ) << 7 ) 
     2353        byte4 = (  ((self.recAv & 1 ) << 7 ) 
     2354                  |((self.authData & 1 ) << 5 ) 
     2355                  |((self.chkDis & 1 ) << 4 ) 
    16012356                  | (self.rCode & 0xf ) ) 
    16022357 
    16032358        strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, 
     
    16172372        self.trunc = ( byte3 >> 1 ) & 1 
    16182373        self.recDes = byte3 & 1 
    16192374        self.recAv = ( byte4 >> 7 ) & 1 
     2375        self.authData = ( byte4 >> 5 ) & 1 
     2376        self.chkDis = ( byte4 >> 4 ) & 1 
    16202377        self.rCode = byte4 & 0xf 
    16212378 
    16222379        self.queries = [] 
     
    16352392 
    16362393    def parseRecords(self, list, num, strio): 
    16372394        for i in range(num): 
    1638             header = RRHeader() 
    16392395            try: 
    1640                 header.decode(strio) 
     2396                header = OPTHeader.factory(strio) 
    16412397            except EOFError: 
    16422398                return 
    16432399            t = self.lookupRecordType(header.type) 
     
    17472503            query, or errbacked with any errors that could happen (exceptions 
    17482504            during writing of the query, timeout errors, ...). 
    17492505        """ 
    1750         m = Message(id, recDes=1) 
     2506        m = Message(id, recDes=self.controller.dnssecConfig.recDes) 
    17512507        m.queries = queries 
     2508        if self.controller.dnssecConfig.ednsEnabled: 
     2509            authData=self.controller.dnssecConfig.authData 
     2510            chkDis=self.controller.dnssecConfig.chkDis 
     2511            m.additional = [Record_OPT(payload_size = self.controller.dnssecConfig.maxUdpPktSz, 
     2512                                       version = self.controller.dnssecConfig.version, 
     2513                                       dnssecOk = self.controller.dnssecConfig.dnssecOk)] 
    17522514 
    17532515        try: 
    17542516            writeMessage(m) 
     
    18022564        self.transport.write(message.toStr(), address) 
    18032565 
    18042566    def startListening(self): 
    1805         self._reactor.listenUDP(0, self, maxPacketSize=512) 
     2567        maxPacketSize = 512 
     2568        if self.controller.dnssecConfig.ednsEnabled: 
     2569            maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 
     2570        self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 
    18062571 
    18072572    def datagramReceived(self, data, addr): 
    18082573        """ 
  • names/secondary.py

     
    5959        if self.transferring: 
    6060            return 
    6161        self.transfering = True 
    62         return client.Resolver(servers=[(self.primary, dns.PORT)] 
    63             ).lookupZone(self.domain 
     62         
     63        primary = self.primary 
     64        port = dns.PORT 
     65        parts = self.primary.split(':') 
     66        if len(parts) == 2: 
     67            primary = parts[0] 
     68            port = int(parts[1]) 
     69             
     70        return client.Resolver(servers=[(primary, port)] 
     71            ).lookupZone(self.domain, timeout=600 
    6472            ).addCallback(self._cbZone 
    6573            ).addErrback(self._ebZone 
    6674            ) 
  • names/test/test_client.py

     
    642642        d.addCallback(self.checkResult, dns.NAPTR) 
    643643        return d 
    644644 
     645    def test_lookupDNSKey(self): 
     646        """ 
     647        See L{test_lookupAddress} 
     648        """ 
     649        d = client.lookupDNSKey(self.hostname) 
     650        d.addCallback(self.checkResult, dns.DNSKEY) 
     651        return d 
    645652 
     653 
    646654class ThreadedResolverTests(unittest.TestCase): 
    647655    """ 
    648656    Tests for L{client.ThreadedResolver}. 
  • 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. 
     
    386458        Initialize the controller: create a list of messages. 
    387459        """ 
    388460        self.messages = [] 
     461        self.dnssecConfig = common.DnssecConfig() 
    389462 
    390463 
    391464    def messageReceived(self, msg, proto, addr): 
     
    840913            repr(dns.UnknownRecord("foo\x1fbar", 12)), 
    841914            "<UNKNOWN data='foo\\x1fbar' ttl=12>") 
    842915 
     916    def test_dnskey(self): 
     917        """ 
     918        The repr of a L{dns.DNSKEY} instance includes the flags, protocol, 
     919        algo, pub_key and ttl fields of the record. 
     920        """ 
     921        self.assertEqual( 
     922            repr(dns.Record_DNSKEY(10, 20, 30, "foo\x1fbar", ttl=20)), 
     923            "<DNSKEY flags=10 protocol=20 algo=30 pub_key=foo\x1fbar ttl=20>") 
     924     
     925    def test_ds(self): 
     926        """ 
     927        The repr of a L{dns.DS} instance includes the key_tag, algo, digest_type, 
     928        digest and ttl fields of the record. 
     929        """ 
     930        self.assertEqual( 
     931            repr(dns.Record_DS(11, 22, 33, "foo\x1fbar1", ttl=21)), 
     932            "<DS key_tag=11 algo=22 digest_type=33 digest=foo\x1fbar1 ttl=21>") 
     933     
     934    def test_nsec(self): 
     935        """ 
     936        The repr of a L{dns.NSEC} instance includes the nxt_name, type_bitmaps and 
     937        ttl fields of the record. 
     938        """ 
     939        self.assertEqual( 
     940            repr(dns.Record_NSEC('bob', "\x1fabcd", ttl=31)), 
     941            "<NSEC nxt_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     942     
     943    def test_nsec3param(self): 
     944        """ 
     945        The repr of a L{dns.NSEC3PARAM} instance includes the hash_algo, flags,  
     946        iterations, salt and ttl fields of the record. 
     947        """ 
     948        self.assertEqual( 
     949            repr(dns.Record_NSEC3PARAM(1, 2, 3, '\x12\x34', ttl=31)), 
     950            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 ttl=31>") 
     951     
     952    def test_nsec3(self): 
     953        """ 
     954        The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, iterations, 
     955        salt, nxt_hash_owner_name, type_bitmaps and ttl fields of the record. 
     956        """ 
     957        self.assertEqual( 
     958            repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', "\x1fabcd", ttl=31)), 
     959            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 nxt_hash_owner_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     960     
     961    def test_opt(self): 
     962        """ 
     963        The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk flag,  
     964        and version fields of the record. (The OPT record has no ttl field.) 
     965        """ 
     966        self.assertEqual( 
     967            repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 
     968                 "<OPT payload_size=1492 flags=0x8000 version=0>") 
    843969 
     970    def test_rrsig(self): 
     971        """ 
     972        The repr of a L{dns.RRSIG} instance includes the algo, labels, original_ttl 
     973        sig_expiration, sig_inception, key_tag, signers_name, signature and ttl  
     974        fields of the record. 
     975        """ 
     976        self.assertEqual( 
     977            repr(dns.Record_RRSIG(type_covered=dns.A, 
     978                                  algo=2, 
     979                                  labels=3, 
     980                                  original_ttl=30, 
     981                                  sig_expiration='20110101123456', 
     982                                  sig_inception= '20110202112233', 
     983                                  key_tag=60, 
     984                                  signers_name='bob', 
     985                                  signature='\x12\x34sig', 
     986                                  ttl=70)), 
     987                 "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 
     988                + " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 
     989                + " signers_name=bob signature=\x12\x34sig ttl=70>") 
    844990 
    845991class _Equal(object): 
    846992    """ 
     
    9081054            cls('example.com', 123), 
    9091055            cls('example.org', 123)) 
    9101056 
     1057    def test_optheader(self): 
     1058        """ 
     1059        Two OptHeader instances comapare equal iff the have the same 
     1060        (Record_OPT) payload and auth bit. 
     1061        """ 
     1062        self._equalityTest( 
     1063            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 
     1064            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 
     1065            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492, dnssecOk=False, version=0, ttl=40), auth=True)) 
    9111066 
    9121067    def test_rrheader(self): 
    9131068        """ 
     
    14301585            dns.UnknownRecord('foo', ttl=10), 
    14311586            dns.UnknownRecord('foo', ttl=10), 
    14321587            dns.UnknownRecord('foo', ttl=100)) 
     1588 
     1589    def test_rrsig(self): 
     1590        """ 
     1591        L(dns.RRSIG) instances compare equal iff they have the same 
     1592        type_covered, algo, labels, original_ttl, sig_expiration, sig_inception,  
     1593        key_tag, signers_name, signature, and ttl 
     1594        """ 
     1595        self._equalityTest( 
     1596            dns.Record_RRSIG(type_covered=dns.A), 
     1597            dns.Record_RRSIG(type_covered=dns.A), 
     1598            dns.Record_RRSIG(type_covered=dns.AAAA)) 
     1599        self._equalityTest( 
     1600            dns.Record_RRSIG(algo=1), 
     1601            dns.Record_RRSIG(algo=1), 
     1602            dns.Record_RRSIG(algo=2)) 
     1603        self._equalityTest( 
     1604            dns.Record_RRSIG(labels=3), 
     1605            dns.Record_RRSIG(labels=3), 
     1606            dns.Record_RRSIG(labels=4)) 
     1607        self._equalityTest( 
     1608            dns.Record_RRSIG(original_ttl=5), 
     1609            dns.Record_RRSIG(original_ttl=5), 
     1610            dns.Record_RRSIG(original_ttl=6)) 
     1611        self._equalityTest( 
     1612            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1613            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1614            dns.Record_RRSIG(sig_expiration='20110101000001')) 
     1615        self._equalityTest( 
     1616            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1617            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1618            dns.Record_RRSIG(sig_inception='20120101000001')) 
     1619        self._equalityTest( 
     1620            dns.Record_RRSIG(key_tag=11), 
     1621            dns.Record_RRSIG(key_tag=11), 
     1622            dns.Record_RRSIG(key_tag=12)) 
     1623        self._equalityTest( 
     1624            dns.Record_RRSIG(signers_name='bob'), 
     1625            dns.Record_RRSIG(signers_name='bob'), 
     1626            dns.Record_RRSIG(signers_name='joe')) 
     1627        self._equalityTest( 
     1628            dns.Record_RRSIG(signature='abcdef'), 
     1629            dns.Record_RRSIG(signature='abcdef'), 
     1630            dns.Record_RRSIG(signature='abcdefg')) 
     1631        self._equalityTest( 
     1632            dns.Record_RRSIG(ttl=10), 
     1633            dns.Record_RRSIG(ttl=10), 
     1634            dns.Record_RRSIG(ttl=20)) 
     1635         
     1636    def test_ds(self): 
     1637        """ 
     1638        L(dns.DS) instances compare equal iff they have the same 
     1639        key_tag, algo, digest_type, digest and ttl 
     1640        """ 
     1641        self._equalityTest( 
     1642            dns.Record_DS(key_tag=1), 
     1643            dns.Record_DS(key_tag=1), 
     1644            dns.Record_DS(key_tag=2)) 
     1645        self._equalityTest( 
     1646            dns.Record_DS(algo=3), 
     1647            dns.Record_DS(algo=3), 
     1648            dns.Record_DS(algo=4)) 
     1649        self._equalityTest( 
     1650            dns.Record_DS(digest_type=5), 
     1651            dns.Record_DS(digest_type=5), 
     1652            dns.Record_DS(digest_type=6)) 
     1653        self._equalityTest( 
     1654            dns.Record_DS(digest='abcdef-digest'), 
     1655            dns.Record_DS(digest='abcdef-digest'), 
     1656            dns.Record_DS(digest='abcdef-digest-f')) 
     1657        self._equalityTest( 
     1658            dns.Record_DS(ttl=10), 
     1659            dns.Record_DS(ttl=10), 
     1660            dns.Record_DS(ttl=20)) 
     1661 
     1662    def test_dnskey(self): 
     1663        """ 
     1664        L(dns.DNSKEY) instances compare equal iff they have the same 
     1665        flags, protocol, algo, pub_key and ttl 
     1666        """ 
     1667        self._equalityTest( 
     1668            dns.Record_DNSKEY(flags=1), 
     1669            dns.Record_DNSKEY(flags=1), 
     1670            dns.Record_DNSKEY(flags=2)) 
     1671        self._equalityTest( 
     1672            dns.Record_DNSKEY(protocol=3), 
     1673            dns.Record_DNSKEY(protocol=3), 
     1674            dns.Record_DNSKEY(protocol=4)) 
     1675        self._equalityTest( 
     1676            dns.Record_DNSKEY(algo=5), 
     1677            dns.Record_DNSKEY(algo=5), 
     1678            dns.Record_DNSKEY(algo=6)) 
     1679        self._equalityTest( 
     1680            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1681            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1682            dns.Record_DNSKEY(pub_key='abcdef-digest-f')) 
     1683        self._equalityTest( 
     1684            dns.Record_DNSKEY(ttl=10), 
     1685            dns.Record_DNSKEY(ttl=10), 
     1686            dns.Record_DNSKEY(ttl=20)) 
     1687 
     1688    def test_nsec(self): 
     1689        """ 
     1690        L(dns.DNSKEY) instances compare equal iff they have the same 
     1691        nxt_name, type_bitmaps and ttl 
     1692        """ 
     1693        self._equalityTest( 
     1694            dns.Record_NSEC(nxt_name="example.com"), 
     1695            dns.Record_NSEC(nxt_name="example.com"), 
     1696            dns.Record_NSEC(nxt_name="a.example.com")) 
     1697        self._equalityTest( 
     1698            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1699            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1700            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1701        self._equalityTest( 
     1702            dns.Record_NSEC(ttl=5), 
     1703            dns.Record_NSEC(ttl=5), 
     1704            dns.Record_NSEC(ttl=6)) 
     1705 
     1706    def test_nsec3param(self): 
     1707        """ 
     1708        L(dns.DNSKEY) instances compare equal iff they have the same 
     1709        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1710        """ 
     1711        self._equalityTest( 
     1712            dns.Record_NSEC3PARAM(hash_algo=1), 
     1713            dns.Record_NSEC3PARAM(hash_algo=1), 
     1714            dns.Record_NSEC3PARAM(hash_algo=2)) 
     1715        self._equalityTest( 
     1716            dns.Record_NSEC3PARAM(flags=1), 
     1717            dns.Record_NSEC3PARAM(flags=1), 
     1718            dns.Record_NSEC3PARAM(flags=2)) 
     1719        self._equalityTest( 
     1720            dns.Record_NSEC3PARAM(iterations=5), 
     1721            dns.Record_NSEC3PARAM(iterations=5), 
     1722            dns.Record_NSEC3PARAM(iterations=6)) 
     1723        self._equalityTest( 
     1724            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1725            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1726            dns.Record_NSEC3PARAM(salt="abcdefg")) 
     1727        self._equalityTest( 
     1728            dns.Record_NSEC3PARAM(ttl=5), 
     1729            dns.Record_NSEC3PARAM(ttl=5), 
     1730            dns.Record_NSEC3PARAM(ttl=6)) 
     1731 
     1732    def test_nsec3(self): 
     1733        """ 
     1734        L(dns.DNSKEY) instances compare equal iff they have the same 
     1735        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1736        """ 
     1737        self._equalityTest( 
     1738            dns.Record_NSEC3(hash_algo=1), 
     1739            dns.Record_NSEC3(hash_algo=1), 
     1740            dns.Record_NSEC3(hash_algo=2)) 
     1741        self._equalityTest( 
     1742            dns.Record_NSEC3(flags=1), 
     1743            dns.Record_NSEC3(flags=1), 
     1744            dns.Record_NSEC3(flags=2)) 
     1745        self._equalityTest( 
     1746            dns.Record_NSEC3(iterations=5), 
     1747            dns.Record_NSEC3(iterations=5), 
     1748            dns.Record_NSEC3(iterations=6)) 
     1749        self._equalityTest( 
     1750            dns.Record_NSEC3(salt="abcdef"), 
     1751            dns.Record_NSEC3(salt="abcdef"), 
     1752            dns.Record_NSEC3(salt="abcdefg")) 
     1753        self._equalityTest( 
     1754            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1755            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1756            dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 
     1757        self._equalityTest( 
     1758            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1759            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1760            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1761        self._equalityTest( 
     1762            dns.Record_NSEC3(ttl=5), 
     1763            dns.Record_NSEC3(ttl=5), 
     1764            dns.Record_NSEC3(ttl=6)) 
     1765 
     1766 
     1767                 
     1768 No newline at end of file 
  • names/test/test_names.py

     
    9393                           '\x12\x01\x16\xfe\xc1\x00\x01'), 
    9494            dns.Record_NAPTR(100, 10, "u", "sip+E2U", 
    9595                             "!^.*$!sip:information@domain.tld!"), 
    96             dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF')], 
     96            dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF'), 
     97            dns.Record_DNSKEY(0x10, 3, 5,  
     98                              "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=" 
     99                             )], 
    97100        'http.tcp.test-domain.com': [ 
    98101            dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') 
    99102        ], 
    100103        'host.test-domain.com': [ 
    101104            dns.Record_A('123.242.1.5'), 
    102105            dns.Record_A('0.255.0.255'), 
     106            dns.Record_RRSIG(dns.A, 5, 3, 86400, '20120101000000', '20120201000000', 2642, 'test-domain.com',  
     107                            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=") 
    103108        ], 
    104109        'host-two.test-domain.com': [ 
    105110# 
     
    429434            [dns.Record_NAPTR(100, 10, "u", "sip+E2U", 
    430435                              "!^.*$!sip:information@domain.tld!", 
    431436                              ttl=19283784)]) 
     437     
     438    def test_DNSKEY(self): 
     439        """Test DNS 'DNSKEY' record queries.""" 
     440        return self.namesTest( 
     441            self.resolver.lookupDNSKey('test-domain.com'), 
     442            [dns.Record_DNSKEY(0x10, 3, 5,  
     443                               "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=", 
     444                               ttl=19283784)]) 
    432445 
    433  
    434  
    435446class DNSServerFactoryTests(unittest.TestCase): 
    436447    """ 
    437448    Tests for L{server.DNSServerFactory}.