Ticket #5453: add-ends0-dnssec-record-types-01b.patch

File add-ends0-dnssec-record-types-01b.patch, 57.0 KB (added by BobNovas, 3 years ago)

whoops. Use this file in place of 1a. I forgot to add the new ser_num_arith.py file to svn

  • 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', 
    271  
     338    dns.DNSKEY:'lookupDNSKey', 
    272339    dns.RP:    'lookupResponsibility', 
    273340    dns.AFSDB: 'lookupAFSDatabase', 
    274341    dns.SRV:   'lookupService', 
  • 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.ser_num_arith 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, auth=False): 
     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(auth=auth) 
     726            rrh.decode(strio) 
     727            rrh.auth = auth 
     728            return rrh 
     729         
     730    __repr__ = __str__ 
     731     
     732     
     733class RRHeader(OPTHeader): 
     734    """ 
    439735    A resource record header. 
    440736 
    441737    @cvar fmt: C{str} specifying the byte format of an RR. 
     
    14691765        return hash(tuple(self.data)) 
    14701766 
    14711767 
     1768class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1769    """ 
     1770    EDNS0 Option record. 
     1771     
     1772    @type payload_size: C{int} 
     1773    @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 
     1774        network can handle. 
     1775     
     1776    @type dnssecOk: C{bool} 
     1777    @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 
     1778        validation (and set the AD bit if the response validates). 
     1779         
     1780    @type version: C{int} 
     1781    @ivar version: The version of DNSSEC used. Currently only version 0  
     1782        is defined. 
     1783    """ 
     1784    implements(IEncodable, IRecord) 
     1785    TYPE = OPT 
     1786    fmt = '!HBBHH' 
     1787     
     1788    fancybasename = 'OPT' 
     1789    showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 
     1790    compareAttributes = ('payload_size', 'flags', 'version') 
     1791     
     1792    def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 
     1793        self.payload_size = payload_size 
     1794        self.version = version 
     1795        self.flags = (dnssecOk & 1) << 15 
     1796         
     1797    def encode(self, strio, compDict = None): 
     1798        OPTHeader().encode(strio) 
     1799        strio.write(struct.pack('!H', self.payload_size)) 
     1800        strio.write(struct.pack('!B', 0)) # high order 0 
     1801        strio.write(struct.pack('!B', self.version)) 
     1802        strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 
     1803        strio.write(struct.pack('!H', 0)) # Data length: 0 
     1804         
     1805    def decode(self, strio, length=None): 
     1806        ''' 
     1807        are OPT Records always 0 rdlength? 
     1808        ''' 
     1809        l = struct.calcsize(self.fmt) 
     1810        buff = readPrecisely(strio, l) 
     1811        r = struct.unpack(self.fmt, buff) 
     1812        self.payload_size, z, self.version, self.flags, length = r 
     1813        assert length == 0 
     1814         
     1815    def __hash__(self): 
     1816        return hash((self.payload_size, self.version, self.flags)) 
    14721817 
     1818class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1819    """ 
     1820    DNSSEC RRSIG record.  See RFC 4034 for details. 
     1821     
     1822    @type type_covered: C{int} 
     1823    @ivar type_covered: Identifies the type of the RRset that this RRSIG covers.  
     1824     
     1825    @type algo: C{int} 
     1826    @ivar algo: Identifies the crypto algorithm type used to create the signature. 
     1827        (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 
     1828     
     1829    @type labels: C{int} 
     1830    @ivar labels: Specifies the number of labels in the original RRSIG RR owner name. 
     1831        A validator can use this to determine whether the answer was synthesized from 
     1832        a wildcard. 
     1833     
     1834    @type original_ttl: C{int} 
     1835    @ivar original_ttl: Specifies the TTL of the covered RRset as it appears in the  
     1836        authoritative zone. 
     1837     
     1838    @type sig_expiration: C{int}  
     1839    @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 
     1840        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1841     
     1842    @type sig_inception: C{int}  
     1843    @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 
     1844        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1845     
     1846    @type key_tag: C{int} 
     1847    @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates this 
     1848        signature, in network byte order. See RFC 4034 App B. 
     1849     
     1850    @type signers_name: L{Name} 
     1851    @ivar signers_name: Identifies the owner name of the DNSKEY RR that a validator 
     1852        should use to validate this signature. Must not use DNS name compression. 
     1853     
     1854    @type signature: L{Sigstr} 
     1855    @ivar signature: Contains the cryptographic signature that covers the RRSIG 
     1856        RDATA (excluding the Signature field and the RRset specified by the  RRSIG 
     1857        owner name, RRSIG class and RRSIG Type Covered fields. 
     1858     
     1859    @type ttl: C{int} 
     1860    @ivar ttl: The maximum number of seconds which this record should be 
     1861        cached. 
     1862    """ 
     1863    implements(IEncodable, IRecord) 
     1864    TYPE = RRSIG 
     1865    fmt = '!HBBIIIH' 
     1866     
     1867    fancybasename = 'RRSIG' 
     1868    showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1869                         ('_sig_expiration', 'sig_expiration', '%s'), 
     1870                         ('_sig_inception', 'sig_inception', '%s'), 
     1871                         'key_tag',  
     1872                         ('signers_name', 'signers_name', '%s'),  
     1873                         ('_signature', 'signature', '%s'), 'ttl') 
     1874    compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1875                         'sig_expiration', 'sig_inception', 'key_tag',  
     1876                         'signers_name', 'signature', 'ttl') 
     1877     
     1878    _sig_expiration = property(lambda self: str(self.sig_expiration)) 
     1879    _sig_inception = property(lambda self: str(self.sig_inception)) 
     1880    _signature = property(lambda self: self.signature.string) 
     1881     
     1882    def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0,  
     1883                 sig_expiration='', sig_inception='', key_tag=0,  
     1884                 signers_name='', signature='', ttl=None): 
     1885        self.type_covered = type_covered 
     1886        self.algo = algo 
     1887        self.labels = labels 
     1888        self.original_ttl = original_ttl 
     1889        self.sig_expiration = DateSNA(sig_expiration) 
     1890        self.sig_inception = DateSNA(sig_inception) 
     1891        self.key_tag = key_tag 
     1892        self.signers_name = Name(signers_name) 
     1893        self.signature = Sigstr(signature) 
     1894        self.ttl = str2time(ttl) 
     1895         
     1896    def encode(self, strio, compDict = None): 
     1897        strio.write(struct.pack(self.fmt,  
     1898                                self.type_covered, 
     1899                                self.algo,  
     1900                                self.labels, 
     1901                                self.original_ttl, 
     1902                                self.sig_expiration.asInt(), 
     1903                                self.sig_inception.asInt(), 
     1904                                self.key_tag)) 
     1905        self.signers_name.encode(strio, None) 
     1906        self.signature.encode(strio, compDict)         
     1907         
     1908    def decode(self, strio, length=None): 
     1909        start = strio.tell() 
     1910        l = struct.calcsize(self.fmt) 
     1911        buff = readPrecisely(strio, l) 
     1912        r = struct.unpack(self.fmt, buff)         
     1913        self.type_covered, self.algo, self.labels, self.original_ttl, \ 
     1914            sig_expiration, sig_inception, self.key_tag = r  
     1915        self.sig_expiration = DateSNA.fromInt(sig_expiration) 
     1916        self.sig_inception = DateSNA.fromInt(sig_inception) 
     1917        self.signers_name.decode(strio) 
     1918        here = strio.tell() 
     1919        self.signature.decode(strio, length + start - here if length else None) 
     1920                 
     1921    def __hash__(self): 
     1922        return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 
     1923                     self.sig_expiration, self.sig_inception, self.key_tag, 
     1924                     self.signers_name, self.signature))     
     1925 
     1926class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1927    """ 
     1928    A DNSSEC DS record. 
     1929     
     1930    @type key_tag: C{int} 
     1931    @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS record. 
     1932     
     1933    @type algo: C{int} 
     1934    @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this DS record.     
     1935 
     1936    @type digest_type: C{int} 
     1937    @ivar digest_type: Identifies the algorithm used to construct the digest field. 
     1938     
     1939    @type digest: L{Sigstr} 
     1940    @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by the 
     1941        algorithm identified by the digest_type field. 
     1942 
     1943    @type ttl: C{int} 
     1944    @ivar ttl: The maximum number of seconds which this record should be 
     1945        cached.     
     1946    """ 
     1947    implements(IEncodable, IRecord) 
     1948    TYPE = DS 
     1949    fmt = '!HBB' 
     1950     
     1951    fancybasename = 'DS' 
     1952    showAttributes = ('key_tag', 'algo', 'digest_type', ('_digest', 'digest', '%s'), 'ttl') 
     1953    compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 
     1954     
     1955    _digest = property(lambda self: self.digest.string) 
     1956 
     1957    def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 
     1958        self.key_tag = key_tag 
     1959        self.algo = algo 
     1960        self.digest_type = digest_type 
     1961        self.digest = Sigstr(digest) 
     1962        self.ttl = str2time(ttl) 
     1963         
     1964    def encode(self, strio, compDict = None): 
     1965        strio.write(struct.pack(self.fmt,  
     1966                                self.key_tag, 
     1967                                self.algo,  
     1968                                self.digest_type)) 
     1969        self.digest.encode(strio, None) 
     1970         
     1971    def decode(self, strio, length=None): 
     1972        start = strio.tell() 
     1973        l = struct.calcsize(self.fmt) 
     1974        buff = readPrecisely(strio, l) 
     1975        r = struct.unpack(self.fmt, buff)         
     1976        self.key_tag, self.algo, self.digest_type = r         
     1977        here = strio.tell() 
     1978        self.digest.decode(strio, length + start - here if length else None) 
     1979                 
     1980    def __hash__(self): 
     1981        return hash((self.key_tag, self.algo, self.digest_type, self.digest))     
     1982 
     1983class Record_DNSKEY(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1984    """ 
     1985    A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 
     1986     
     1987    @type flags: C{int} 
     1988    @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 
     1989        DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 
     1990        the name of a zone.  If bit 7 has value 0, then the DNSKEY record 
     1991        holds some other type of DNS public key and MUST NOT be used to  
     1992        verify RRSIGs that cover RRsets.   
     1993        Bit 15 is the Secure Entry Point flag. See RFC 3757.)  
     1994        All other bits are reserved and must be zero. 
     1995         
     1996    @type protocol: C{int} 
     1997    @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 
     1998        if this field does not contain 3. 
     1999     
     2000    @type algo: C{int} 
     2001    @ivar algo: Identifies the public key's cryptographic algorithm and determines 
     2002        the format of the pub_key field.  See RFC 4034 App A. 
     2003     
     2004    @type pub_key: L{Sigstr} 
     2005    @ivar pub_key: Holds the public key material. 
     2006 
     2007    @type ttl: C{int} 
     2008    @ivar ttl: The maximum number of seconds which this record should be 
     2009        cached.     
     2010    """ 
     2011    implements(IEncodable, IRecord) 
     2012    TYPE = DNSKEY 
     2013    fmt = '!HBB' 
     2014     
     2015    fancybasename = 'DNSKEY' 
     2016    showAttributes = ('flags', 'protocol', 'algo', ('_pub_key', 'pub_key', '%s'), 'ttl') 
     2017    compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 
     2018     
     2019    _pub_key = property(lambda self: self.pub_key.string) 
     2020     
     2021    def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 
     2022        self.flags = flags 
     2023        self.protocol = protocol 
     2024        self.algo = algo 
     2025        self.pub_key = Sigstr(pub_key) 
     2026        self.ttl = str2time(ttl) 
     2027         
     2028    def encode(self, strio, compDict = None): 
     2029        strio.write(struct.pack(self.fmt,  
     2030                                self.flags, 
     2031                                self.protocol,  
     2032                                self.algo)) 
     2033        self.pub_key.encode(strio, None) 
     2034         
     2035    def decode(self, strio, length=None): 
     2036        start = strio.tell() 
     2037        l = struct.calcsize(self.fmt) 
     2038        buff = readPrecisely(strio, l) 
     2039        r = struct.unpack(self.fmt, buff)         
     2040        self.flags, self.protocol, self.algo = r         
     2041        here = strio.tell() 
     2042        self.pub_key.decode(strio, length + start - here if length else None) 
     2043                 
     2044    def __hash__(self): 
     2045        return hash((self.flags, self.protocol, self.algo, self.pub_key)) 
     2046 
     2047class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2048    """ 
     2049    A DNSSEC NSEC record provides authenticated denial of existance for DNS data.  
     2050 
     2051    A DNSSEC NSEC record lists: 
     2052     
     2053        1) the next owner name in canonical ordering of the zone that contains authoritataive 
     2054           data or a delegation point NS RRset. 
     2055         
     2056        2) the set of RR types present at the NSEC RR's owner name. 
     2057 
     2058    @type nxt_name: L{Name} 
     2059    @ivar nxt_name: The next owner name that has authoritative data or contains a 
     2060        delegation point NS RRset. 
     2061     
     2062    @type type_bitmaps: L{TypeBitmaps} 
     2063    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's owner name. 
     2064     
     2065    @type ttl: C{int} 
     2066    @ivar ttl: The maximum number of seconds which this record should be 
     2067        cached. 
     2068    """ 
     2069    implements(IEncodable, IRecord) 
     2070    TYPE = NSEC 
     2071     
     2072    fancybasename = 'NSEC' 
     2073    showAttributes = (('nxt_name', 'nxt_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2074    compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 
     2075     
     2076    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2077     
     2078    def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 
     2079        self.nxt_name = Name(nxt_name) 
     2080        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2081        self.ttl = str2time(ttl) 
     2082         
     2083    def encode(self, strio, compDict = None): 
     2084        self.nxt_name.encode(strio, None) 
     2085        self.type_bitmaps.encode(strio, None) 
     2086         
     2087    def decode(self, strio, length=None): 
     2088        start = strio.tell() 
     2089        self.nxt_name.decode(strio, None) 
     2090        here = strio.tell() 
     2091        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2092                 
     2093    def __hash__(self): 
     2094        return hash((self.nxt_name, self.type_bitmaps)) 
     2095 
     2096class Record_NSEC3PARAM(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2097    """ 
     2098    A DNSSEC NSEC3PARAM record contains the NSEC3 parameters (hash algorithm, 
     2099    flags, iterations and salt) needed by authoritative servers to calculate 
     2100    hashed owner names.  The presence of an NSEC3PARAM RR at a zone apex 
     2101    indicates that the specified parameters may be used by authoritative  
     2102    servers to choose an appropriate set of NSEC3 RRs for negative responses.  
     2103 
     2104    @type hash_algo: C{int} 
     2105    @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 
     2106     
     2107    @type flags: C{int} 
     2108    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the  
     2109        opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 
     2110        delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 
     2111     
     2112    @type iterations: C{int} 
     2113    @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 
     2114     
     2115    @type salt: L{Charset} 
     2116    @ivar salt: Identifies the salt value provided to the hash. 
     2117 
     2118    @type ttl: C{int} 
     2119    @ivar ttl: The maximum number of seconds which this record should be 
     2120        cached. 
     2121    """ 
     2122    implements(IEncodable, IRecord) 
     2123    TYPE = NSEC3 
     2124    fmt = '!BBH' 
     2125     
     2126    fancybasename = 'NSEC3' 
     2127    showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), 'ttl') 
     2128    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'ttl') 
     2129     
     2130    _salt = property(lambda self: self.salt.string) 
     2131     
     2132    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', ttl=None): 
     2133        self.hash_algo = hash_algo 
     2134        self.flags = flags 
     2135        self.iterations = iterations 
     2136        self.salt = Charstr(salt) 
     2137        self.ttl = str2time(ttl) 
     2138         
     2139    def encode(self, strio, compDict = None): 
     2140        strio.write(struct.pack(self.fmt, 
     2141                                self.hash_algo, 
     2142                                self.flags, 
     2143                                self.iterations)) 
     2144        self.salt.encode(strio, None) 
     2145         
     2146    def decode(self, strio, length=None): 
     2147        start = strio.tell() 
     2148        l = struct.calcsize(self.fmt) 
     2149        buff = readPrecisely(strio, l) 
     2150        r = struct.unpack(self.fmt, buff)         
     2151        self.hash_algo, self.flags, self.iterations = r    
     2152        self.salt.decode(strio) 
     2153        here = strio.tell() 
     2154                 
     2155    def __hash__(self): 
     2156        return hash((self.hash_algo, self.flags, self.iterations, self.salt)) 
     2157     
     2158class Record_NSEC3(Record_NSEC3PARAM): 
     2159    """ 
     2160    A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of existance  
     2161    for DNS data and permits a gradual expansion of delegation-centric zones.  
     2162 
     2163    A DNSSEC NSEC3 record lists: 
     2164     
     2165        1) the set of RR types present at the original owner name of the NSEC RR. 
     2166 
     2167        2) the next hashed owner name in the hash order of the zone. 
     2168 
     2169    @type hash_algo: C{int} 
     2170    @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 
     2171     
     2172    @type flags: C{int} 
     2173    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the  
     2174        opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 
     2175        delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 
     2176     
     2177    @type iterations: C{int} 
     2178    @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 
     2179     
     2180    @type salt: L{Charset} 
     2181    @ivar salt: Identifies the salt value provided to the hash. 
     2182     
     2183    @type nxt_hash_owner_name: L{Charset} 
     2184    @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone in hash order. 
     2185     
     2186    @type type_bitmaps: L{TypeBitmaps} 
     2187    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's original owner name. 
     2188     
     2189    @type ttl: C{int} 
     2190    @ivar ttl: The maximum number of seconds which this record should be 
     2191        cached. 
     2192    """ 
     2193    implements(IEncodable, IRecord) 
     2194    TYPE = NSEC3 
     2195    fmt = '!BBH' 
     2196     
     2197    fancybasename = 'NSEC3' 
     2198    showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2199    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 
     2200     
     2201    _salt = property(lambda self: self.salt.string) 
     2202    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2203     
     2204    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', nxt_hash_owner='', type_bitmaps=None, ttl=None): 
     2205        Record_NSEC3PARAM.__init__( self, hash_algo, flags, iterations, salt, ttl) 
     2206        self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 
     2207        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2208         
     2209    def encode(self, strio, compDict = None): 
     2210        Record_NSEC3PARAM.encode(self, strio, compDict) 
     2211        self.nxt_hash_owner_name.encode(strio, None) 
     2212        self.type_bitmaps.encode(strio, None) 
     2213         
     2214    def decode(self, strio, length=None): 
     2215        start = strio.tell() 
     2216        Record_NSEC3PARAM.decode(self, strio, compDict) 
     2217        self.nxt_hash_owner_name.decode(strio) 
     2218        here = strio.tell() 
     2219        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2220                 
     2221    def __hash__(self): 
     2222        return hash((self.hash_algo, self.flags, self.iterations, self.salt, 
     2223                     self.nxt_hash_owner_name, self.type_bitmaps)) 
     2224 
    14732225# This is a fallback record 
    14742226class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 
    14752227    """ 
     
    15462298    queries = answers = add = ns = None 
    15472299 
    15482300    def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 
    1549                        auth=0, rCode=OK, trunc=0, maxSize=512): 
     2301                 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 
    15502302        self.maxSize = maxSize 
    15512303        self.id = id 
    15522304        self.answer = answer 
    15532305        self.opCode = opCode 
    1554         self.auth = auth 
    1555         self.trunc = trunc 
    1556         self.recDes = recDes 
    1557         self.recAv = recAv 
     2306        self.auth = auth            #AA - Authoritative Answer 
     2307        self.trunc = trunc          #TC - TrunCated 
     2308        self.recDes = recDes        #RD - Recursion Desired 
     2309        self.recAv = recAv          #RA - Recursion Available 
     2310        self.authData = authData    #AD - Authentic Data 
     2311        self.chkDis = chkDis        #CD - Checking Disabled 
    15582312        self.rCode = rCode 
    15592313        self.queries = [] 
    15602314        self.answers = [] 
     
    15992353                 | ((self.auth & 1 ) << 2 ) 
    16002354                 | ((self.trunc & 1 ) << 1 ) 
    16012355                 | ( self.recDes & 1 ) ) 
    1602         byte4 = ( ( (self.recAv & 1 ) << 7 ) 
     2356        byte4 = (  ((self.recAv & 1 ) << 7 ) 
     2357                  |((self.authData & 1 ) << 5 ) 
     2358                  |((self.chkDis & 1 ) << 4 ) 
    16032359                  | (self.rCode & 0xf ) ) 
    16042360 
    16052361        strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, 
     
    16192375        self.trunc = ( byte3 >> 1 ) & 1 
    16202376        self.recDes = byte3 & 1 
    16212377        self.recAv = ( byte4 >> 7 ) & 1 
     2378        self.authData = ( byte4 >> 5 ) & 1 
     2379        self.chkDis = ( byte4 >> 4 ) & 1 
    16222380        self.rCode = byte4 & 0xf 
    16232381 
    16242382        self.queries = [] 
     
    16372395 
    16382396    def parseRecords(self, list, num, strio): 
    16392397        for i in range(num): 
    1640             header = RRHeader(auth=self.auth) 
    16412398            try: 
    1642                 header.decode(strio) 
     2399                header = OPTHeader.factory(strio, auth=self.auth) 
    16432400            except EOFError: 
    16442401                return 
    16452402            t = self.lookupRecordType(header.type) 
  • names/ser_num_arith.py

     
     1# -*- test-case-name: twisted.names.test.test_ser_num_arith -*- 
     2# Copyright (c) Twisted Matrix Laboratories. 
     3# See LICENSE for details. 
     4 
     5""" 
     6Serial Number Arithmetic 
     7 
     8This module implements RFC 1982 DNS Serial Number Arithmetic  
     9(see http://tools.ietf.org/pdf/rfc1982.pdf). 
     10SNA is used in DNS and specifically in DNSSEC as defined in  
     11RFC 4034 in the DNSSEC Signature Expiration and Inception Fields. 
     12 
     13bob.novas@shinkuro.com 
     14""" 
     15 
     16import calendar, time 
     17 
     18class SNA(object): 
     19    """ 
     20    implements RFC 1982 - DNS Serial Number Arithmetic 
     21    """ 
     22    SERIAL_BITS = 32 
     23    MODULOVAL = 2**SERIAL_BITS 
     24    HLFRNG = 2**(SERIAL_BITS-1) 
     25    MAXADD = (2**(SERIAL_BITS-1)-1) 
     26     
     27    def __init__(self, number): 
     28        self._number = int(number)%self.MODULOVAL 
     29         
     30    def __repr__(self): 
     31        return str(self._number) 
     32     
     33    def asInt(self): 
     34        return self._number 
     35         
     36    def eq(self, sna2): 
     37        assert isinstance(sna2, SNA) 
     38        return sna2._number == self._number 
     39     
     40    def lt(self, sna2): 
     41        assert isinstance(sna2, SNA) 
     42        return not self.eq(sna2) and \ 
     43               ((self._number < sna2._number) and ((sna2._number - self._number) < self.HLFRNG) or \ 
     44                (self._number > sna2._number) and ((self._number - sna2._number) > self.HLFRNG)) 
     45 
     46    def gt(self, sna2): 
     47        assert isinstance(sna2, SNA) 
     48        return not self.eq(sna2) and \ 
     49               ((self._number < sna2._number) and ((sna2._number - self._number) > self.HLFRNG) or \ 
     50                (self._number > sna2._number) and ((self._number - sna2._number) < self.HLFRNG)) 
     51     
     52    def le(self, sna2): 
     53        return self.eq(sna2) or self.lt(sna2) 
     54     
     55    def ge(self, sna2): 
     56        return self.eq(sna2) or self.gt(sna2) 
     57 
     58    def add(self, sna2): 
     59        assert isinstance(sna2, SNA) 
     60        if sna2.le(SNA(self.MAXADD)): 
     61            return SNA( (self._number + sna2._number)%self.MODULOVAL ) 
     62        else: 
     63            raise ArithmeticError 
     64         
     65    def __hash__(self): 
     66        return hash(self._number) 
     67     
     68    __eq__  = eq 
     69    __lt__  = lt 
     70    __gt__  = gt 
     71    __le__  = le 
     72    __ge__  = ge 
     73    __add__ = add 
     74         
     75    @staticmethod 
     76    def max(snaList): 
     77        """ 
     78        this takes a list of sna's from which it will pick the sn with the highest value 
     79        """ 
     80        if len(snaList) == 0: 
     81            return None 
     82        trialMax = snaList[0] 
     83        for s in snaList[1:]: 
     84            if not trialMax: 
     85                trialMax = s 
     86            elif s and s > trialMax: 
     87                trialMax = s 
     88        return trialMax 
     89 
     90class DateSNA(SNA): 
     91    """ 
     92    implements DNS Serial Number Arithmetic 
     93    for dates 'YYYYMMDDHHMMSS' per RFC 4034 P3.1.5 
     94    """ 
     95    fmt = '%Y%m%d%H%M%S' 
     96 
     97    def __init__(self, utcDateTime=''): 
     98        ''' 
     99        accept a UTC date/time string as YYMMDDHHMMSS 
     100        and convert it to seconds since the epoch 
     101        ''' 
     102        if not utcDateTime: 
     103            utcDateTime = '19700101000000' 
     104        dtstruct = time.strptime(utcDateTime, DateSNA.fmt) 
     105        assert dtstruct.tm_year < 1970+136 
     106        secondsSinceE = calendar.timegm(dtstruct) 
     107        super(DateSNA, self).__init__(secondsSinceE) 
     108     
     109    def add(self, sna2): 
     110        if not isinstance(sna2, SNA): 
     111            return NotImplemented 
     112         
     113        if sna2.le(SNA(self.MAXADD)) and (self._number + sna2._number < self.MODULOVAL): 
     114            sna = SNA((self._number + sna2._number)%self.MODULOVAL) 
     115            return DateSNA.fromSNA(sna) 
     116        else: 
     117            raise ArithmeticError 
     118     
     119    def asDate(self): 
     120        dtstruct = time.gmtime(self._number) 
     121        return time.strftime(DateSNA.fmt, dtstruct) 
     122     
     123    @staticmethod 
     124    def fromSNA(sna): 
     125        assert isinstance(sna, SNA) 
     126        d = DateSNA() 
     127        d._number = sna._number 
     128        return d 
     129     
     130    @staticmethod 
     131    def fromInt(i): 
     132        return DateSNA.fromSNA(SNA(i)) 
     133         
     134    def __str__(self): 
     135        return self.asDate() 
     136 
  • names/test/test_dns.py

     
    88 
    99from cStringIO import StringIO 
    1010 
     11import re 
    1112import struct 
    1213 
    1314from twisted.python.failure import Failure 
    1415from twisted.internet import address, task 
    1516from twisted.internet.error import CannotListenError, ConnectionDone 
    1617from twisted.trial import unittest 
    17 from twisted.names import dns 
     18from twisted.names import dns, common 
    1819 
    1920from twisted.test import proto_helpers 
    2021 
     
    2526    dns.Record_WKS, dns.Record_SRV, dns.Record_AFSDB, dns.Record_RP, 
    2627    dns.Record_HINFO, dns.Record_MINFO, dns.Record_MX, dns.Record_TXT, 
    2728    dns.Record_AAAA, dns.Record_A6, dns.Record_NAPTR, dns.UnknownRecord, 
     29    dns.Record_OPT, dns.Record_RRSIG, dns.Record_DS, dns.Record_DNSKEY, 
     30    dns.Record_NSEC, dns.Record_NSEC3PARAM, dns.Record_NSEC3, 
    2831    ] 
    2932 
    3033class NameTests(unittest.TestCase): 
     
    189192    """Encoding and then decoding various objects.""" 
    190193 
    191194    names = ["example.org", "go-away.fish.tv", "23strikesback.net"] 
    192  
     195    sigs = ["Qm12VZVaZgKS0/DZx35SGECDwPiTTf3ngChb7OkgSv5iupVmJGhPWudm /18qBSXKyv9hxMlEXFFgpBieNqLfSBkP1bwKnlqPfr1Hx7ctDwDUpkT3 cS8u/ms9yo3Fu1ybpO4Hfsb1HbA2N3zzQnjWKnyk26AAQSz8KgjNTFzD tJM=", 
     196            "ZH2kahMD1g2WOieIotAcBwB0e/o30Zq6YR//M/xwP1ktkYuclmcR56iv XiR3QFWqmN5Xz3YpgmM4tZkjIeSMp2doYa7XYORZ7OpzG7oyfo8IoXxc j1VGDeAn1CeNCpBtoSGapRABG1gjY7oeRj/smPQPp2Gkf79+WZfuzRom /t4=",  
     197            "AZpaboyNQAmbnBO1K66QmZ0c+VCdY/wu9QpEdRnMpnIOLPD28pNVu6hk GQMz6eg5WYkPYDdJK+1D/oyAQkDmRgn10+O9EdeFDyLqYqq/htEAvDm4 CziMSOpD/mkg1bSWCZ2mdln/GBk8WooCeeM7LEHmRjmHMMj0xb6N4SKa MEc=",  
     198            "AwEAAbi5VQa3x+R3WQouBDNts+ZX2zIKZNoj9pzl7ew446kI/2omv3j6 c/4RQ6VneYE3mK7r0fFIKhVagmiRroFO1rRUJ8sVidssZ35CldE0sju+ E7wymVg3tV+ZUUO/+5v6Sfj+tw3rlp6eKqm7EGKKM88t+KuXiGYMu0Vw Rm9OUO1n",     
     199            "AwEAAbmTL+kuV45kAxGN//iBKz93Y6lutgxoptp+I1+PZZMsBkhm/dZj q57040Pz/Hr3f2zQX7z6fFu7/Ml3MHPH1eQDiVXDvOkeNq2x4IbCO7x+ 0p6bGYj4fw/tEfh/8dUzyzvMwfuAMsOvXza8Kh+UP4jvFc95cUuGgYus uEjUOp40PsL7EtYvAks3UssA6/OZP4w/1Z5m/VFx4PzgY0dkEuc=",     
     200            "VGPxa8A81eV1dtUxVhz9b9Jsp6FF4M5H6J0QhzbNCUTHTHjLNR2VHYfE fM+Akwo3/qKq3D6vzTfzqtyPAXP8CmGfdD8hfv0s7Hae9c7Is8usdlrk ZpoXEFMW+YVG8G9OieYViq6tBIpUvKgMVZ+oXKo63KJ/tC/yBW0H0VQP YwdzZ3ZvYRDmZDvrXoX7T0YNU+0HYHnb7g7nUECIJ/4HHg==", 
     201            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFE h9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffp Z9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55 Y1k="] 
     202    type_bitmaps = ["A MX RRSIG NSEC TYPE1234", 
     203                    "AAAA NS CNAME MX TXT RRSIG NSEC3 DNAME", 
     204                    "NSEC3 A AAAA RRSIG DS NS TYPE5000 TYPE1000 TYPE2000 TYPE3000 TYPE4000", 
     205                    None] 
     206                     
    193207    def testName(self): 
    194208        for n in self.names: 
    195209            # encode the name 
     
    276290            self.assertEqual(result.string, n) 
    277291 
    278292 
     293    def test_Sigstr(self): 
     294        """ 
     295        Test L{dns.Sigstr} encode and decode. 
     296        """ 
     297        for s in self.sigs: 
     298            # encode the signature/key 
     299            f = StringIO() 
     300            dns.Sigstr(s).encode(f) 
     301            l = f.tell() 
     302 
     303            # decode the signature/key 
     304            f.seek(0, 0) 
     305            result = dns.Sigstr() 
     306            result.decode(f,l) 
     307            #spaces are free, and dig sticks them in 
     308            self.assertEqual(result.string, s.replace(' ', '')) 
     309 
     310 
     311    def test_TypeBitmaps(self): 
     312        """ 
     313        Test L{dns.TypeBitmaps} encode and decode. 
     314        """ 
     315        typeRegex = re.compile('TYPE(\d+)') 
     316         
     317        for b in self.type_bitmaps: 
     318            # encode the type_bitmaps 
     319            f = StringIO() 
     320            dns.TypeBitmaps(b).encode(f) 
     321            l = f.tell() 
     322 
     323            # decode the type_bitmaps 
     324            f.seek(0, 0) 
     325            result = dns.TypeBitmaps() 
     326            result.decode(f,l) 
     327             
     328            def mnuVal(mnu): 
     329                mnuVal = dns.REV_TYPES.get(mnu, None) 
     330                if not mnuVal: 
     331                    m = typeRegex.match(mnu) 
     332                    if m.groups(): 
     333                        mnuVal = int(m.group(1)) 
     334                        assert mnuVal < 65536 
     335                    else: 
     336                        log.err("can't parse %s in %s" % (mnu, self.string, )) 
     337                        mnuVal = 0 
     338                return mnuVal 
     339             
     340            def sorttok(string): 
     341                if not string: 
     342                    return '' 
     343                 
     344                toks = string.split(' ') 
     345                toks.sort(key = mnuVal) 
     346                return ' '.join(toks) 
     347             
     348            self.assertEqual(result.type_bitmaps, sorttok(b)) 
     349 
     350 
    279351    def test_NAPTR(self): 
    280352        """ 
    281353        Test L{dns.Record_NAPTR} encode and decode. 
     
    439511        Initialize the controller: create a list of messages. 
    440512        """ 
    441513        self.messages = [] 
     514        self.dnssecConfig = common.DnssecConfig() 
    442515 
    443516 
    444517    def messageReceived(self, msg, proto, addr): 
     
    893966            repr(dns.UnknownRecord("foo\x1fbar", 12)), 
    894967            "<UNKNOWN data='foo\\x1fbar' ttl=12>") 
    895968 
     969    def test_dnskey(self): 
     970        """ 
     971        The repr of a L{dns.DNSKEY} instance includes the flags, protocol, 
     972        algo, pub_key and ttl fields of the record. 
     973        """ 
     974        self.assertEqual( 
     975            repr(dns.Record_DNSKEY(10, 20, 30, "foo\x1fbar", ttl=20)), 
     976            "<DNSKEY flags=10 protocol=20 algo=30 pub_key=foo\x1fbar ttl=20>") 
     977     
     978    def test_ds(self): 
     979        """ 
     980        The repr of a L{dns.DS} instance includes the key_tag, algo, digest_type, 
     981        digest and ttl fields of the record. 
     982        """ 
     983        self.assertEqual( 
     984            repr(dns.Record_DS(11, 22, 33, "foo\x1fbar1", ttl=21)), 
     985            "<DS key_tag=11 algo=22 digest_type=33 digest=foo\x1fbar1 ttl=21>") 
     986     
     987    def test_nsec(self): 
     988        """ 
     989        The repr of a L{dns.NSEC} instance includes the nxt_name, type_bitmaps and 
     990        ttl fields of the record. 
     991        """ 
     992        self.assertEqual( 
     993            repr(dns.Record_NSEC('bob', "\x1fabcd", ttl=31)), 
     994            "<NSEC nxt_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     995     
     996    def test_nsec3param(self): 
     997        """ 
     998        The repr of a L{dns.NSEC3PARAM} instance includes the hash_algo, flags,  
     999        iterations, salt and ttl fields of the record. 
     1000        """ 
     1001        self.assertEqual( 
     1002            repr(dns.Record_NSEC3PARAM(1, 2, 3, '\x12\x34', ttl=31)), 
     1003            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 ttl=31>") 
     1004     
     1005    def test_nsec3(self): 
     1006        """ 
     1007        The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, iterations, 
     1008        salt, nxt_hash_owner_name, type_bitmaps and ttl fields of the record. 
     1009        """ 
     1010        self.assertEqual( 
     1011            repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', "\x1fabcd", ttl=31)), 
     1012            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 nxt_hash_owner_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     1013     
     1014    def test_opt(self): 
     1015        """ 
     1016        The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk flag,  
     1017        and version fields of the record. (The OPT record has no ttl field.) 
     1018        """ 
     1019        self.assertEqual( 
     1020            repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 
     1021                 "<OPT payload_size=1492 flags=0x8000 version=0>") 
    8961022 
     1023    def test_rrsig(self): 
     1024        """ 
     1025        The repr of a L{dns.RRSIG} instance includes the algo, labels, original_ttl 
     1026        sig_expiration, sig_inception, key_tag, signers_name, signature and ttl  
     1027        fields of the record. 
     1028        """ 
     1029        self.assertEqual( 
     1030            repr(dns.Record_RRSIG(type_covered=dns.A, 
     1031                                  algo=2, 
     1032                                  labels=3, 
     1033                                  original_ttl=30, 
     1034                                  sig_expiration='20110101123456', 
     1035                                  sig_inception= '20110202112233', 
     1036                                  key_tag=60, 
     1037                                  signers_name='bob', 
     1038                                  signature='\x12\x34sig', 
     1039                                  ttl=70)), 
     1040                 "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 
     1041                + " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 
     1042                + " signers_name=bob signature=\x12\x34sig ttl=70>") 
    8971043 
    8981044class _Equal(object): 
    8991045    """ 
     
    9611107            cls('example.com', 123), 
    9621108            cls('example.org', 123)) 
    9631109 
     1110    def test_optheader(self): 
     1111        """ 
     1112        Two OptHeader instances comapare equal iff the have the same 
     1113        (Record_OPT) payload and auth bit. 
     1114        """ 
     1115        self._equalityTest( 
     1116            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 
     1117            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, dnssecOk=True, version=0, ttl=30)), 
     1118            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492, dnssecOk=False, version=0, ttl=40), auth=True)) 
    9641119 
    9651120    def test_rrheader(self): 
    9661121        """ 
     
    14831638            dns.UnknownRecord('foo', ttl=10), 
    14841639            dns.UnknownRecord('foo', ttl=10), 
    14851640            dns.UnknownRecord('foo', ttl=100)) 
     1641 
     1642    def test_rrsig(self): 
     1643        """ 
     1644        L(dns.RRSIG) instances compare equal iff they have the same 
     1645        type_covered, algo, labels, original_ttl, sig_expiration, sig_inception,  
     1646        key_tag, signers_name, signature, and ttl 
     1647        """ 
     1648        self._equalityTest( 
     1649            dns.Record_RRSIG(type_covered=dns.A), 
     1650            dns.Record_RRSIG(type_covered=dns.A), 
     1651            dns.Record_RRSIG(type_covered=dns.AAAA)) 
     1652        self._equalityTest( 
     1653            dns.Record_RRSIG(algo=1), 
     1654            dns.Record_RRSIG(algo=1), 
     1655            dns.Record_RRSIG(algo=2)) 
     1656        self._equalityTest( 
     1657            dns.Record_RRSIG(labels=3), 
     1658            dns.Record_RRSIG(labels=3), 
     1659            dns.Record_RRSIG(labels=4)) 
     1660        self._equalityTest( 
     1661            dns.Record_RRSIG(original_ttl=5), 
     1662            dns.Record_RRSIG(original_ttl=5), 
     1663            dns.Record_RRSIG(original_ttl=6)) 
     1664        self._equalityTest( 
     1665            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1666            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1667            dns.Record_RRSIG(sig_expiration='20110101000001')) 
     1668        self._equalityTest( 
     1669            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1670            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1671            dns.Record_RRSIG(sig_inception='20120101000001')) 
     1672        self._equalityTest( 
     1673            dns.Record_RRSIG(key_tag=11), 
     1674            dns.Record_RRSIG(key_tag=11), 
     1675            dns.Record_RRSIG(key_tag=12)) 
     1676        self._equalityTest( 
     1677            dns.Record_RRSIG(signers_name='bob'), 
     1678            dns.Record_RRSIG(signers_name='bob'), 
     1679            dns.Record_RRSIG(signers_name='joe')) 
     1680        self._equalityTest( 
     1681            dns.Record_RRSIG(signature='abcdef'), 
     1682            dns.Record_RRSIG(signature='abcdef'), 
     1683            dns.Record_RRSIG(signature='abcdefg')) 
     1684        self._equalityTest( 
     1685            dns.Record_RRSIG(ttl=10), 
     1686            dns.Record_RRSIG(ttl=10), 
     1687            dns.Record_RRSIG(ttl=20)) 
     1688         
     1689    def test_ds(self): 
     1690        """ 
     1691        L(dns.DS) instances compare equal iff they have the same 
     1692        key_tag, algo, digest_type, digest and ttl 
     1693        """ 
     1694        self._equalityTest( 
     1695            dns.Record_DS(key_tag=1), 
     1696            dns.Record_DS(key_tag=1), 
     1697            dns.Record_DS(key_tag=2)) 
     1698        self._equalityTest( 
     1699            dns.Record_DS(algo=3), 
     1700            dns.Record_DS(algo=3), 
     1701            dns.Record_DS(algo=4)) 
     1702        self._equalityTest( 
     1703            dns.Record_DS(digest_type=5), 
     1704            dns.Record_DS(digest_type=5), 
     1705            dns.Record_DS(digest_type=6)) 
     1706        self._equalityTest( 
     1707            dns.Record_DS(digest='abcdef-digest'), 
     1708            dns.Record_DS(digest='abcdef-digest'), 
     1709            dns.Record_DS(digest='abcdef-digest-f')) 
     1710        self._equalityTest( 
     1711            dns.Record_DS(ttl=10), 
     1712            dns.Record_DS(ttl=10), 
     1713            dns.Record_DS(ttl=20)) 
     1714 
     1715    def test_dnskey(self): 
     1716        """ 
     1717        L(dns.DNSKEY) instances compare equal iff they have the same 
     1718        flags, protocol, algo, pub_key and ttl 
     1719        """ 
     1720        self._equalityTest( 
     1721            dns.Record_DNSKEY(flags=1), 
     1722            dns.Record_DNSKEY(flags=1), 
     1723            dns.Record_DNSKEY(flags=2)) 
     1724        self._equalityTest( 
     1725            dns.Record_DNSKEY(protocol=3), 
     1726            dns.Record_DNSKEY(protocol=3), 
     1727            dns.Record_DNSKEY(protocol=4)) 
     1728        self._equalityTest( 
     1729            dns.Record_DNSKEY(algo=5), 
     1730            dns.Record_DNSKEY(algo=5), 
     1731            dns.Record_DNSKEY(algo=6)) 
     1732        self._equalityTest( 
     1733            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1734            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1735            dns.Record_DNSKEY(pub_key='abcdef-digest-f')) 
     1736        self._equalityTest( 
     1737            dns.Record_DNSKEY(ttl=10), 
     1738            dns.Record_DNSKEY(ttl=10), 
     1739            dns.Record_DNSKEY(ttl=20)) 
     1740 
     1741    def test_nsec(self): 
     1742        """ 
     1743        L(dns.DNSKEY) instances compare equal iff they have the same 
     1744        nxt_name, type_bitmaps and ttl 
     1745        """ 
     1746        self._equalityTest( 
     1747            dns.Record_NSEC(nxt_name="example.com"), 
     1748            dns.Record_NSEC(nxt_name="example.com"), 
     1749            dns.Record_NSEC(nxt_name="a.example.com")) 
     1750        self._equalityTest( 
     1751            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1752            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1753            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1754        self._equalityTest( 
     1755            dns.Record_NSEC(ttl=5), 
     1756            dns.Record_NSEC(ttl=5), 
     1757            dns.Record_NSEC(ttl=6)) 
     1758 
     1759    def test_nsec3param(self): 
     1760        """ 
     1761        L(dns.DNSKEY) instances compare equal iff they have the same 
     1762        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1763        """ 
     1764        self._equalityTest( 
     1765            dns.Record_NSEC3PARAM(hash_algo=1), 
     1766            dns.Record_NSEC3PARAM(hash_algo=1), 
     1767            dns.Record_NSEC3PARAM(hash_algo=2)) 
     1768        self._equalityTest( 
     1769            dns.Record_NSEC3PARAM(flags=1), 
     1770            dns.Record_NSEC3PARAM(flags=1), 
     1771            dns.Record_NSEC3PARAM(flags=2)) 
     1772        self._equalityTest( 
     1773            dns.Record_NSEC3PARAM(iterations=5), 
     1774            dns.Record_NSEC3PARAM(iterations=5), 
     1775            dns.Record_NSEC3PARAM(iterations=6)) 
     1776        self._equalityTest( 
     1777            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1778            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1779            dns.Record_NSEC3PARAM(salt="abcdefg")) 
     1780        self._equalityTest( 
     1781            dns.Record_NSEC3PARAM(ttl=5), 
     1782            dns.Record_NSEC3PARAM(ttl=5), 
     1783            dns.Record_NSEC3PARAM(ttl=6)) 
     1784 
     1785    def test_nsec3(self): 
     1786        """ 
     1787        L(dns.DNSKEY) instances compare equal iff they have the same 
     1788        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1789        """ 
     1790        self._equalityTest( 
     1791            dns.Record_NSEC3(hash_algo=1), 
     1792            dns.Record_NSEC3(hash_algo=1), 
     1793            dns.Record_NSEC3(hash_algo=2)) 
     1794        self._equalityTest( 
     1795            dns.Record_NSEC3(flags=1), 
     1796            dns.Record_NSEC3(flags=1), 
     1797            dns.Record_NSEC3(flags=2)) 
     1798        self._equalityTest( 
     1799            dns.Record_NSEC3(iterations=5), 
     1800            dns.Record_NSEC3(iterations=5), 
     1801            dns.Record_NSEC3(iterations=6)) 
     1802        self._equalityTest( 
     1803            dns.Record_NSEC3(salt="abcdef"), 
     1804            dns.Record_NSEC3(salt="abcdef"), 
     1805            dns.Record_NSEC3(salt="abcdefg")) 
     1806        self._equalityTest( 
     1807            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1808            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1809            dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 
     1810        self._equalityTest( 
     1811            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1812            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1813            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1814        self._equalityTest( 
     1815            dns.Record_NSEC3(ttl=5), 
     1816            dns.Record_NSEC3(ttl=5), 
     1817            dns.Record_NSEC3(ttl=6)) 
     1818 
     1819 
     1820                 
     1821 No newline at end of file