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

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

dnssec security aware patch to twisted.names

  • 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', 'NULL', 'OPT', 'PTR', 'RP', 'RRSIG', 'SOA', 'SPF',  
     21    '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 
    8295SPF = 99 
    8396 
    8497QUERY_TYPES = { 
     
    108121    NAPTR: 'NAPTR', 
    109122    A6: 'A6', 
    110123    DNAME: 'DNAME', 
    111     SPF: 'SPF' 
     124    OPT: 'OPT', 
     125    DS: 'DS', 
     126    RRSIG: 'RRSIG', 
     127    NSEC: 'NSEC', 
     128    DNSKEY: 'DNSKEY', 
     129    NSEC3: 'NSEC3',  
     130    SPF: 'SPF', 
    112131} 
    113132 
    114133IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) 
     
    277296    def __str__(self): 
    278297        return self.string 
    279298 
    280  
    281  
    282299class Name: 
    283300    implements(IEncodable) 
    284301 
     
    370387 
    371388    def __str__(self): 
    372389        return self.name 
     390     
     391class Sigstr(object): 
     392    ''' 
     393    for signatures and keys. display as b64 encoded 
     394    ''' 
     395    implements(IEncodable) 
     396     
     397    def __init__(self, string=''): 
     398        if not isinstance(string, str): 
     399            raise ValueError("%r is not a string" % (string, )) 
     400        self.string = string #b64encoded string 
     401         
     402    def encode(self, strio, compDict=None): 
     403        ''' 
     404        Write the byte representation (the un-b64-encoded string) 
     405        to the file. 
     406         
     407        @type strio: file 
     408        @param srio: The byte representation of this signature or key 
     409        will be written to this file 
     410         
     411        @type compDict: dict 
     412        @param compDict: not used. 
     413        ''' 
     414        strio.write(b64decode(self.string)) 
     415         
     416    def decode(self, strio, length=None): 
     417        ''' 
     418        Decode a signature or a key. 
    373419 
     420        @type strio: file 
     421        @param strio: Exactly length bytes will be read from this file  
     422        to decode the full signature or key 
     423         
     424        @type length: int 
     425        @param lenth: length must always be given. A signature or key 
     426        is always the last thing in an RR and so you can always determine 
     427        its length.  
     428        ''' 
     429        self.string = '' 
     430        if length == None: 
     431            return 
     432         
     433        assert isinstance(length, int) 
     434        buff = readPrecisely(strio, length) 
     435        self.string = b64encode(buff) 
     436 
     437    def __eq__(self, other): 
     438        if isinstance(other, Sigstr): 
     439            return self.string == other.string 
     440        return False 
     441 
     442    def __hash__(self): 
     443        return hash(self.string) 
     444 
     445    def __str__(self): 
     446        return self.string 
     447     
     448 
     449class TypeBitmaps(object): 
     450    ''' 
     451    bitmap encoding scheme used by NSEC and NSEC3 RR's 
     452    to indicate the RRset types that exist at the  
     453    NSEC/NSEC3 RR's original owner name or hashed name.   
     454    See RFC 4034 and RFC 5155. 
     455    ''' 
     456    fmt = 'BB' 
     457    typeRegex = re.compile('TYPE(\d+)') 
     458     
     459    def __init__(self, string=''): 
     460        self.string = string 
     461         
     462    def encode(self, strio, compDict=None): 
     463        """ 
     464        Encode the string field, which consists of a set  
     465        of type names, into an NSEC/NSEC3 type bitmap. 
     466         
     467        @type strio: file 
     468        @param strio: the byte representation of the type bitmap 
     469        will be written to this file. 
     470         
     471        @type compDict: dict 
     472        @param compDict: not used. 
     473        """ 
     474        if not self.string: 
     475            return; 
     476         
     477        #get a sorted list of RR Type Values 
     478        mnus = self.string.split(' ') 
     479        mnuVals = [] 
     480        for mnu in mnus: 
     481            mnuVal = REV_TYPES.get(mnu, None) 
     482            if not mnuVal: 
     483                m = self.typeRegex.match(mnu) 
     484                if m.groups(): 
     485                    mnuVal = int(m.group(1)) 
     486                    assert mnuVal < 65536 
     487                else: 
     488                    log.err("can't parse %s in %s" % (mnu, self.string, )) 
     489                    continue; 
     490            mnuVals.append(mnuVal) 
     491        mnuVals.sort() 
     492         
     493        #convert that to a dict of windows and lists 
     494        windDict = {} 
     495        for v in mnuVals: 
     496            window = (v >> 8) & 0xFF 
     497            if window not in windDict: 
     498                windDict[window] = [] 
     499            windDict[window].append(v & 0xFF) 
     500         
     501        #have to sort the keys - they're not in order! 
     502        windows = windDict.keys() 
     503        windows.sort() 
     504 
     505        #create the bitmaps 
     506        bmap = bytearray() 
     507        for w in windows: 
     508            bmapseg = bytearray(32) 
     509            maxoff = 0 
     510            for v in windDict[w]: 
     511                vm1 = v - 1 
     512                off = vm1 >> 3 
     513                bit = vm1 & 0x7 
     514                msk = 1 << bit 
     515                bmapseg[off] |= msk 
     516                maxoff = max(off, maxoff) 
     517            bmapseg = bmapseg[0:maxoff+1] 
     518            bmap += chr(w) + chr(maxoff+1) + bmapseg 
     519         
     520        strio.write(str(bmap)) 
     521     
     522    def decode(self, strio, length=None): 
     523        """ 
     524        Decode an NSEC/NSEC3 type bitmap into a string 
     525        representation of type names. 
     526        """ 
     527        self.type_bitmaps = "" 
     528        if length == None: 
     529            return 
     530 
     531        type_bitmaps = bytearray() 
     532        l = struct.calcsize(self.fmt) 
     533        parsed_length = 0 
     534        while parsed_length < length: 
     535            buff = readPrecisely(strio, l) 
     536            wb_num, bm_len = struct.unpack(self.fmt, buff) 
     537            assert parsed_length + 2 + bm_len <= length 
     538            bm = readPrecisely(strio, bm_len) 
     539            byteNum = -1 
     540            for b in bm: 
     541                byteNum += 1 
     542                ob = ord(b) 
     543                if ob == 0: 
     544                    continue 
     545                 
     546                for v in range(8): 
     547                    msk = 1<<v 
     548                    if ob & msk: 
     549                        val = wb_num*256 + byteNum*8 + v + 1 
     550                        mnu = QUERY_TYPES.get(val, None) 
     551                        if not mnu: 
     552                            mnu = 'TYPE' + str(val) 
     553                        type_bitmaps += (mnu + ' ')                         
     554             
     555            parsed_length += 2 + bm_len 
     556             
     557        self.type_bitmaps = str(type_bitmaps[0:-1]) 
     558 
     559    def __eq__(self, other): 
     560        if isinstance(other, TypeBitmaps): 
     561            return self.string == other.string 
     562        return False 
     563 
     564    def __hash__(self): 
     565        return hash(self.string) 
     566 
     567    def __str__(self): 
     568        return self.string 
     569 
     570 
    374571class Query: 
    375572    """ 
    376573    Represent a single DNS query. 
     
    434631        return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 
    435632 
    436633 
    437 class RRHeader(tputil.FancyEqMixin): 
     634     
     635class OPTHeader(tputil.FancyEqMixin): 
    438636    """ 
     637    A OPT record header. 
     638 
     639    @cvar fmt: C{str} specifying the byte format of an OPT Header. 
     640 
     641    @ivar name: Root (0, 8-bits) 
     642    @ivar type: 41 (OPT Record) 
     643    @ivar payload: An object that implements the IEncodable interface 
     644    @ivar auth: Whether this header is authoritative or not. 
     645    """ 
     646 
     647    implements(IEncodable) 
     648 
     649    compareAttributes = ('name', 'type', 'payload', 'auth') 
     650 
     651    fmt = "!H" 
     652 
     653    name = None 
     654    type = None 
     655    payload = None 
     656 
     657    #OPTHeader _really_ has no ttl or rdlength, but the 
     658    #existence of the attributes is required. 
     659    ttl = None 
     660    rdlength = None 
     661 
     662    cachedResponse = None 
     663 
     664    def __init__(self, payload=None, auth=False): 
     665        """ 
     666        @type name: C{str} 
     667        @param name: Root (0) 
     668 
     669        @type type: C{int} 
     670        @param type: Query type 41. 
     671 
     672        @type payload: An object implementing C{IEncodable} 
     673        @param payload: The OPT payload 
     674        """ 
     675        assert (payload is None) or (payload.TYPE == OPT) 
     676 
     677        self.name = 0 
     678        self.type = OPT 
     679        self.payload = payload 
     680        self.auth = auth 
     681 
     682    def encode(self, strio, compDict=None): 
     683        strio.write(struct.pack('!B', 0)) 
     684        strio.write(struct.pack(self.fmt, self.type)) 
     685        if self.payload: 
     686            prefix = strio.tell() 
     687            self.payload.encode(strio, compDict) 
     688            aft = strio.tell() 
     689            strio.seek(prefix - 2, 0) 
     690            strio.write(struct.pack('!H', aft - prefix)) 
     691            strio.seek(aft, 0) 
     692 
     693    def decode(self, strio, length = None): 
     694        self.name.decode(strio) 
     695        l = struct.calcsize(self.fmt) 
     696        buff = readPrecisely(strio, l) 
     697        r = struct.unpack(self.fmt, buff) 
     698        self.type = r[0] 
     699 
     700    def isAuthoritative(self): 
     701        return self.auth 
     702 
     703    def __str__(self): 
     704        return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 
     705 
     706    @staticmethod 
     707    def factory(strio): 
     708        ''' 
     709        reads enough of the stream to figure out if what is there is 
     710        an OPTHeader or an RRHeader 
     711        ''' 
     712        beginPos = strio.tell() 
     713        name = Name() 
     714        name.decode(strio) 
     715        type = struct.unpack(OPTHeader.fmt, readPrecisely(strio, 2))[0] 
     716         
     717        if len(name.name) == 0 and type == OPT: 
     718            return OPTHeader() 
     719        else: 
     720            #back up to the beginning and try again 
     721            strio.seek(beginPos, 0) 
     722            rrh = RRHeader() 
     723            rrh.decode(strio) 
     724            return rrh 
     725         
     726    __repr__ = __str__ 
     727     
     728     
     729class RRHeader(OPTHeader): 
     730    """ 
    439731    A resource record header. 
    440732 
    441733    @cvar fmt: C{str} specifying the byte format of an RR. 
     
    14671759        return hash(tuple(self.data)) 
    14681760 
    14691761 
     1762class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1763    """ 
     1764    EDNS0 Option record. 
     1765     
     1766    @type payload_size: C{int} 
     1767    @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 
     1768        network can handle. 
     1769     
     1770    @type dnssecOk: C{bool} 
     1771    @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 
     1772        validation (and set the AD bit if the response validates). 
     1773         
     1774    @type version: C{int} 
     1775    @ivar version: The version of DNSSEC used. Currently only version 0  
     1776        is defined. 
     1777    """ 
     1778    implements(IEncodable, IRecord) 
     1779    TYPE = OPT 
     1780    fmt = '!HBBHH' 
     1781     
     1782    fancybasename = 'OPT' 
     1783    showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 
     1784    compareAttributes = ('payload_size', 'flags', 'version') 
     1785     
     1786    def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 
     1787        self.payload_size = payload_size 
     1788        self.version = version 
     1789        self.flags = (dnssecOk & 1) << 15 
     1790         
     1791    def encode(self, strio, compDict = None): 
     1792        OPTHeader().encode(strio) 
     1793        strio.write(struct.pack('!H', self.payload_size)) 
     1794        strio.write(struct.pack('!B', 0)) # high order 0 
     1795        strio.write(struct.pack('!B', self.version)) 
     1796        strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 
     1797        strio.write(struct.pack('!H', 0)) # Data length: 0 
     1798         
     1799    def decode(self, strio, length=None): 
     1800        ''' 
     1801        are OPT Records always 0 rdlength? 
     1802        ''' 
     1803        l = struct.calcsize(self.fmt) 
     1804        buff = readPrecisely(strio, l) 
     1805        r = struct.unpack(self.fmt, buff) 
     1806        self.payload_size, z, self.version, self.flags, length = r 
     1807        assert length == 0 
     1808         
     1809    def __hash__(self): 
     1810        return hash((self.payload_size, self.version, self.flags)) 
    14701811 
     1812class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1813    """ 
     1814    DNSSEC RRSIG record.  See RFC 4034 for details. 
     1815     
     1816    @type type_covered: C{int} 
     1817    @ivar type_covered: Identifies the type of the RRset that this RRSIG covers.  
     1818     
     1819    @type algo: C{int} 
     1820    @ivar algo: Identifies the crypto algorithm type used to create the signature. 
     1821        (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 
     1822     
     1823    @type labels: C{int} 
     1824    @ivar labels: Specifies the number of labels in the original RRSIG RR owner name. 
     1825        A validator can use this to determine whether the answer was synthesized from 
     1826        a wildcard. 
     1827     
     1828    @type original_ttl: C{int} 
     1829    @ivar original_ttl: Specifies the TTL of the covered RRset as it appears in the  
     1830        authoritative zone. 
     1831     
     1832    @type sig_expiration: C{int}  
     1833    @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 
     1834        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1835     
     1836    @type sig_inception: C{int}  
     1837    @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 
     1838        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1839     
     1840    @type key_tag: C{int} 
     1841    @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates this 
     1842        signature, in network byte order. See RFC 4034 App B. 
     1843     
     1844    @type signers_name: L{Name} 
     1845    @ivar signers_name: Identifies the owner name of the DNSKEY RR that a validator 
     1846        should use to validate this signature. Must not use DNS name compression. 
     1847     
     1848    @type signature: L{Sigstr} 
     1849    @ivar signature: Contains the cryptographic signature that covers the RRSIG 
     1850        RDATA (excluding the Signature field and the RRset specified by the  RRSIG 
     1851        owner name, RRSIG class and RRSIG Type Covered fields. 
     1852     
     1853    @type ttl: C{int} 
     1854    @ivar ttl: The maximum number of seconds which this record should be 
     1855        cached. 
     1856    """ 
     1857    implements(IEncodable, IRecord) 
     1858    TYPE = RRSIG 
     1859    fmt = '!HBBIIIH' 
     1860     
     1861    fancybasename = 'RRSIG' 
     1862    showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1863                         ('_sig_expiration', 'sig_expiration', '%s'), 
     1864                         ('_sig_inception', 'sig_inception', '%s'), 
     1865                         'key_tag',  
     1866                         ('signers_name', 'signers_name', '%s'),  
     1867                         ('_signature', 'signature', '%s'), 'ttl') 
     1868    compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1869                         'sig_expiration', 'sig_inception', 'key_tag',  
     1870                         'signers_name', 'signature', 'ttl') 
     1871     
     1872    _sig_expiration = property(lambda self: str(self.sig_expiration)) 
     1873    _sig_inception = property(lambda self: str(self.sig_inception)) 
     1874    _signature = property(lambda self: self.signature.string) 
     1875     
     1876    def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0,  
     1877                 sig_expiration='', sig_inception='', key_tag=0,  
     1878                 signers_name='', signature='', ttl=None): 
     1879        self.type_covered = type_covered 
     1880        self.algo = algo 
     1881        self.labels = labels 
     1882        self.original_ttl = original_ttl 
     1883        self.sig_expiration = DateSNA(sig_expiration) 
     1884        self.sig_inception = DateSNA(sig_inception) 
     1885        self.key_tag = key_tag 
     1886        self.signers_name = Name(signers_name) 
     1887        self.signature = Sigstr(signature) 
     1888        self.ttl = str2time(ttl) 
     1889         
     1890    def encode(self, strio, compDict = None): 
     1891        strio.write(struct.pack(self.fmt,  
     1892                                self.type_covered, 
     1893                                self.algo,  
     1894                                self.labels, 
     1895                                self.original_ttl, 
     1896                                self.sig_expiration.asInt(), 
     1897                                self.sig_inception.asInt(), 
     1898                                self.key_tag)) 
     1899        self.signers_name.encode(strio, None) 
     1900        self.signature.encode(strio, compDict)         
     1901         
     1902    def decode(self, strio, length=None): 
     1903        start = strio.tell() 
     1904        l = struct.calcsize(self.fmt) 
     1905        buff = readPrecisely(strio, l) 
     1906        r = struct.unpack(self.fmt, buff)         
     1907        self.type_covered, self.algo, self.labels, self.original_ttl, \ 
     1908            sig_expiration, sig_inception, self.key_tag = r  
     1909        self.sig_expiration = DateSNA.fromInt(sig_expiration) 
     1910        self.sig_inception = DateSNA.fromInt(sig_inception) 
     1911        self.signers_name.decode(strio) 
     1912        here = strio.tell() 
     1913        self.signature.decode(strio, length + start - here if length else None) 
     1914                 
     1915    def __hash__(self): 
     1916        return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 
     1917                     self.sig_expiration, self.sig_inception, self.key_tag, 
     1918                     self.signers_name, self.signature))     
     1919 
     1920class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1921    """ 
     1922    A DNSSEC DS record. 
     1923     
     1924    @type key_tag: C{int} 
     1925    @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS record. 
     1926     
     1927    @type algo: C{int} 
     1928    @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this DS record.     
     1929 
     1930    @type digest_type: C{int} 
     1931    @ivar digest_type: Identifies the algorithm used to construct the digest field. 
     1932     
     1933    @type digest: L{Sigstr} 
     1934    @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by the 
     1935        algorithm identified by the digest_type field. 
     1936 
     1937    @type ttl: C{int} 
     1938    @ivar ttl: The maximum number of seconds which this record should be 
     1939        cached.     
     1940    """ 
     1941    implements(IEncodable, IRecord) 
     1942    TYPE = DS 
     1943    fmt = '!HBB' 
     1944     
     1945    fancybasename = 'DS' 
     1946    showAttributes = ('key_tag', 'algo', 'digest_type', ('_digest', 'digest', '%s'), 'ttl') 
     1947    compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 
     1948     
     1949    _digest = property(lambda self: self.digest.string) 
     1950 
     1951    def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 
     1952        self.key_tag = key_tag 
     1953        self.algo = algo 
     1954        self.digest_type = digest_type 
     1955        self.digest = Sigstr(digest) 
     1956        self.ttl = str2time(ttl) 
     1957         
     1958    def encode(self, strio, compDict = None): 
     1959        strio.write(struct.pack(self.fmt,  
     1960                                self.key_tag, 
     1961                                self.algo,  
     1962                                self.digest_type)) 
     1963        self.digest.encode(strio, None) 
     1964         
     1965    def decode(self, strio, length=None): 
     1966        start = strio.tell() 
     1967        l = struct.calcsize(self.fmt) 
     1968        buff = readPrecisely(strio, l) 
     1969        r = struct.unpack(self.fmt, buff)         
     1970        self.key_tag, self.algo, self.digest_type = r         
     1971        here = strio.tell() 
     1972        self.digest.decode(strio, length + start - here if length else None) 
     1973                 
     1974    def __hash__(self): 
     1975        return hash((self.key_tag, self.algo, self.digest_type, self.digest))     
     1976 
     1977class Record_DNSKey(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1978    """ 
     1979    A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 
     1980     
     1981    @type flags: C{int} 
     1982    @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 
     1983        DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 
     1984        the name of a zone.  If bit 7 has value 0, then the DNSKEY record 
     1985        holds some other type of DNS public key and MUST NOT be used to  
     1986        verify RRSIGs that cover RRsets.   
     1987        Bit 15 is the Secure Entry Point flag. See RFC 3757.)  
     1988        All other bits are reserved and must be zero. 
     1989         
     1990    @type protocol: C{int} 
     1991    @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 
     1992        if this field does not contain 3. 
     1993     
     1994    @type algo: C{int} 
     1995    @ivar algo: Identifies the public key's cryptographic algorithm and determines 
     1996        the format of the pub_key field.  See RFC 4034 App A. 
     1997     
     1998    @type pub_key: L{Sigstr} 
     1999    @ivar pub_key: Holds the public key material. 
     2000 
     2001    @type ttl: C{int} 
     2002    @ivar ttl: The maximum number of seconds which this record should be 
     2003        cached.     
     2004    """ 
     2005    implements(IEncodable, IRecord) 
     2006    TYPE = DNSKEY 
     2007    fmt = '!HBB' 
     2008     
     2009    fancybasename = 'DNSKEY' 
     2010    showAttributes = ('flags', 'protocol', 'algo', ('_pub_key', 'pub_key', '%s'), 'ttl') 
     2011    compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 
     2012     
     2013    _pub_key = property(lambda self: self.pub_key.string) 
     2014     
     2015    def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 
     2016        self.flags = flags 
     2017        self.protocol = protocol 
     2018        self.algo = algo 
     2019        self.pub_key = Sigstr(pub_key) 
     2020        self.ttl = str2time(ttl) 
     2021         
     2022    def encode(self, strio, compDict = None): 
     2023        strio.write(struct.pack(self.fmt,  
     2024                                self.flags, 
     2025                                self.protocol,  
     2026                                self.algo)) 
     2027        self.pub_key.encode(strio, None) 
     2028         
     2029    def decode(self, strio, length=None): 
     2030        start = strio.tell() 
     2031        l = struct.calcsize(self.fmt) 
     2032        buff = readPrecisely(strio, l) 
     2033        r = struct.unpack(self.fmt, buff)         
     2034        self.flags, self.protocol, self.algo = r         
     2035        here = strio.tell() 
     2036        self.pub_key.decode(strio, length + start - here if length else None) 
     2037                 
     2038    def __hash__(self): 
     2039        return hash((self.flags, self.protocol, self.algo, self.pub_key)) 
     2040 
     2041class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2042    """ 
     2043    A DNSSEC NSEC record provides authenticated denial of existance for DNS data.  
     2044 
     2045    A DNSSEC NSEC record lists: 
     2046     
     2047        1) the next owner name in canonical ordering of the zone that contains authoritataive 
     2048           data or a delegation point NS RRset. 
     2049         
     2050        2) the set of RR types present at the NSEC RR's owner name. 
     2051 
     2052    @type nxt_name: L{Name} 
     2053    @ivar nxt_name: The next owner name that has authoritative data or contains a 
     2054        delegation point NS RRset. 
     2055     
     2056    @type type_bitmaps: L{TypeBitmaps} 
     2057    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's owner name. 
     2058     
     2059    @type ttl: C{int} 
     2060    @ivar ttl: The maximum number of seconds which this record should be 
     2061        cached. 
     2062    """ 
     2063    implements(IEncodable, IRecord) 
     2064    TYPE = NSEC 
     2065     
     2066    fancybasename = 'NSEC' 
     2067    showAttributes = (('nxt_name', 'nxt_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2068    compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 
     2069     
     2070    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2071     
     2072    def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 
     2073        self.nxt_name = Name(nxt_name) 
     2074        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2075        self.ttl = str2time(ttl) 
     2076         
     2077    def encode(self, strio, compDict = None): 
     2078        self.nxt_name.encode(strio, None) 
     2079        self.type_bitmaps.encode(strio, None) 
     2080         
     2081    def decode(self, strio, length=None): 
     2082        start = strio.tell() 
     2083        self.nxt_name.decode(strio, None) 
     2084        here = strio.tell() 
     2085        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2086                 
     2087    def __hash__(self): 
     2088        return hash((self.nxt_name, self.type_bitmaps)) 
     2089 
     2090class Record_NSEC3(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2091    """ 
     2092    A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of existance  
     2093    for DNS data and permits a gradual expansion of delegation-centric zones.  
     2094 
     2095    A DNSSEC NSEC3 record lists: 
     2096     
     2097        1) the set of RR types present at the original owner name of the NSEC RR. 
     2098 
     2099        2) the next hashed owner name in the hash order of the zone. 
     2100 
     2101    @type hash_algo: C{int} 
     2102    @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 
     2103     
     2104    @type flags: C{int} 
     2105    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the  
     2106        opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 
     2107        delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 
     2108     
     2109    @type iterations: C{int} 
     2110    @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 
     2111     
     2112    @type salt: L{Charset} 
     2113    @ivar salt: Identifies the salt value provided to the hash. 
     2114     
     2115    @type nxt_hash_owner_name: L{Charset} 
     2116    @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone in hash order. 
     2117     
     2118    @type type_bitmaps: L{TypeBitmaps} 
     2119    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's original owner name. 
     2120     
     2121    @type ttl: C{int} 
     2122    @ivar ttl: The maximum number of seconds which this record should be 
     2123        cached. 
     2124    """ 
     2125    implements(IEncodable, IRecord) 
     2126    TYPE = NSEC3 
     2127    fmt = '!BBH' 
     2128     
     2129    fancybasename = 'NSEC3' 
     2130    showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2131    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 
     2132     
     2133    _salt = property(lambda self: self.salt.string) 
     2134    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2135     
     2136    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', nxt_hash_owner='', type_bitmaps=None, ttl=None): 
     2137        self.hash_algo = hash_algo 
     2138        self.flags = flags 
     2139        self.iterations = iterations 
     2140        self.salt = Charstr(salt) 
     2141        self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 
     2142        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2143        self.ttl = str2time(ttl) 
     2144         
     2145    def encode(self, strio, compDict = None): 
     2146        strio.write(struct.pack(self.fmt, 
     2147                                self.hash_algo, 
     2148                                self.flags, 
     2149                                self.iterations)) 
     2150        self.salt.encode(strio, None) 
     2151        self.nxt_hash_owner_name.encode(strio, None) 
     2152        self.type_bitmaps.encode(strio, None) 
     2153         
     2154    def decode(self, strio, length=None): 
     2155        start = strio.tell() 
     2156        l = struct.calcsize(self.fmt) 
     2157        buff = readPrecisely(strio, l) 
     2158        r = struct.unpack(self.fmt, buff)         
     2159        self.hash_algo, self.flags, self.iterations = r    
     2160        self.salt.decode(strio) 
     2161        self.nxt_hash_owner_name.decode(strio) 
     2162        here = strio.tell() 
     2163        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2164                 
     2165    def __hash__(self): 
     2166        return hash((self.hash_algo, self.flags, self.iterations, self.salt, 
     2167                     self.nxt_hash_owner_name, self.type_bitmaps)) 
     2168     
    14712169# This is a fallback record 
    14722170class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 
    14732171    """ 
     
    15442242    queries = answers = add = ns = None 
    15452243 
    15462244    def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 
    1547                        auth=0, rCode=OK, trunc=0, maxSize=512): 
     2245                 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 
    15482246        self.maxSize = maxSize 
    15492247        self.id = id 
    15502248        self.answer = answer 
    15512249        self.opCode = opCode 
    1552         self.auth = auth 
    1553         self.trunc = trunc 
    1554         self.recDes = recDes 
    1555         self.recAv = recAv 
     2250        self.auth = auth            #AA - Authoritative Answer 
     2251        self.trunc = trunc          #TC - TrunCated 
     2252        self.recDes = recDes        #RD - Recursion Desired 
     2253        self.recAv = recAv          #RA - Recursion Available 
     2254        self.authData = authData    #AD - Authentic Data 
     2255        self.chkDis = chkDis        #CD - Checking Disabled 
    15562256        self.rCode = rCode 
    15572257        self.queries = [] 
    15582258        self.answers = [] 
     
    15972297                 | ((self.auth & 1 ) << 2 ) 
    15982298                 | ((self.trunc & 1 ) << 1 ) 
    15992299                 | ( self.recDes & 1 ) ) 
    1600         byte4 = ( ( (self.recAv & 1 ) << 7 ) 
     2300        byte4 = (  ((self.recAv & 1 ) << 7 ) 
     2301                  |((self.authData & 1 ) << 5 ) 
     2302                  |((self.chkDis & 1 ) << 4 ) 
    16012303                  | (self.rCode & 0xf ) ) 
    16022304 
    16032305        strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, 
     
    16172319        self.trunc = ( byte3 >> 1 ) & 1 
    16182320        self.recDes = byte3 & 1 
    16192321        self.recAv = ( byte4 >> 7 ) & 1 
     2322        self.authData = ( byte4 >> 5 ) & 1 
     2323        self.chkDis = ( byte4 >> 4 ) & 1 
    16202324        self.rCode = byte4 & 0xf 
    16212325 
    16222326        self.queries = [] 
     
    16352339 
    16362340    def parseRecords(self, list, num, strio): 
    16372341        for i in range(num): 
    1638             header = RRHeader() 
    16392342            try: 
    1640                 header.decode(strio) 
     2343                header = OPTHeader.factory(strio) 
    16412344            except EOFError: 
    16422345                return 
    16432346            t = self.lookupRecordType(header.type) 
     
    17472450            query, or errbacked with any errors that could happen (exceptions 
    17482451            during writing of the query, timeout errors, ...). 
    17492452        """ 
    1750         m = Message(id, recDes=1) 
     2453        m = Message(id, recDes=self.controller.dnssecConfig.recDes) 
    17512454        m.queries = queries 
     2455        if self.controller.dnssecConfig.ednsEnabled: 
     2456            authData=self.controller.dnssecConfig.authData 
     2457            chkDis=self.controller.dnssecConfig.chkDis 
     2458            m.additional = [Record_OPT(payload_size = self.controller.dnssecConfig.maxUdpPktSz, 
     2459                                       version = self.controller.dnssecConfig.version, 
     2460                                       dnssecOk = self.controller.dnssecConfig.dnssecOk)] 
    17522461 
    17532462        try: 
    17542463            writeMessage(m) 
     
    18022511        self.transport.write(message.toStr(), address) 
    18032512 
    18042513    def startListening(self): 
    1805         self._reactor.listenUDP(0, self, maxPacketSize=512) 
     2514        maxPacketSize = 512 
     2515        if self.controller.dnssecConfig.ednsEnabled: 
     2516            maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 
     2517        self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 
    18062518 
    18072519    def datagramReceived(self, data, addr): 
    18082520        """ 
  • names/serialNumberArithmetic.py

     
     1#!/usr/bin/env python 
     2# 
     3# RFC 1982 DNS Serial Number Arithmetic 
     4# RFC 4034 DNSSEC Signature Expiration and Inception Fields 
     5# 
     6# bob.novas@shinkuro.com 
     7# 
     8 
     9class SNA(object): 
     10    """ 
     11    implements RFC 1982 - DNS Serial Number Arithmetic 
     12    """ 
     13    SERIAL_BITS = 32 
     14    MODULOVAL = 2**SERIAL_BITS 
     15    HLFRNG = 2**(SERIAL_BITS-1) 
     16    MAXADD = (2**(SERIAL_BITS-1)-1) 
     17     
     18    def __init__(self, number): 
     19        self._number = int(number)%self.MODULOVAL 
     20         
     21    def __repr__(self): 
     22        return str(self._number) 
     23         
     24    def EQ(self, sna2): 
     25        assert isinstance(sna2, SNA) 
     26        return sna2._number == self._number 
     27     
     28    def LT(self, sna2): 
     29        assert isinstance(sna2, SNA) 
     30        return not self.EQ(sna2) and \ 
     31               ((self._number < sna2._number) and ((sna2._number - self._number) < self.HLFRNG) or \ 
     32                (self._number > sna2._number) and ((self._number - sna2._number) > self.HLFRNG)) 
     33 
     34    def GT(self, sna2): 
     35        assert isinstance(sna2, SNA) 
     36        return not self.EQ(sna2) and \ 
     37               ((self._number < sna2._number) and ((sna2._number - self._number) > self.HLFRNG) or \ 
     38                (self._number > sna2._number) and ((self._number - sna2._number) < self.HLFRNG)) 
     39     
     40    def LE(self, sna2): 
     41        return self.EQ(sna2) or self.LT(sna2) 
     42     
     43    def GE(self, sna2): 
     44        return self.EQ(sna2) or self.GT(sna2) 
     45 
     46    def Add(self, sna2): 
     47        assert isinstance(sna2, SNA) 
     48        if sna2.LE(SNA(self.MAXADD)): 
     49            return SNA( (self._number + sna2._number)%self.MODULOVAL ) 
     50        else: 
     51            raise ArithmeticError 
     52         
     53    def __hash__(self): 
     54        return hash(self._number) 
     55     
     56    __eq__  = EQ 
     57    __lt__  = LT 
     58    __gt__  = GT 
     59    __le__  = LE 
     60    __ge__  = GE 
     61    __add__ = Add 
     62         
     63    @staticmethod 
     64    def Max(snaList): 
     65        """ 
     66        this takes a list of sna's from which it will pick the sn with the highest value 
     67        """ 
     68        if len(snaList) == 0: 
     69            return None 
     70        trialMax = snaList[0] 
     71        for s in snaList[1:]: 
     72            if not trialMax: 
     73                trialMax = s 
     74            elif s and s.GT(trialMax): 
     75                trialMax = s 
     76        return trialMax 
     77 
     78import calendar, time 
     79class DateSNA(SNA): 
     80    """ 
     81    implements DNS Serial Number Arithmetic 
     82    for dates 'YYYYMMDDHHMMSS' per RFC 4034 P3.1.5 
     83    """ 
     84    fmt = '%Y%m%d%H%M%S' 
     85 
     86    def __init__(self, utcDateTime=''): 
     87        ''' 
     88        accept a UTC date/time string as YYMMDDHHMMSS 
     89        and convert it to seconds since the epoch 
     90        ''' 
     91        if not utcDateTime: 
     92            utcDateTime = '19700101000000' 
     93        dtstruct = time.strptime(utcDateTime, DateSNA.fmt) 
     94        assert dtstruct.tm_year < 1970+136 
     95        secondsSinceE = calendar.timegm(dtstruct) 
     96        super(DateSNA, self).__init__(secondsSinceE) 
     97     
     98    def Add(self, sna2): 
     99        if not isinstance(sna2, SNA): 
     100            return NotImplemented 
     101         
     102        if sna2.LE(SNA(self.MAXADD)) and (self._number + sna2._number < self.MODULOVAL): 
     103            sna = SNA((self._number + sna2._number)%self.MODULOVAL) 
     104            return DateSNA.fromSNA(sna) 
     105        else: 
     106            raise ArithmeticError 
     107     
     108    def asDate(self): 
     109        dtstruct = time.gmtime(self._number) 
     110        return time.strftime(DateSNA.fmt, dtstruct) 
     111     
     112    def asInt(self): 
     113        return self._number 
     114     
     115    @staticmethod 
     116    def fromSNA(sna): 
     117        assert isinstance(sna, SNA) 
     118        d = DateSNA() 
     119        d._number = sna._number 
     120        return d 
     121     
     122    @staticmethod 
     123    def fromInt(i): 
     124        return DateSNA.fromSNA(SNA(i)) 
     125         
     126    def __str__(self): 
     127        return self.asDate() 
     128 
     129     
     130if __name__ == "__main__": 
     131 
     132    s1 = SNA(1) 
     133    s1a = SNA(1) 
     134    s2 = SNA(2) 
     135     
     136    assert s1 == s1a 
     137    assert hash(s1) == hash(s1a) 
     138    assert s1 <= s1a 
     139    assert s1 >= s1a 
     140    assert s1 <  s2 
     141    assert not s1 > s2 
     142    assert s1 <= s2 
     143    assert not s1 >= s2  
     144     
     145    smaxval = SNA(SNA.HLFRNG+SNA.HLFRNG-1) 
     146    smaxplus1 = smaxval.Add(s1) 
     147    smaxadd = SNA(SNA.MAXADD) 
     148     
     149    assert smaxplus1 > smaxval 
     150    assert s1 + smaxadd 
     151    assert SNA.Max([None, s1]) == s1 
     152    assert SNA.Max([s1, None]) == s1 
     153     
     154    date1 = DateSNA('20120101000000')  
     155    date2 = DateSNA('20130101000000') 
     156    assert date1 < date2 
     157     
     158    date3 = DateSNA('20370101000000') 
     159    sna1  = SNA(365*24*60*60) 
     160    date4 = date3 + sna1 
     161    assert date4._number ==  date3._number + sna1._number 
     162     
     163    date5 = DateSNA() 
     164    date6 = date5 + SNA(24*60*60) 
     165    assert date6._number == date5._number + 24*60*60 
     166     
     167    date7 = DateSNA('20370101000000') 
     168    date8 = date7 + sna1 
     169    assert date8._number == date7._number + sna1._number 
     170     
     171     
     172 No newline at end of file 
  • names/test/test_client.py

     
    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_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_nsec3(self): 
     944        """ 
     945        The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, iterations, 
     946        salt, nxt_hash_owner_name, type_bitmaps and ttl fields of the record. 
     947        """ 
     948        self.assertEqual( 
     949            repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', "\x1fabcd", ttl=31)), 
     950            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 nxt_hash_owner_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     951     
     952    def test_opt(self): 
     953        """ 
     954        The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk flag,  
     955        and version fields of the record. (The OPT record has no ttl field.) 
     956        """ 
     957        self.assertEqual( 
     958            repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 
     959                 "<OPT payload_size=1492 flags=0x8000 version=0>") 
    843960 
     961    def test_rrsig(self): 
     962        """ 
     963        The repr of a L{dns.RRSIG} instance includes the algo, labels, original_ttl 
     964        sig_expiration, sig_inception, key_tag, signers_name, signature and ttl  
     965        fields of the record. 
     966        """ 
     967        self.assertEqual( 
     968            repr(dns.Record_RRSIG(type_covered=dns.A, 
     969                                  algo=2, 
     970                                  labels=3, 
     971                                  original_ttl=30, 
     972                                  sig_expiration='20110101123456', 
     973                                  sig_inception= '20110202112233', 
     974                                  key_tag=60, 
     975                                  signers_name='bob', 
     976                                  signature='\x12\x34sig', 
     977                                  ttl=70)), 
     978                 "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 
     979                + " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 
     980                + " signers_name=bob signature=\x12\x34sig ttl=70>") 
    844981 
    845982class _Equal(object): 
    846983    """ 
     
    9081045            cls('example.com', 123), 
    9091046            cls('example.org', 123)) 
    9101047 
     1048    def test_optheader(self): 
     1049        """ 
     1050        Two OptHeader instances comapare equal iff the have the same 
     1051        (Record_OPT) payload and auth bit. 
     1052        """ 
     1053        self._equalityTest( 
     1054            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 
     1055            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 
     1056            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492, dnssecOk=False, version=0, ttl=40), auth=True)) 
    9111057 
    9121058    def test_rrheader(self): 
    9131059        """ 
     
    14301576            dns.UnknownRecord('foo', ttl=10), 
    14311577            dns.UnknownRecord('foo', ttl=10), 
    14321578            dns.UnknownRecord('foo', ttl=100)) 
     1579 
     1580    def test_rrsig(self): 
     1581        """ 
     1582        L(dns.RRSIG) instances compare equal iff they have the same 
     1583        type_covered, algo, labels, original_ttl, sig_expiration, sig_inception,  
     1584        key_tag, signers_name, signature, and ttl 
     1585        """ 
     1586        self._equalityTest( 
     1587            dns.Record_RRSIG(type_covered=dns.A), 
     1588            dns.Record_RRSIG(type_covered=dns.A), 
     1589            dns.Record_RRSIG(type_covered=dns.AAAA)) 
     1590        self._equalityTest( 
     1591            dns.Record_RRSIG(algo=1), 
     1592            dns.Record_RRSIG(algo=1), 
     1593            dns.Record_RRSIG(algo=2)) 
     1594        self._equalityTest( 
     1595            dns.Record_RRSIG(labels=3), 
     1596            dns.Record_RRSIG(labels=3), 
     1597            dns.Record_RRSIG(labels=4)) 
     1598        self._equalityTest( 
     1599            dns.Record_RRSIG(original_ttl=5), 
     1600            dns.Record_RRSIG(original_ttl=5), 
     1601            dns.Record_RRSIG(original_ttl=6)) 
     1602        self._equalityTest( 
     1603            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1604            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1605            dns.Record_RRSIG(sig_expiration='20110101000001')) 
     1606        self._equalityTest( 
     1607            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1608            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1609            dns.Record_RRSIG(sig_inception='20120101000001')) 
     1610        self._equalityTest( 
     1611            dns.Record_RRSIG(key_tag=11), 
     1612            dns.Record_RRSIG(key_tag=11), 
     1613            dns.Record_RRSIG(key_tag=12)) 
     1614        self._equalityTest( 
     1615            dns.Record_RRSIG(signers_name='bob'), 
     1616            dns.Record_RRSIG(signers_name='bob'), 
     1617            dns.Record_RRSIG(signers_name='joe')) 
     1618        self._equalityTest( 
     1619            dns.Record_RRSIG(signature='abcdef'), 
     1620            dns.Record_RRSIG(signature='abcdef'), 
     1621            dns.Record_RRSIG(signature='abcdefg')) 
     1622        self._equalityTest( 
     1623            dns.Record_RRSIG(ttl=10), 
     1624            dns.Record_RRSIG(ttl=10), 
     1625            dns.Record_RRSIG(ttl=20)) 
     1626         
     1627    def test_ds(self): 
     1628        """ 
     1629        L(dns.DS) instances compare equal iff they have the same 
     1630        key_tag, algo, digest_type, digest and ttl 
     1631        """ 
     1632        self._equalityTest( 
     1633            dns.Record_DS(key_tag=1), 
     1634            dns.Record_DS(key_tag=1), 
     1635            dns.Record_DS(key_tag=2)) 
     1636        self._equalityTest( 
     1637            dns.Record_DS(algo=3), 
     1638            dns.Record_DS(algo=3), 
     1639            dns.Record_DS(algo=4)) 
     1640        self._equalityTest( 
     1641            dns.Record_DS(digest_type=5), 
     1642            dns.Record_DS(digest_type=5), 
     1643            dns.Record_DS(digest_type=6)) 
     1644        self._equalityTest( 
     1645            dns.Record_DS(digest='abcdef-digest'), 
     1646            dns.Record_DS(digest='abcdef-digest'), 
     1647            dns.Record_DS(digest='abcdef-digest-f')) 
     1648        self._equalityTest( 
     1649            dns.Record_DS(ttl=10), 
     1650            dns.Record_DS(ttl=10), 
     1651            dns.Record_DS(ttl=20)) 
     1652 
     1653    def test_dnskey(self): 
     1654        """ 
     1655        L(dns.DNSKEY) instances compare equal iff they have the same 
     1656        flags, protocol, algo, pub_key and ttl 
     1657        """ 
     1658        self._equalityTest( 
     1659            dns.Record_DNSKey(flags=1), 
     1660            dns.Record_DNSKey(flags=1), 
     1661            dns.Record_DNSKey(flags=2)) 
     1662        self._equalityTest( 
     1663            dns.Record_DNSKey(protocol=3), 
     1664            dns.Record_DNSKey(protocol=3), 
     1665            dns.Record_DNSKey(protocol=4)) 
     1666        self._equalityTest( 
     1667            dns.Record_DNSKey(algo=5), 
     1668            dns.Record_DNSKey(algo=5), 
     1669            dns.Record_DNSKey(algo=6)) 
     1670        self._equalityTest( 
     1671            dns.Record_DNSKey(pub_key='abcdef-digest'), 
     1672            dns.Record_DNSKey(pub_key='abcdef-digest'), 
     1673            dns.Record_DNSKey(pub_key='abcdef-digest-f')) 
     1674        self._equalityTest( 
     1675            dns.Record_DNSKey(ttl=10), 
     1676            dns.Record_DNSKey(ttl=10), 
     1677            dns.Record_DNSKey(ttl=20)) 
     1678 
     1679    def test_nsec(self): 
     1680        """ 
     1681        L(dns.DNSKEY) instances compare equal iff they have the same 
     1682        nxt_name, type_bitmaps and ttl 
     1683        """ 
     1684        self._equalityTest( 
     1685            dns.Record_NSEC(nxt_name="example.com"), 
     1686            dns.Record_NSEC(nxt_name="example.com"), 
     1687            dns.Record_NSEC(nxt_name="a.example.com")) 
     1688        self._equalityTest( 
     1689            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1690            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1691            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1692        self._equalityTest( 
     1693            dns.Record_NSEC(ttl=5), 
     1694            dns.Record_NSEC(ttl=5), 
     1695            dns.Record_NSEC(ttl=6)) 
     1696 
     1697    def test_nsec3(self): 
     1698        """ 
     1699        L(dns.DNSKEY) instances compare equal iff they have the same 
     1700        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1701        """ 
     1702        self._equalityTest( 
     1703            dns.Record_NSEC3(hash_algo=1), 
     1704            dns.Record_NSEC3(hash_algo=1), 
     1705            dns.Record_NSEC3(hash_algo=2)) 
     1706        self._equalityTest( 
     1707            dns.Record_NSEC3(flags=1), 
     1708            dns.Record_NSEC3(flags=1), 
     1709            dns.Record_NSEC3(flags=2)) 
     1710        self._equalityTest( 
     1711            dns.Record_NSEC3(iterations=5), 
     1712            dns.Record_NSEC3(iterations=5), 
     1713            dns.Record_NSEC3(iterations=6)) 
     1714        self._equalityTest( 
     1715            dns.Record_NSEC3(salt="abcdef"), 
     1716            dns.Record_NSEC3(salt="abcdef"), 
     1717            dns.Record_NSEC3(salt="abcdefg")) 
     1718        self._equalityTest( 
     1719            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1720            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1721            dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 
     1722        self._equalityTest( 
     1723            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1724            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1725            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1726        self._equalityTest( 
     1727            dns.Record_NSEC3(ttl=5), 
     1728            dns.Record_NSEC3(ttl=5), 
     1729            dns.Record_NSEC3(ttl=6)) 
     1730 
     1731 
     1732                 
     1733 No newline at end of file 
  • names/test/test_names.py

     
    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}.