Ticket #5454: AddEDNS0andDNSSEC5454.patch

File AddEDNS0andDNSSEC5454.patch, 79.3 KB (added by BobNovas, 2 years ago)

patch for ticket 5454

  • names/client.py

     
    7171    protocol = property(_getProtocol) 
    7272 
    7373 
    74     def __init__(self, resolv=None, servers=None, timeout=(1, 3, 11, 45), reactor=None): 
     74    def __init__(self,  
     75                 resolv=None,  
     76                 servers=None,  
     77                 timeout=(1, 3, 11, 45),  
     78                 reactor=None,  
     79                 dnssecConfig=None): 
    7580        """ 
    7681        Construct a resolver which will query domain name servers listed in 
    7782        the C{resolv.conf(5)}-format file given by C{resolv} as well as 
     
    98103            L{IReactorTCP} which will be used to establish connections, listen 
    99104            for DNS datagrams, and enforce timeouts.  If not provided, the 
    100105            global reactor will be used. 
     106             
     107        @param dnssecConfig: An L{DnssecConfig} - see common.DnssecConfig() 
    101108 
    102109        @raise ValueError: Raised if no nameserver addresses can be found. 
    103110        """ 
    104         common.ResolverBase.__init__(self) 
     111        common.ResolverBase.__init__(self, dnssecConfig) 
    105112 
    106113        if reactor is None: 
    107114            from twisted.internet import reactor 
     
    381388            return self.queryTCP(message.queries).addCallback(self.filterAnswers) 
    382389        if message.rCode != dns.OK: 
    383390            return failure.Failure(self.exceptionForCode(message.rCode)(message)) 
    384         return (message.answers, message.authority, message.additional) 
     391         
     392        #if dnssecOk is enabled, return a reference to the message as the 4th member of  
     393        #the tuple, so the caller can access the message header flags. There are more 
     394        #flags than just AD (authentic Data) that are set in a response. 
     395        if self.dnssecConfig.dnssecOk: 
     396            return (message.answers, message.authority, message.additional, message) 
     397        else: 
     398            #dnssecOk was not requested - return a legacy 3-tuple 
     399            return (message.answers, message.authority, message.additional) 
    385400 
    386401 
    387402    def _lookup(self, name, cls, type, timeout): 
     
    953968    @rtype: C{Deferred} 
    954969    """ 
    955970    return getResolver().lookupNamingAuthorityPointer(name, timeout) 
     971 
     972 
     973def lookupDNSKey(name, timeout=None): 
     974    """ 
     975    DNSKEY lookup.     
     976 
     977    @type name: C{str} 
     978    @param name: DNS name to resolve. 
     979 
     980    @type timeout: Sequence of C{int} 
     981    @param timeout: Number of seconds after which to reissue the query. 
     982        When the last timeout expires, the query is considered failed. 
     983 
     984    @rtype: C{Deferred} 
     985    """ 
     986    return getResolver().lookupDNSKey(name, timeout) 
     987 
     988 
     989def lookupDS(name, timeout=None): 
     990    """ 
     991    DS lookup.     
     992 
     993    @type name: C{str} 
     994    @param name: DNS name to resolve. 
     995 
     996    @type timeout: Sequence of C{int} 
     997    @param timeout: Number of seconds after which to reissue the query. 
     998        When the last timeout expires, the query is considered failed. 
     999 
     1000    @rtype: C{Deferred} 
     1001    """ 
     1002    return getResolver().lookupDS(name, timeout) 
     1003 
     1004 
     1005def lookupNSEC(name, timeout=None): 
     1006    """ 
     1007    NSEC lookup.     
     1008 
     1009    @type name: C{str} 
     1010    @param name: DNS name to resolve. 
     1011 
     1012    @type timeout: Sequence of C{int} 
     1013    @param timeout: Number of seconds after which to reissue the query. 
     1014        When the last timeout expires, the query is considered failed. 
     1015 
     1016    @rtype: C{Deferred} 
     1017    """ 
     1018    return getResolver().lookupNSEC(name, timeout) 
     1019 
     1020 
     1021def lookupNSEC3(name, timeout=None): 
     1022    """ 
     1023    NSEC3 lookup.     
     1024 
     1025    @type name: C{str} 
     1026    @param name: DNS name to resolve. 
     1027 
     1028    @type timeout: Sequence of C{int} 
     1029    @param timeout: Number of seconds after which to reissue the query. 
     1030        When the last timeout expires, the query is considered failed. 
     1031 
     1032    @rtype: C{Deferred} 
     1033    """ 
     1034    return getResolver().lookupNSEC3(name, timeout) 
     1035 
     1036 
     1037def lookupNSEC3Param(name, timeout=None): 
     1038    """ 
     1039    NSEC3 Param lookup.     
     1040 
     1041    @type name: C{str} 
     1042    @param name: DNS name to resolve. 
     1043 
     1044    @type timeout: Sequence of C{int} 
     1045    @param timeout: Number of seconds after which to reissue the query. 
     1046        When the last timeout expires, the query is considered failed. 
     1047 
     1048    @rtype: C{Deferred} 
     1049    """ 
     1050    return getResolver().lookupNSEC3Param(name, timeout) 
     1051 
     1052 
     1053def lookupRRSIG(name, timeout=None): 
     1054    """ 
     1055    RRSIG lookup.     
     1056 
     1057    @type name: C{str} 
     1058    @param name: DNS name to resolve. 
     1059 
     1060    @type timeout: Sequence of C{int} 
     1061    @param timeout: Number of seconds after which to reissue the query. 
     1062        When the last timeout expires, the query is considered failed. 
     1063 
     1064    @rtype: C{Deferred} 
     1065    """ 
     1066    return getResolver().lookupRRSIG(name, timeout) 
  • 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    """ 
     52    def __init__(self,  
     53                 recDes=True, 
     54                 ednsEnabled=False,  
     55                 maxUdpPktSz=512,  
     56                 dnssecOk=False, 
     57                 chkDis=False, 
     58                 version=0): 
     59 
     60        self.recDes = recDes 
     61        self.ednsEnabled = ednsEnabled 
     62        self.maxUdpPktSz = maxUdpPktSz 
     63        self.dnssecOk = dnssecOk 
     64        self.chkDis = chkDis 
     65        self.version = version 
     66 
     67        assert not self.ednsEnabled or 512 <= self.maxUdpPktSz <= 65535 
     68        assert version == 0 
     69 
    2170class ResolverBase: 
    2271    """ 
    2372    L{ResolverBase} is a base class for L{IResolver} implementations which 
     
    3685 
    3786    typeToMethod = None 
    3887 
    39     def __init__(self): 
     88    def __init__(self, dnssecConfig=None): 
    4089        self.typeToMethod = {} 
    4190        for (k, v) in typeToMethod.items(): 
    4291            self.typeToMethod[k] = getattr(self, v) 
     92        self.dnssecConfig = dnssecConfig 
     93        if self.dnssecConfig == None: 
     94            self.dnssecConfig = DnssecConfig() 
    4395 
    44  
    4596    def exceptionForCode(self, responseCode): 
    4697        """ 
    4798        Convert a response code (one of the possible values of 
     
    200251        @see: twisted.names.client.lookupAllRecords 
    201252        """ 
    202253        return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) 
     254     
    203255 
     256    def lookupDNSKey(self, name, timeout=None): 
     257        """ 
     258        @see: twisted.names.client.lookupDNSKey 
     259        """ 
     260        return self._lookup(name, dns.IN, dns.DNSKEY, timeout) 
     261     
     262 
     263    def lookupDS(self, name, timeout=None): 
     264        """ 
     265        @see: twisted.names.client.lookupDS 
     266        """ 
     267        return self._lookup(name, dns.IN, dns.DS, timeout) 
     268     
     269 
     270    def lookupNSEC(self, name, timeout=None): 
     271        """ 
     272        @see: twisted.names.client.lookupNSEC 
     273        """ 
     274        return self._lookup(name, dns.IN, dns.NSEC, timeout) 
     275     
     276 
     277    def lookupNSEC3(self, name, timeout=None): 
     278        """ 
     279        @see: twisted.names.client.lookupNSEC3 
     280        """ 
     281        return self._lookup(name, dns.IN, dns.NSEC3, timeout) 
     282     
     283 
     284    def lookupNSEC3Param(self, name, timeout=None): 
     285        """ 
     286        @see: twisted.names.client.lookupNSEC3Param 
     287        """ 
     288        return self._lookup(name, dns.IN, dns.NSEC3PARAM, timeout) 
     289     
     290 
     291    def lookupRRSIG(self, name, timeout=None): 
     292        """ 
     293        @see: twisted.names.client.lookupRRSIG 
     294        """ 
     295        return self._lookup(name, dns.IN, dns.RRSIG, timeout) 
     296 
     297 
    204298    def getHostByName(self, name, timeout = None, effort = 10): 
    205299        """ 
    206300        @see: twisted.names.client.getHostByName 
     
    268362    dns.MX:    'lookupMailExchange', 
    269363    dns.TXT:   'lookupText', 
    270364    dns.SPF:   'lookupSenderPolicy', 
     365    dns.DNSKEY:'lookupDNSKey', 
     366    dns.DS:    'lookupDS', 
     367    dns.NSEC:  'lookupNSEC', 
     368    dns.NSEC3: 'lookupNSEC3', 
     369    dns.NSEC3PARAM: 'lookupNSEC3Param', 
     370    dns.RRSIG: 'lookupRRSIG', 
    271371 
    272372    dns.RP:    'lookupResponsibility', 
    273373    dns.AFSDB: 'lookupAFSDatabase', 
  • names/dns.py

     
    1515__all__ = [ 
    1616    'IEncodable', 'IRecord', 
    1717 
    18     'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'HINFO', 
     18    'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'DNSKEY', 'DS', 'HINFO', 
    1919    'MAILA', 'MAILB', 'MB', 'MD', 'MF', 'MG', 'MINFO', 'MR', 'MX', 
    20     'NAPTR', 'NS', 'NULL', 'PTR', 'RP', 'SOA', 'SPF', 'SRV', 'TXT', 'WKS', 
     20    'NAPTR', 'NS', 'NSEC', 'NSEC3', 'NSEC3PARAM', 'NULL', 'OPT', 'PTR',  
     21    'RP', 'RRSIG', 'SOA', 'SPF', 'SRV', 'TXT', 'WKS', 
    2122 
    2223    'ANY', 'CH', 'CS', 'HS', 'IN', 
    2324 
     
    2627    'EFORMAT', 'ENAME', 'ENOTIMP', 'EREFUSED', 'ESERVER', 
    2728 
    2829    'Record_A', 'Record_A6', 'Record_AAAA', 'Record_AFSDB', 'Record_CNAME', 
    29     'Record_DNAME', 'Record_HINFO', 'Record_MB', 'Record_MD', 'Record_MF', 
     30    'Record_DNAME', 'Record_DNSKEY', 'Record_DS', 'Record_HINFO', 'Record_MB',  
     31    'Record_MD', 'Record_MF', 
    3032    'Record_MG', 'Record_MINFO', 'Record_MR', 'Record_MX', 'Record_NAPTR', 
    31     'Record_NS', 'Record_NULL', 'Record_PTR', 'Record_RP', 'Record_SOA', 
    32     'Record_SPF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 
     33    'Record_NS', 'Record_NSEC', 'Record_NSEC3', 'Record_NULL', 'Record_OPT', 'Record_PTR', 'Record_RP', 'Record_RRSIG',  
     34    'Record_SOA', 'Record_SPF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 
    3335 
    3436    'QUERY_CLASSES', 'QUERY_TYPES', 'REV_CLASSES', 'REV_TYPES', 'EXT_QUERIES', 
    3537 
    36     'Charstr', 'Message', 'Name', 'Query', 'RRHeader', 'SimpleRecord', 
     38    'Charstr', 'Message', 'Name', 'OPTHeader', 'Query', 'RRHeader', 'SimpleRecord', 
    3739    'DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', 
    3840 
    3941    'OK', 'OP_INVERSE', 'OP_NOTIFY', 'OP_QUERY', 'OP_STATUS', 'OP_UPDATE', 
     
    4648# System imports 
    4749import warnings 
    4850 
     51import re 
    4952import struct, random, types, socket 
    5053 
    5154import cStringIO as StringIO 
     
    5457 
    5558from zope.interface import implements, Interface, Attribute 
    5659 
     60from base64 import b64decode, b64encode 
    5761 
    5862# Twisted imports 
    5963from twisted.internet import protocol, defer 
     
    6165from twisted.python import log, failure 
    6266from twisted.python import util as tputil 
    6367from twisted.python import randbytes 
     68from twisted.names.ser_num_arith import SNA, DateSNA 
    6469 
    6570 
    6671def randomSource(): 
     
    7984NAPTR = 35 
    8085A6 = 38 
    8186DNAME = 39 
     87OPT = 41 
     88DS = 43 
     89RRSIG = 46 
     90NSEC = 47 
     91DNSKEY = 48 
     92NSEC3 = 50 
     93NSEC3PARAM = 51 
    8294SPF = 99 
    8395 
    8496QUERY_TYPES = { 
     
    108120    NAPTR: 'NAPTR', 
    109121    A6: 'A6', 
    110122    DNAME: 'DNAME', 
    111     SPF: 'SPF' 
     123    OPT: 'OPT', 
     124    DS: 'DS', 
     125    RRSIG: 'RRSIG', 
     126    NSEC: 'NSEC', 
     127    DNSKEY: 'DNSKEY', 
     128    NSEC3: 'NSEC3',  
     129    NSEC3PARAM: 'NSEC3PARAM', 
     130    SPF: 'SPF', 
    112131} 
    113132 
    114133IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) 
     
    370389 
    371390    def __str__(self): 
    372391        return self.name 
     392     
     393class Sigstr(object): 
     394    ''' 
     395    for signatures and keys. display as b64 encoded 
     396    ''' 
     397    implements(IEncodable) 
     398     
     399    def __init__(self, string=''): 
     400        if not isinstance(string, str): 
     401            raise ValueError("%r is not a string" % (string, )) 
     402        self.string = string #b64encoded string 
     403         
     404    def encode(self, strio, compDict=None): 
     405        ''' 
     406        Write the byte representation (the un-b64-encoded string) 
     407        to the file. 
     408         
     409        @type strio: file 
     410        @param srio: The byte representation of this signature or key 
     411        will be written to this file 
     412         
     413        @type compDict: dict 
     414        @param compDict: not used. 
     415        ''' 
     416        strio.write(b64decode(self.string)) 
     417         
     418    def decode(self, strio, length=None): 
     419        ''' 
     420        Decode a signature or a key. 
    373421 
     422        @type strio: file 
     423        @param strio: Exactly length bytes will be read from this file  
     424        to decode the full signature or key 
     425         
     426        @type length: int 
     427        @param lenth: length must always be given. A signature or key 
     428        is always the last thing in an RR and so you can always determine 
     429        its length.  
     430        ''' 
     431        self.string = '' 
     432        if length == None: 
     433            return 
     434         
     435        assert isinstance(length, int) 
     436        buff = readPrecisely(strio, length) 
     437        self.string = b64encode(buff) 
     438 
     439    def __eq__(self, other): 
     440        if isinstance(other, Sigstr): 
     441            return self.string == other.string 
     442        return False 
     443 
     444    def __hash__(self): 
     445        return hash(self.string) 
     446 
     447    def __str__(self): 
     448        return self.string 
     449     
     450 
     451class TypeBitmaps(object): 
     452    ''' 
     453    bitmap encoding scheme used by NSEC and NSEC3 RR's 
     454    to indicate the RRset types that exist at the  
     455    NSEC/NSEC3 RR's original owner name or hashed name.   
     456    See RFC 4034 and RFC 5155. 
     457    ''' 
     458    fmt = 'BB' 
     459    typeRegex = re.compile('TYPE(\d+)') 
     460     
     461    def __init__(self, string=''): 
     462        self.string = string 
     463         
     464    def encode(self, strio, compDict=None): 
     465        """ 
     466        Encode the string field, which consists of a set  
     467        of type names, into an NSEC/NSEC3 type bitmap. 
     468         
     469        @type strio: file 
     470        @param strio: the byte representation of the type bitmap 
     471        will be written to this file. 
     472         
     473        @type compDict: dict 
     474        @param compDict: not used. 
     475        """ 
     476        if not self.string: 
     477            return; 
     478         
     479        #get a sorted list of RR Type Values 
     480        mnus = self.string.split(' ') 
     481        mnuVals = [] 
     482        for mnu in mnus: 
     483            mnuVal = REV_TYPES.get(mnu, None) 
     484            if not mnuVal: 
     485                m = self.typeRegex.match(mnu) 
     486                if m.groups(): 
     487                    mnuVal = int(m.group(1)) 
     488                    assert mnuVal < 65536 
     489                else: 
     490                    log.err("can't parse %s in %s" % (mnu, self.string, )) 
     491                    continue; 
     492            mnuVals.append(mnuVal) 
     493        mnuVals.sort() 
     494         
     495        #convert that to a dict of windows and lists 
     496        windDict = {} 
     497        for v in mnuVals: 
     498            window = (v >> 8) & 0xFF 
     499            if window not in windDict: 
     500                windDict[window] = [] 
     501            windDict[window].append(v & 0xFF) 
     502         
     503        #have to sort the keys - they're not in order! 
     504        windows = windDict.keys() 
     505        windows.sort() 
     506 
     507        #create the bitmaps 
     508        bmap = bytearray() 
     509        for w in windows: 
     510            bmapseg = bytearray(32) 
     511            maxoff = 0 
     512            for v in windDict[w]: 
     513                vm1 = v - 1 
     514                off = vm1 >> 3 
     515                bit = vm1 & 0x7 
     516                msk = 1 << bit 
     517                bmapseg[off] |= msk 
     518                maxoff = max(off, maxoff) 
     519            bmapseg = bmapseg[0:maxoff+1] 
     520            bmap += chr(w) + chr(maxoff+1) + bmapseg 
     521         
     522        strio.write(str(bmap)) 
     523     
     524    def decode(self, strio, length=None): 
     525        """ 
     526        Decode an NSEC/NSEC3 type bitmap into a string 
     527        representation of type names. 
     528        """ 
     529        self.type_bitmaps = "" 
     530        if length == None: 
     531            return 
     532 
     533        type_bitmaps = bytearray() 
     534        l = struct.calcsize(self.fmt) 
     535        parsed_length = 0 
     536        while parsed_length < length: 
     537            buff = readPrecisely(strio, l) 
     538            wb_num, bm_len = struct.unpack(self.fmt, buff) 
     539            assert parsed_length + 2 + bm_len <= length 
     540            bm = readPrecisely(strio, bm_len) 
     541            byteNum = -1 
     542            for b in bm: 
     543                byteNum += 1 
     544                ob = ord(b) 
     545                if ob == 0: 
     546                    continue 
     547                 
     548                for v in range(8): 
     549                    msk = 1<<v 
     550                    if ob & msk: 
     551                        val = wb_num*256 + byteNum*8 + v + 1 
     552                        mnu = QUERY_TYPES.get(val, None) 
     553                        if not mnu: 
     554                            mnu = 'TYPE' + str(val) 
     555                        type_bitmaps += (mnu + ' ')                         
     556             
     557            parsed_length += 2 + bm_len 
     558             
     559        self.type_bitmaps = str(type_bitmaps[0:-1]) 
     560 
     561    def __eq__(self, other): 
     562        if isinstance(other, TypeBitmaps): 
     563            return self.string == other.string 
     564        return False 
     565 
     566    def __hash__(self): 
     567        return hash(self.string) 
     568 
     569    def __str__(self): 
     570        return self.string 
     571 
    374572class Query: 
    375573    """ 
    376574    Represent a single DNS query. 
     
    434632        return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 
    435633 
    436634 
    437 class RRHeader(tputil.FancyEqMixin): 
     635     
     636class OPTHeader(tputil.FancyEqMixin): 
    438637    """ 
     638    A OPT record header. 
     639 
     640    @cvar fmt: C{str} specifying the byte format of an OPT Header. 
     641 
     642    @ivar name: Root (0, 8-bits) 
     643    @ivar type: 41 (OPT Record) 
     644    @ivar payload: An object that implements the IEncodable interface 
     645    @ivar auth: Whether this header is authoritative or not. 
     646    """ 
     647 
     648    implements(IEncodable) 
     649 
     650    compareAttributes = ('name', 'type', 'payload', 'auth') 
     651 
     652    fmt = "!H" 
     653 
     654    name = None 
     655    type = None 
     656    payload = None 
     657 
     658    #OPTHeader _really_ has no ttl or rdlength, but the 
     659    #existence of the attributes is required. 
     660    ttl = None 
     661    rdlength = None 
     662 
     663    cachedResponse = None 
     664 
     665    def __init__(self, payload=None, auth=False): 
     666        """ 
     667        @type name: C{str} 
     668        @param name: Root (0) 
     669 
     670        @type type: C{int} 
     671        @param type: Query type 41. 
     672 
     673        @type payload: An object implementing C{IEncodable} 
     674        @param payload: The OPT payload 
     675        """ 
     676        assert (payload is None) or (payload.TYPE == OPT) 
     677 
     678        self.name = 0 
     679        self.type = OPT 
     680        self.payload = payload 
     681        self.auth = auth 
     682 
     683    def encode(self, strio, compDict=None): 
     684        strio.write(struct.pack('!B', 0)) 
     685        strio.write(struct.pack(self.fmt, self.type)) 
     686        if self.payload: 
     687            prefix = strio.tell() 
     688            self.payload.encode(strio, compDict) 
     689            aft = strio.tell() 
     690            strio.seek(prefix - 2, 0) 
     691            strio.write(struct.pack('!H', aft - prefix)) 
     692            strio.seek(aft, 0) 
     693 
     694    def decode(self, strio, length = None): 
     695        self.name.decode(strio) 
     696        l = struct.calcsize(self.fmt) 
     697        buff = readPrecisely(strio, l) 
     698        r = struct.unpack(self.fmt, buff) 
     699        self.type = r[0] 
     700 
     701    def isAuthoritative(self): 
     702        return self.auth 
     703 
     704    def __str__(self): 
     705        return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 
     706 
     707    @staticmethod 
     708    def factory(strio, auth=False): 
     709        ''' 
     710        reads enough of the stream to figure out if what is there is 
     711        an OPTHeader or an RRHeader 
     712        ''' 
     713        beginPos = strio.tell() 
     714        name = Name() 
     715        name.decode(strio) 
     716        type = struct.unpack(OPTHeader.fmt, readPrecisely(strio, 2))[0] 
     717         
     718        if len(name.name) == 0 and type == OPT: 
     719            return OPTHeader() 
     720        else: 
     721            #back up to the beginning and try again 
     722            strio.seek(beginPos, 0) 
     723            rrh = RRHeader(auth=auth) 
     724            rrh.decode(strio) 
     725            return rrh 
     726         
     727    __repr__ = __str__ 
     728     
     729     
     730class RRHeader(OPTHeader): 
     731    """ 
    439732    A resource record header. 
    440733 
    441734    @cvar fmt: C{str} specifying the byte format of an RR. 
     
    445738    @ivar cls: The query class of the original request. 
    446739    @ivar ttl: The time-to-live for this record. 
    447740    @ivar payload: An object that implements the IEncodable interface 
    448  
    449     @ivar auth: A C{bool} indicating whether this C{RRHeader} was parsed from an 
    450         authoritative message. 
     741    @ivar auth: Whether this header is authoritative or not. 
    451742    """ 
    452743 
    453744    implements(IEncodable) 
     
    14691760        return hash(tuple(self.data)) 
    14701761 
    14711762 
     1763class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1764    """ 
     1765    EDNS0 Option record. 
     1766     
     1767    @type payload_size: C{int} 
     1768    @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 
     1769        network can handle. 
     1770     
     1771    @type dnssecOk: C{bool} 
     1772    @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 
     1773        validation (and set the AD bit if the response validates). 
     1774         
     1775    @type version: C{int} 
     1776    @ivar version: The version of DNSSEC used. Currently only version 0  
     1777        is defined. 
     1778    """ 
     1779    implements(IEncodable, IRecord) 
     1780    TYPE = OPT 
     1781    fmt = '!HBBHH' 
     1782     
     1783    fancybasename = 'OPT' 
     1784    showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 
     1785    compareAttributes = ('payload_size', 'flags', 'version') 
     1786     
     1787    def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 
     1788        self.payload_size = payload_size 
     1789        self.version = version 
     1790        self.flags = (dnssecOk & 1) << 15 
     1791         
     1792    def encode(self, strio, compDict = None): 
     1793        OPTHeader().encode(strio) 
     1794        strio.write(struct.pack('!H', self.payload_size)) 
     1795        strio.write(struct.pack('!B', 0)) # high order 0 
     1796        strio.write(struct.pack('!B', self.version)) 
     1797        strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 
     1798        strio.write(struct.pack('!H', 0)) # Data length: 0 
     1799         
     1800    def decode(self, strio, length=None): 
     1801        ''' 
     1802        are OPT Records always 0 rdlength? 
     1803        ''' 
     1804        l = struct.calcsize(self.fmt) 
     1805        buff = readPrecisely(strio, l) 
     1806        r = struct.unpack(self.fmt, buff) 
     1807        self.payload_size, z, self.version, self.flags, length = r 
     1808        assert length == 0 
     1809         
     1810    def __hash__(self): 
     1811        return hash((self.payload_size, self.version, self.flags)) 
    14721812 
     1813class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1814    """ 
     1815    DNSSEC RRSIG record.  See RFC 4034 for details. 
     1816     
     1817    @type type_covered: C{int} 
     1818    @ivar type_covered: Identifies the type of the RRset that this RRSIG covers.  
     1819     
     1820    @type algo: C{int} 
     1821    @ivar algo: Identifies the crypto algorithm type used to create the signature. 
     1822        (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 
     1823     
     1824    @type labels: C{int} 
     1825    @ivar labels: Specifies the number of labels in the original RRSIG RR owner name. 
     1826        A validator can use this to determine whether the answer was synthesized from 
     1827        a wildcard. 
     1828     
     1829    @type original_ttl: C{int} 
     1830    @ivar original_ttl: Specifies the TTL of the covered RRset as it appears in the  
     1831        authoritative zone. 
     1832     
     1833    @type sig_expiration: C{int}  
     1834    @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 
     1835        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1836     
     1837    @type sig_inception: C{int}  
     1838    @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 
     1839        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1840     
     1841    @type key_tag: C{int} 
     1842    @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates this 
     1843        signature, in network byte order. See RFC 4034 App B. 
     1844     
     1845    @type signers_name: L{Name} 
     1846    @ivar signers_name: Identifies the owner name of the DNSKEY RR that a validator 
     1847        should use to validate this signature. Must not use DNS name compression. 
     1848     
     1849    @type signature: L{Sigstr} 
     1850    @ivar signature: Contains the cryptographic signature that covers the RRSIG 
     1851        RDATA (excluding the Signature field and the RRset specified by the  RRSIG 
     1852        owner name, RRSIG class and RRSIG Type Covered fields. 
     1853     
     1854    @type ttl: C{int} 
     1855    @ivar ttl: The maximum number of seconds which this record should be 
     1856        cached. 
     1857    """ 
     1858    implements(IEncodable, IRecord) 
     1859    TYPE = RRSIG 
     1860    fmt = '!HBBIIIH' 
     1861     
     1862    fancybasename = 'RRSIG' 
     1863    showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1864                         ('_sig_expiration', 'sig_expiration', '%s'), 
     1865                         ('_sig_inception', 'sig_inception', '%s'), 
     1866                         'key_tag',  
     1867                         ('signers_name', 'signers_name', '%s'),  
     1868                         ('_signature', 'signature', '%s'), 'ttl') 
     1869    compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl',  
     1870                         'sig_expiration', 'sig_inception', 'key_tag',  
     1871                         'signers_name', 'signature', 'ttl') 
     1872     
     1873    _sig_expiration = property(lambda self: str(self.sig_expiration)) 
     1874    _sig_inception = property(lambda self: str(self.sig_inception)) 
     1875    _signature = property(lambda self: self.signature.string) 
     1876     
     1877    def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0,  
     1878                 sig_expiration='', sig_inception='', key_tag=0,  
     1879                 signers_name='', signature='', ttl=None): 
     1880        self.type_covered = type_covered 
     1881        self.algo = algo 
     1882        self.labels = labels 
     1883        self.original_ttl = original_ttl 
     1884        self.sig_expiration = DateSNA(sig_expiration) 
     1885        self.sig_inception = DateSNA(sig_inception) 
     1886        self.key_tag = key_tag 
     1887        self.signers_name = Name(signers_name) 
     1888        self.signature = Sigstr(signature) 
     1889        self.ttl = str2time(ttl) 
     1890         
     1891    def encode(self, strio, compDict = None): 
     1892        strio.write(struct.pack(self.fmt,  
     1893                                self.type_covered, 
     1894                                self.algo,  
     1895                                self.labels, 
     1896                                self.original_ttl, 
     1897                                self.sig_expiration.asInt(), 
     1898                                self.sig_inception.asInt(), 
     1899                                self.key_tag)) 
     1900        self.signers_name.encode(strio, None) 
     1901        self.signature.encode(strio, compDict)         
     1902         
     1903    def decode(self, strio, length=None): 
     1904        start = strio.tell() 
     1905        l = struct.calcsize(self.fmt) 
     1906        buff = readPrecisely(strio, l) 
     1907        r = struct.unpack(self.fmt, buff)         
     1908        self.type_covered, self.algo, self.labels, self.original_ttl, \ 
     1909            sig_expiration, sig_inception, self.key_tag = r  
     1910        self.sig_expiration = DateSNA.fromInt(sig_expiration) 
     1911        self.sig_inception = DateSNA.fromInt(sig_inception) 
     1912        self.signers_name.decode(strio) 
     1913        here = strio.tell() 
     1914        self.signature.decode(strio, length + start - here if length else None) 
     1915                 
     1916    def __hash__(self): 
     1917        return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 
     1918                     self.sig_expiration, self.sig_inception, self.key_tag, 
     1919                     self.signers_name, self.signature))     
     1920 
     1921class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1922    """ 
     1923    A DNSSEC DS record. 
     1924     
     1925    @type key_tag: C{int} 
     1926    @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS record. 
     1927     
     1928    @type algo: C{int} 
     1929    @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this DS record.     
     1930 
     1931    @type digest_type: C{int} 
     1932    @ivar digest_type: Identifies the algorithm used to construct the digest field. 
     1933     
     1934    @type digest: L{Sigstr} 
     1935    @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by the 
     1936        algorithm identified by the digest_type field. 
     1937 
     1938    @type ttl: C{int} 
     1939    @ivar ttl: The maximum number of seconds which this record should be 
     1940        cached.     
     1941    """ 
     1942    implements(IEncodable, IRecord) 
     1943    TYPE = DS 
     1944    fmt = '!HBB' 
     1945     
     1946    fancybasename = 'DS' 
     1947    showAttributes = ('key_tag', 'algo', 'digest_type', ('_digest', 'digest', '%s'), 'ttl') 
     1948    compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 
     1949     
     1950    _digest = property(lambda self: self.digest.string) 
     1951 
     1952    def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 
     1953        self.key_tag = key_tag 
     1954        self.algo = algo 
     1955        self.digest_type = digest_type 
     1956        self.digest = Sigstr(digest) 
     1957        self.ttl = str2time(ttl) 
     1958         
     1959    def encode(self, strio, compDict = None): 
     1960        strio.write(struct.pack(self.fmt,  
     1961                                self.key_tag, 
     1962                                self.algo,  
     1963                                self.digest_type)) 
     1964        self.digest.encode(strio, None) 
     1965         
     1966    def decode(self, strio, length=None): 
     1967        start = strio.tell() 
     1968        l = struct.calcsize(self.fmt) 
     1969        buff = readPrecisely(strio, l) 
     1970        r = struct.unpack(self.fmt, buff)         
     1971        self.key_tag, self.algo, self.digest_type = r         
     1972        here = strio.tell() 
     1973        self.digest.decode(strio, length + start - here if length else None) 
     1974                 
     1975    def __hash__(self): 
     1976        return hash((self.key_tag, self.algo, self.digest_type, self.digest))     
     1977 
     1978class Record_DNSKEY(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1979    """ 
     1980    A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 
     1981     
     1982    @type flags: C{int} 
     1983    @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 
     1984        DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 
     1985        the name of a zone.  If bit 7 has value 0, then the DNSKEY record 
     1986        holds some other type of DNS public key and MUST NOT be used to  
     1987        verify RRSIGs that cover RRsets.   
     1988        Bit 15 is the Secure Entry Point flag. See RFC 3757.)  
     1989        All other bits are reserved and must be zero. 
     1990         
     1991    @type protocol: C{int} 
     1992    @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 
     1993        if this field does not contain 3. 
     1994     
     1995    @type algo: C{int} 
     1996    @ivar algo: Identifies the public key's cryptographic algorithm and determines 
     1997        the format of the pub_key field.  See RFC 4034 App A. 
     1998     
     1999    @type pub_key: L{Sigstr} 
     2000    @ivar pub_key: Holds the public key material. 
     2001 
     2002    @type ttl: C{int} 
     2003    @ivar ttl: The maximum number of seconds which this record should be 
     2004        cached.     
     2005    """ 
     2006    implements(IEncodable, IRecord) 
     2007    TYPE = DNSKEY 
     2008    fmt = '!HBB' 
     2009     
     2010    fancybasename = 'DNSKEY' 
     2011    showAttributes = ('flags', 'protocol', 'algo', ('_pub_key', 'pub_key', '%s'), 'ttl') 
     2012    compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 
     2013     
     2014    _pub_key = property(lambda self: self.pub_key.string) 
     2015     
     2016    def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 
     2017        self.flags = flags 
     2018        self.protocol = protocol 
     2019        self.algo = algo 
     2020        self.pub_key = Sigstr(pub_key) 
     2021        self.ttl = str2time(ttl) 
     2022         
     2023    def encode(self, strio, compDict = None): 
     2024        strio.write(struct.pack(self.fmt,  
     2025                                self.flags, 
     2026                                self.protocol,  
     2027                                self.algo)) 
     2028        self.pub_key.encode(strio, None) 
     2029         
     2030    def decode(self, strio, length=None): 
     2031        start = strio.tell() 
     2032        l = struct.calcsize(self.fmt) 
     2033        buff = readPrecisely(strio, l) 
     2034        r = struct.unpack(self.fmt, buff)         
     2035        self.flags, self.protocol, self.algo = r         
     2036        here = strio.tell() 
     2037        self.pub_key.decode(strio, length + start - here if length else None) 
     2038                 
     2039    def __hash__(self): 
     2040        return hash((self.flags, self.protocol, self.algo, self.pub_key)) 
     2041 
     2042class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2043    """ 
     2044    A DNSSEC NSEC record provides authenticated denial of existance for DNS data.  
     2045 
     2046    A DNSSEC NSEC record lists: 
     2047     
     2048        1) the next owner name in canonical ordering of the zone that contains authoritataive 
     2049           data or a delegation point NS RRset. 
     2050         
     2051        2) the set of RR types present at the NSEC RR's owner name. 
     2052 
     2053    @type nxt_name: L{Name} 
     2054    @ivar nxt_name: The next owner name that has authoritative data or contains a 
     2055        delegation point NS RRset. 
     2056     
     2057    @type type_bitmaps: L{TypeBitmaps} 
     2058    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's owner name. 
     2059     
     2060    @type ttl: C{int} 
     2061    @ivar ttl: The maximum number of seconds which this record should be 
     2062        cached. 
     2063    """ 
     2064    implements(IEncodable, IRecord) 
     2065    TYPE = NSEC 
     2066     
     2067    fancybasename = 'NSEC' 
     2068    showAttributes = (('nxt_name', 'nxt_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2069    compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 
     2070     
     2071    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2072     
     2073    def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 
     2074        self.nxt_name = Name(nxt_name) 
     2075        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2076        self.ttl = str2time(ttl) 
     2077         
     2078    def encode(self, strio, compDict = None): 
     2079        self.nxt_name.encode(strio, None) 
     2080        self.type_bitmaps.encode(strio, None) 
     2081         
     2082    def decode(self, strio, length=None): 
     2083        start = strio.tell() 
     2084        self.nxt_name.decode(strio, None) 
     2085        here = strio.tell() 
     2086        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2087                 
     2088    def __hash__(self): 
     2089        return hash((self.nxt_name, self.type_bitmaps)) 
     2090 
     2091class Record_NSEC3PARAM(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2092    """ 
     2093    A DNSSEC NSEC3PARAM record contains the NSEC3 parameters (hash algorithm, 
     2094    flags, iterations and salt) needed by authoritative servers to calculate 
     2095    hashed owner names.  The presence of an NSEC3PARAM RR at a zone apex 
     2096    indicates that the specified parameters may be used by authoritative  
     2097    servers to choose an appropriate set of NSEC3 RRs for negative responses.  
     2098 
     2099    @type hash_algo: C{int} 
     2100    @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 
     2101     
     2102    @type flags: C{int} 
     2103    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the  
     2104        opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 
     2105        delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 
     2106     
     2107    @type iterations: C{int} 
     2108    @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 
     2109     
     2110    @type salt: L{Charset} 
     2111    @ivar salt: Identifies the salt value provided to the hash. 
     2112 
     2113    @type ttl: C{int} 
     2114    @ivar ttl: The maximum number of seconds which this record should be 
     2115        cached. 
     2116    """ 
     2117    implements(IEncodable, IRecord) 
     2118    TYPE = NSEC3 
     2119    fmt = '!BBH' 
     2120     
     2121    fancybasename = 'NSEC3' 
     2122    showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), 'ttl') 
     2123    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'ttl') 
     2124     
     2125    _salt = property(lambda self: self.salt.string) 
     2126     
     2127    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', ttl=None): 
     2128        self.hash_algo = hash_algo 
     2129        self.flags = flags 
     2130        self.iterations = iterations 
     2131        self.salt = Charstr(salt) 
     2132        self.ttl = str2time(ttl) 
     2133         
     2134    def encode(self, strio, compDict = None): 
     2135        strio.write(struct.pack(self.fmt, 
     2136                                self.hash_algo, 
     2137                                self.flags, 
     2138                                self.iterations)) 
     2139        self.salt.encode(strio, None) 
     2140         
     2141    def decode(self, strio, length=None): 
     2142        start = strio.tell() 
     2143        l = struct.calcsize(self.fmt) 
     2144        buff = readPrecisely(strio, l) 
     2145        r = struct.unpack(self.fmt, buff)         
     2146        self.hash_algo, self.flags, self.iterations = r    
     2147        self.salt.decode(strio) 
     2148        here = strio.tell() 
     2149                 
     2150    def __hash__(self): 
     2151        return hash((self.hash_algo, self.flags, self.iterations, self.salt)) 
     2152     
     2153class Record_NSEC3(Record_NSEC3PARAM): 
     2154    """ 
     2155    A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of existance  
     2156    for DNS data and permits a gradual expansion of delegation-centric zones.  
     2157 
     2158    A DNSSEC NSEC3 record lists: 
     2159     
     2160        1) the set of RR types present at the original owner name of the NSEC RR. 
     2161 
     2162        2) the next hashed owner name in the hash order of the zone. 
     2163 
     2164    @type hash_algo: C{int} 
     2165    @ivar hash_algo: Identifies the cryptographic hash algorithm used to construct the hash value. 
     2166     
     2167    @type flags: C{int} 
     2168    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is the  
     2169        opt-out flag. If the opt-out flag is set, the NSEC3 record covers zero or more unsigned 
     2170        delegations. If the opt-out flag is clear, the NSEC3 record covers zero unsigned delegations. 
     2171     
     2172    @type iterations: C{int} 
     2173    @ivar iterations: Defines the nubmer of additional times the hash algorithm has been performed. 
     2174     
     2175    @type salt: L{Charset} 
     2176    @ivar salt: Identifies the salt value provided to the hash. 
     2177     
     2178    @type nxt_hash_owner_name: L{Charset} 
     2179    @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone in hash order. 
     2180     
     2181    @type type_bitmaps: L{TypeBitmaps} 
     2182    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's original owner name. 
     2183     
     2184    @type ttl: C{int} 
     2185    @ivar ttl: The maximum number of seconds which this record should be 
     2186        cached. 
     2187    """ 
     2188    implements(IEncodable, IRecord) 
     2189    TYPE = NSEC3 
     2190    fmt = '!BBH' 
     2191     
     2192    fancybasename = 'NSEC3' 
     2193    showAttributes = ('hash_algo', 'flags', 'iterations', ('_salt', 'salt', '%s'), ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2194    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 
     2195     
     2196    _salt = property(lambda self: self.salt.string) 
     2197    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2198     
     2199    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', nxt_hash_owner='', type_bitmaps=None, ttl=None): 
     2200        Record_NSEC3PARAM.__init__( self, hash_algo, flags, iterations, salt, ttl) 
     2201        self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 
     2202        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2203         
     2204    def encode(self, strio, compDict = None): 
     2205        Record_NSEC3PARAM.encode(self, strio, compDict) 
     2206        self.nxt_hash_owner_name.encode(strio, None) 
     2207        self.type_bitmaps.encode(strio, None) 
     2208         
     2209    def decode(self, strio, length=None): 
     2210        start = strio.tell() 
     2211        Record_NSEC3PARAM.decode(self, strio, compDict) 
     2212        self.nxt_hash_owner_name.decode(strio) 
     2213        here = strio.tell() 
     2214        self.type_bitmaps.decode(strio, length + start - here if length else None) 
     2215                 
     2216    def __hash__(self): 
     2217        return hash((self.hash_algo, self.flags, self.iterations, self.salt, 
     2218                     self.nxt_hash_owner_name, self.type_bitmaps)) 
     2219 
    14732220# This is a fallback record 
    14742221class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 
    14752222    """ 
     
    15462293    queries = answers = add = ns = None 
    15472294 
    15482295    def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 
    1549                        auth=0, rCode=OK, trunc=0, maxSize=512): 
     2296                 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 
    15502297        self.maxSize = maxSize 
    15512298        self.id = id 
    15522299        self.answer = answer 
    15532300        self.opCode = opCode 
    1554         self.auth = auth 
    1555         self.trunc = trunc 
    1556         self.recDes = recDes 
    1557         self.recAv = recAv 
     2301        self.auth = auth            #AA - Authoritative Answer 
     2302        self.trunc = trunc          #TC - TrunCated 
     2303        self.recDes = recDes        #RD - Recursion Desired 
     2304        self.recAv = recAv          #RA - Recursion Available 
     2305        self.authData = authData    #AD - Authentic Data 
     2306        self.chkDis = chkDis        #CD - Checking Disabled 
    15582307        self.rCode = rCode 
    15592308        self.queries = [] 
    15602309        self.answers = [] 
     
    15992348                 | ((self.auth & 1 ) << 2 ) 
    16002349                 | ((self.trunc & 1 ) << 1 ) 
    16012350                 | ( self.recDes & 1 ) ) 
    1602         byte4 = ( ( (self.recAv & 1 ) << 7 ) 
     2351        byte4 = (  ((self.recAv & 1 ) << 7 ) 
     2352                  |((self.authData & 1 ) << 5 ) 
     2353                  |((self.chkDis & 1 ) << 4 ) 
    16032354                  | (self.rCode & 0xf ) ) 
    16042355 
    16052356        strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, 
     
    16192370        self.trunc = ( byte3 >> 1 ) & 1 
    16202371        self.recDes = byte3 & 1 
    16212372        self.recAv = ( byte4 >> 7 ) & 1 
     2373        self.authData = ( byte4 >> 5 ) & 1 
     2374        self.chkDis = ( byte4 >> 4 ) & 1 
    16222375        self.rCode = byte4 & 0xf 
    16232376 
    16242377        self.queries = [] 
     
    16372390 
    16382391    def parseRecords(self, list, num, strio): 
    16392392        for i in range(num): 
    1640             header = RRHeader(auth=self.auth) 
    16412393            try: 
    1642                 header.decode(strio) 
     2394                header = OPTHeader.factory(strio, auth=self.auth) 
    16432395            except EOFError: 
    16442396                return 
    16452397            t = self.lookupRecordType(header.type) 
     
    17492501            query, or errbacked with any errors that could happen (exceptions 
    17502502            during writing of the query, timeout errors, ...). 
    17512503        """ 
    1752         m = Message(id, recDes=1) 
     2504        chkDis=self.controller.dnssecConfig.chkDis 
     2505        m = Message(id, recDes=self.controller.dnssecConfig.recDes, chkDis=chkDis) 
    17532506        m.queries = queries 
     2507        if self.controller.dnssecConfig.ednsEnabled: 
     2508            m.additional = [Record_OPT(payload_size = self.controller.dnssecConfig.maxUdpPktSz, 
     2509                                       version = self.controller.dnssecConfig.version, 
     2510                                       dnssecOk = self.controller.dnssecConfig.dnssecOk)] 
    17542511 
    17552512        try: 
    17562513            writeMessage(m) 
     
    18042561        self.transport.write(message.toStr(), address) 
    18052562 
    18062563    def startListening(self): 
    1807         self._reactor.listenUDP(0, self, maxPacketSize=512) 
     2564        maxPacketSize = 512 
     2565        if self.controller.dnssecConfig.ednsEnabled: 
     2566            maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 
     2567        self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 
    18082568 
    18092569    def datagramReceived(self, data, addr): 
    18102570        """ 
  • names/secondary.py

     
    9090 
    9191    @ivar _reactor: The reactor to use to perform the zone transfers, or C{None} 
    9292        to use the global reactor. 
     93     
     94    #ivar dnssecConfig a L{DnssecConfig} giving the DNSSEC configuration to set  
     95        on the resolver. 
    9396    """ 
    9497 
    9598    transferring = False 
     
    97100    _port = 53 
    98101    _reactor = None 
    99102 
    100     def __init__(self, primaryIP, domain): 
    101         common.ResolverBase.__init__(self) 
     103    def __init__(self, primaryIP, domain, dnssecConfig=None): 
     104        common.ResolverBase.__init__(self, dnssecConfig) 
    102105        self.primary = primaryIP 
    103106        self.domain = domain 
    104107 
  • 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_client.py

     
    88from twisted.names import client, dns 
    99from twisted.names.error import DNSQueryTimeoutError 
    1010from twisted.trial import unittest 
    11 from twisted.names.common import ResolverBase 
     11from twisted.names.common import ResolverBase, DnssecConfig 
     12from twisted.names.dns import Query, Message 
    1213from twisted.internet import defer, error 
    1314from twisted.python import failure 
    1415from twisted.python.deprecate import getWarningMethod, setWarningMethod 
    1516from twisted.python.compat import set 
     17from twisted.names.test.test_rootresolve import MemoryReactor 
    1618 
    1719 
    1820class FakeResolver(ResolverBase): 
     
    428430        # Disconnecting should remove the protocol from the connection list: 
    429431        protocol.connectionLost(None) 
    430432        self.assertNotIn(protocol, resolver.connections) 
     433         
     434         
     435    def _edns0ConfigurationTest(self, reactor, resolver): 
     436        """ 
     437        A Resolver created with edns0 sends an OPT record as part of the  
     438        query indicating the maxUdpPktSz and EDNS version supported  
     439        (only EDNS version 0 - the default - is defined by spec). 
     440         
     441        In addition, check that the message flag bits (DO, CD, RC) agree 
     442        with the flags set in the resolver. 
     443        """ 
     444        #make sure EDNS is enabled 
     445        self.assertTrue(resolver.dnssecConfig.ednsEnabled) 
     446         
     447        d = resolver._query(('example.com', 53), 
     448                            [Query('foo.example.com',dns.A, dns.IN)],  
     449                            30) 
     450                    
     451        # A UDP port should have been started 
     452        portNumber, transport = reactor.udpPorts.popitem() 
     453         
     454        # and a DNS packet sent 
     455        [(packet, address)] = transport._sentPackets 
     456         
     457        msg = Message() 
     458        msg.fromStr(packet) 
     459         
     460        # the query should have an additional OPT Header with  
     461        # version == 0 and payload_size as defined by the resolver's dnssecConfig 
     462        # and DO should be set 
     463        self.assertEqual(len(msg.additional), 1) 
     464        additional = msg.additional[0] 
     465        self.assertEqual(additional.type, dns.OPT) 
     466        self.assertEqual(additional.payload.version, resolver.dnssecConfig.version) 
     467        self.assertEqual(additional.payload.payload_size, resolver.dnssecConfig.maxUdpPktSz) 
     468        #payload.flags bit 15 is DO, should equal resolver.dnssecOk's truth value 
     469        self.assertEqual(not not(additional.payload.flags & 0x8000), resolver.dnssecConfig.dnssecOk) 
     470         
     471        # the rest of the query should be as above also 
     472        self.assertEqual(msg.queries, [Query('foo.example.com', dns.A, dns.IN)]) 
     473        self.assertEqual(msg.answers, []) 
     474        self.assertEqual(msg.authority, []) 
    431475 
     476        # the message header flags should be set as per the resolver's dnssecConfig settings 
     477        self.assertEqual(msg.chkDis, resolver.dnssecConfig.chkDis) 
     478        self.assertEqual(msg.recDes, resolver.dnssecConfig.recDes) 
     479         
     480        response = [] 
     481        d.addCallback(response.append) 
     482        self.assertEqual(response, []) 
     483         
     484        # Once a reply is received, the Deferred should fire. 
     485        # Make the flag bits in the message agree with what you asked for 
     486        del msg.queries[:] 
     487        msg.answer = 1 
     488        msg.answers.append(dns.RRHeader('foo.example.com', payload=dns.Record_A('5.8.13.21'))) 
     489        msg.authData = resolver.dnssecConfig.dnssecOk #if you requested DO, say you got AD 
     490        msg.chkDis = resolver.dnssecConfig.chkDis 
     491        msg.recDes = resolver.dnssecConfig.recDes 
     492        transport._protocol.datagramReceived(msg.toStr(), ('1.1.2.4', 1053)) 
     493        return response[0] 
    432494 
     495     
     496    def test_dnssecEnabled(self): 
     497        """ 
     498        A query sent with DNSSEC Enabled has an additional OPT record with  
     499        DO set. Such a query returns a 4-tuple as a result, with the 4th 
     500        member of the tuple being the message with the header bits set as 
     501        set in the original query. 
     502        """ 
     503        # Create a resolver with EDNS0, max packet size = 4096,  
     504        # and dnssecOk, chkDis and recDes = True 
     505        maxPacketSize = 4096 
     506        dsc = DnssecConfig(ednsEnabled=True,  
     507                           maxUdpPktSz=maxPacketSize, 
     508                           dnssecOk=True,  # DO 
     509                           chkDis=True,    # CD 
     510                           recDes=True)    # RC 
    433511 
     512        reactor = MemoryReactor() 
     513        resolver = client.Resolver(servers=[('example.com', 53)],  
     514                                   reactor=reactor,  
     515                                   dnssecConfig=dsc) 
     516          
     517        message = self._edns0ConfigurationTest(reactor, resolver) 
     518         
     519        #check that a resolver with dnssecOk returns a 4-tuple with the header set as in the query 
     520        answer, authority, additional, message = resolver.filterAnswers(message) 
     521        self.assertEqual(answer, 
     522                         [dns.RRHeader('foo.example.com', payload=dns.Record_A('5.8.13.21', ttl=0))]) 
     523        self.assertEqual(authority, []) 
     524        self.assertEqual(additional, []) 
     525        self.assertIsInstance(message, dns.Message) 
     526        self.assertTrue(message.authData) 
     527        self.assertTrue(message.chkDis) 
     528        self.assertTrue(message.recDes) 
     529     
     530     
     531    def test_dnssecDisabled(self): 
     532        """ 
     533        A query sent with DNSSEC Disabled but EDNS enabled has an additional  
     534        OPT record with DO clear. Such a query returns a 3-tuple as a result. 
     535        """ 
     536         
     537        # Create a resolver with EDNS0, max packet size = 4096,  
     538        # and dnssecOk = False, but recDes = True 
     539        maxPacketSize = 4096 
     540        dsc = DnssecConfig(ednsEnabled=True,  
     541                           maxUdpPktSz=maxPacketSize, 
     542                           dnssecOk=False, # not DO 
     543                           recDes=True)    # RC 
     544 
     545        reactor = MemoryReactor() 
     546        resolver = client.Resolver(servers=[('example.com', 53)],  
     547                                   reactor=reactor,  
     548                                   dnssecConfig=dsc) 
     549          
     550        message = self._edns0ConfigurationTest(reactor, resolver) 
     551         
     552        #check that a resolver with dnssecOk == False returns a 3-tuple 
     553        #containing the right stuff. Note - no access to header info in this case 
     554        answer, authority, additional = resolver.filterAnswers(message) 
     555        self.assertEqual(answer, 
     556                         [dns.RRHeader('foo.example.com', payload=dns.Record_A('5.8.13.21', ttl=0))]) 
     557        self.assertEqual(authority, []) 
     558        self.assertEqual(additional, []) 
     559         
     560 
    434561class ClientTestCase(unittest.TestCase): 
    435562 
    436563    def setUp(self): 
     
    658785        return d 
    659786 
    660787 
     788    def test_lookupDNSKey(self): 
     789        """ 
     790        See L{test_lookupAddress} 
     791        """ 
     792        d = client.lookupDNSKey(self.hostname) 
     793        d.addCallback(self.checkResult, dns.DNSKEY) 
     794        return d 
     795 
     796 
     797    def test_lookupDS(self): 
     798        """ 
     799        See L{test_lookupAddress} 
     800        """ 
     801        d = client.lookupDS(self.hostname) 
     802        d.addCallback(self.checkResult, dns.DS) 
     803        return d 
     804 
     805 
     806    def test_lookupNSEC(self): 
     807        """ 
     808        See L{test_lookupAddress} 
     809        """ 
     810        d = client.lookupNSEC(self.hostname) 
     811        d.addCallback(self.checkResult, dns.NSEC) 
     812        return d 
     813 
     814 
     815    def test_lookupNSEC3(self): 
     816        """ 
     817        See L{test_lookupAddress} 
     818        """ 
     819        d = client.lookupNSEC3(self.hostname) 
     820        d.addCallback(self.checkResult, dns.NSEC3) 
     821        return d 
     822 
     823 
     824    def test_lookupNSEC3Param(self): 
     825        """ 
     826        See L{test_lookupAddress} 
     827        """ 
     828        d = client.lookupNSEC3Param(self.hostname) 
     829        d.addCallback(self.checkResult, dns.NSEC3PARAM) 
     830        return d 
     831 
     832 
     833    def test_lookupRRSIG(self): 
     834        """ 
     835        See L{test_lookupAddress} 
     836        """ 
     837        d = client.lookupRRSIG(self.hostname) 
     838        d.addCallback(self.checkResult, dns.RRSIG) 
     839        return d 
     840 
     841 
    661842class ThreadedResolverTests(unittest.TestCase): 
    662843    """ 
    663844    Tests for L{client.ThreadedResolver}. 
  • names/test/test_dns.py

     
    88 
    99from cStringIO import StringIO 
    1010 
     11import re 
    1112import struct 
    1213 
    1314from twisted.python.failure import Failure 
    1415from twisted.internet import address, task 
    1516from twisted.internet.error import CannotListenError, ConnectionDone 
    1617from twisted.trial import unittest 
    17 from twisted.names import dns 
     18from twisted.names import dns, common 
    1819 
    1920from twisted.test import proto_helpers 
    2021 
     
    2526    dns.Record_WKS, dns.Record_SRV, dns.Record_AFSDB, dns.Record_RP, 
    2627    dns.Record_HINFO, dns.Record_MINFO, dns.Record_MX, dns.Record_TXT, 
    2728    dns.Record_AAAA, dns.Record_A6, dns.Record_NAPTR, dns.UnknownRecord, 
     29    dns.Record_OPT, dns.Record_RRSIG, dns.Record_DS, dns.Record_DNSKEY, 
     30    dns.Record_NSEC, dns.Record_NSEC3PARAM, dns.Record_NSEC3, 
    2831    ] 
    2932 
    3033class NameTests(unittest.TestCase): 
     
    189192    """Encoding and then decoding various objects.""" 
    190193 
    191194    names = ["example.org", "go-away.fish.tv", "23strikesback.net"] 
    192  
     195    sigs = ["Qm12VZVaZgKS0/DZx35SGECDwPiTTf3ngChb7OkgSv5iupVmJGhPWudm /18qBSXKyv9hxMlEXFFgpBieNqLfSBkP1bwKnlqPfr1Hx7ctDwDUpkT3 cS8u/ms9yo3Fu1ybpO4Hfsb1HbA2N3zzQnjWKnyk26AAQSz8KgjNTFzD tJM=", 
     196            "ZH2kahMD1g2WOieIotAcBwB0e/o30Zq6YR//M/xwP1ktkYuclmcR56iv XiR3QFWqmN5Xz3YpgmM4tZkjIeSMp2doYa7XYORZ7OpzG7oyfo8IoXxc j1VGDeAn1CeNCpBtoSGapRABG1gjY7oeRj/smPQPp2Gkf79+WZfuzRom /t4=",  
     197            "AZpaboyNQAmbnBO1K66QmZ0c+VCdY/wu9QpEdRnMpnIOLPD28pNVu6hk GQMz6eg5WYkPYDdJK+1D/oyAQkDmRgn10+O9EdeFDyLqYqq/htEAvDm4 CziMSOpD/mkg1bSWCZ2mdln/GBk8WooCeeM7LEHmRjmHMMj0xb6N4SKa MEc=",  
     198            "AwEAAbi5VQa3x+R3WQouBDNts+ZX2zIKZNoj9pzl7ew446kI/2omv3j6 c/4RQ6VneYE3mK7r0fFIKhVagmiRroFO1rRUJ8sVidssZ35CldE0sju+ E7wymVg3tV+ZUUO/+5v6Sfj+tw3rlp6eKqm7EGKKM88t+KuXiGYMu0Vw Rm9OUO1n",     
     199            "AwEAAbmTL+kuV45kAxGN//iBKz93Y6lutgxoptp+I1+PZZMsBkhm/dZj q57040Pz/Hr3f2zQX7z6fFu7/Ml3MHPH1eQDiVXDvOkeNq2x4IbCO7x+ 0p6bGYj4fw/tEfh/8dUzyzvMwfuAMsOvXza8Kh+UP4jvFc95cUuGgYus uEjUOp40PsL7EtYvAks3UssA6/OZP4w/1Z5m/VFx4PzgY0dkEuc=",     
     200            "VGPxa8A81eV1dtUxVhz9b9Jsp6FF4M5H6J0QhzbNCUTHTHjLNR2VHYfE fM+Akwo3/qKq3D6vzTfzqtyPAXP8CmGfdD8hfv0s7Hae9c7Is8usdlrk ZpoXEFMW+YVG8G9OieYViq6tBIpUvKgMVZ+oXKo63KJ/tC/yBW0H0VQP YwdzZ3ZvYRDmZDvrXoX7T0YNU+0HYHnb7g7nUECIJ/4HHg==", 
     201            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFE h9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffp Z9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55 Y1k="] 
     202    type_bitmaps = ["A MX RRSIG NSEC TYPE1234", 
     203                    "AAAA NS CNAME MX TXT RRSIG NSEC3 DNAME", 
     204                    "NSEC3 A AAAA RRSIG DS NS TYPE5000 TYPE1000 TYPE2000 TYPE3000 TYPE4000", 
     205                    None] 
     206                     
    193207    def testName(self): 
    194208        for n in self.names: 
    195209            # encode the name 
     
    276290            self.assertEqual(result.string, n) 
    277291 
    278292 
     293    def test_Sigstr(self): 
     294        """ 
     295        Test L{dns.Sigstr} encode and decode. 
     296        """ 
     297        for s in self.sigs: 
     298            # encode the signature/key 
     299            f = StringIO() 
     300            dns.Sigstr(s).encode(f) 
     301            l = f.tell() 
     302 
     303            # decode the signature/key 
     304            f.seek(0, 0) 
     305            result = dns.Sigstr() 
     306            result.decode(f,l) 
     307            #spaces are free, and dig sticks them in 
     308            self.assertEqual(result.string, s.replace(' ', '')) 
     309 
     310 
     311    def test_TypeBitmaps(self): 
     312        """ 
     313        Test L{dns.TypeBitmaps} encode and decode. 
     314        """ 
     315        typeRegex = re.compile('TYPE(\d+)') 
     316         
     317        for b in self.type_bitmaps: 
     318            # encode the type_bitmaps 
     319            f = StringIO() 
     320            dns.TypeBitmaps(b).encode(f) 
     321            l = f.tell() 
     322 
     323            # decode the type_bitmaps 
     324            f.seek(0, 0) 
     325            result = dns.TypeBitmaps() 
     326            result.decode(f,l) 
     327             
     328            def mnuVal(mnu): 
     329                mnuVal = dns.REV_TYPES.get(mnu, None) 
     330                if not mnuVal: 
     331                    m = typeRegex.match(mnu) 
     332                    if m.groups(): 
     333                        mnuVal = int(m.group(1)) 
     334                        assert mnuVal < 65536 
     335                    else: 
     336                        log.err("can't parse %s in %s" % (mnu, self.string, )) 
     337                        mnuVal = 0 
     338                return mnuVal 
     339             
     340            def sorttok(string): 
     341                if not string: 
     342                    return '' 
     343                 
     344                toks = string.split(' ') 
     345                toks.sort(key = mnuVal) 
     346                return ' '.join(toks) 
     347             
     348            self.assertEqual(result.type_bitmaps, sorttok(b)) 
     349 
     350 
    279351    def test_NAPTR(self): 
    280352        """ 
    281353        Test L{dns.Record_NAPTR} encode and decode. 
     
    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 
  • names/test/test_names.py

     
    9898                           '\x12\x01\x16\xfe\xc1\x00\x01'), 
    9999            dns.Record_NAPTR(100, 10, "u", "sip+E2U", 
    100100                             "!^.*$!sip:information@domain.tld!"), 
    101             dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF')], 
     101            dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF'), 
     102            dns.Record_DNSKEY(0x10, 3, 5,  
     103                              "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=" 
     104                             )], 
    102105        'http.tcp.test-domain.com': [ 
    103106            dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') 
    104107        ], 
    105108        'host.test-domain.com': [ 
    106109            dns.Record_A('123.242.1.5'), 
    107110            dns.Record_A('0.255.0.255'), 
     111            dns.Record_RRSIG(dns.A, 5, 3, 86400, '20120101000000', '20120201000000', 2642, 'test-domain.com',  
     112                            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=") 
    108113        ], 
    109114        'host-two.test-domain.com': [ 
    110115# 
     
    434439            [dns.Record_NAPTR(100, 10, "u", "sip+E2U", 
    435440                              "!^.*$!sip:information@domain.tld!", 
    436441                              ttl=19283784)]) 
     442     
     443    def test_DNSKEY(self): 
     444        """Test DNS 'DNSKEY' record queries.""" 
     445        return self.namesTest( 
     446            self.resolver.lookupDNSKey('test-domain.com'), 
     447            [dns.Record_DNSKEY(0x10, 3, 5,  
     448                               "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=", 
     449                               ttl=19283784)]) 
    437450 
    438  
    439  
    440451class DNSServerFactoryTests(unittest.TestCase): 
    441452    """ 
    442453    Tests for L{server.DNSServerFactory}. 
     
    890901        self.assertEqual(service.domains[1].domain, 'example.edu') 
    891902 
    892903 
    893  
    894904class SecondaryAuthorityTests(unittest.TestCase): 
    895905    """ 
    896906    L{twisted.names.secondary.SecondaryAuthority} correctly constructs objects 
  • names/test/test_ser_num_arith.py

     
     1# Copyright (c) Twisted Matrix Laboratories. 
     2# See LICENSE for details. 
     3 
     4""" 
     5Test cases for L{twisted.names.ser_num_arith}. 
     6""" 
     7 
     8from twisted.names.ser_num_arith import SNA, DateSNA 
     9from twisted.trial import unittest 
     10 
     11class SNATest(unittest.TestCase): 
     12 
     13    def setUp(self): 
     14        self.s1 = SNA(1) 
     15        self.s1a = SNA(1) 
     16        self.s2 = SNA(2) 
     17        self.sMaxVal = SNA(SNA.HLFRNG+SNA.HLFRNG-1) 
     18 
     19    def test_equality(self): 
     20        """ 
     21        Test SNA equality 
     22        """ 
     23        self.assertEqual(self.s1, self.s1a) 
     24        self.assertNotIdentical(self.s1, self.s1a) 
     25        self.assertEqual(hash(self.s1), hash(self.s1a)) 
     26        self.assertNotEqual(hash(self.s1), hash(self.s2)) 
     27         
     28    def test_le(self): 
     29        """ 
     30        Test SNA less than or equal 
     31        """ 
     32        self.assertTrue( self.s1 <= self.s1 ) 
     33        self.assertTrue( self.s1 <= self.s1a ) 
     34        self.assertTrue( self.s1 <= self.s2 ) 
     35        self.assertFalse( self.s2 <= self.s1 ) 
     36         
     37    def test_ge(self): 
     38        """ 
     39        Test SNA greater than or equal 
     40        """ 
     41        self.assertTrue( self.s1 >= self.s1 ) 
     42        self.assertTrue( self.s1 >= self.s1a ) 
     43        self.assertFalse( self.s1 >= self.s2 ) 
     44        self.assertTrue( self.s2 >= self.s1 ) 
     45         
     46         
     47    def test_lt(self): 
     48        """ 
     49        Test SNA less than 
     50        """ 
     51        self.assertFalse( self.s1 < self.s1 ) 
     52        self.assertFalse( self.s1 < self.s1a ) 
     53        self.assertTrue( self.s1 < self.s2 ) 
     54        self.assertFalse( self.s2 < self.s1 ) 
     55         
     56    def test_gt(self): 
     57        """ 
     58        Test SNA greater than 
     59        """ 
     60        self.assertFalse( self.s1 > self.s1 ) 
     61        self.assertFalse( self.s1 > self.s1a ) 
     62        self.assertFalse( self.s1 > self.s2 ) 
     63        self.assertTrue( self.s2 > self.s1 ) 
     64 
     65    def test_add(self): 
     66        """ 
     67        Test SNA addition 
     68        """ 
     69        self.assertEqual( self.s1 + self.s1, self.s2) 
     70        self.assertEqual( self.s1 + SNA(SNA.MAXADD), SNA(SNA.MAXADD + 1) ) 
     71        self.assertEqual( SNA(SNA.MAXADD) + SNA(SNA.MAXADD) + SNA(2), SNA(0) ) 
     72         
     73    def test_maxval(self): 
     74        """ 
     75        Test SNA maxval 
     76        """ 
     77        smaxplus1 = self.sMaxVal + self.s1 
     78        self.assertTrue( smaxplus1 > self.sMaxVal ) 
     79        self.assertEqual( smaxplus1, SNA(0) ) 
     80         
     81    def test_max(self): 
     82        """ 
     83        Test the SNA max function 
     84        """ 
     85        self.assertEqual( SNA.max([None, self.s1]), self.s1 ) 
     86        self.assertEqual( SNA.max([self.s1, None]), self.s1 ) 
     87        self.assertEqual( SNA.max([self.s1, self.s1a]), self.s1 ) 
     88        self.assertEqual( SNA.max([self.s2, self.s1a, self.s1, None]), self.s2 ) 
     89        self.assertEqual( SNA.max([SNA(SNA.MAXADD), self.s2, self.s1a, self.s1, None]), SNA(SNA.MAXADD) ) 
     90        self.assertEqual( SNA.max([self.s2, self.s1a, self.s1, None, self.sMaxVal]), self.s2 ) 
     91 
     92    def test_dateSNA(self): 
     93        """ 
     94        Test DateSNA construction and comparison 
     95        """ 
     96        date1 = DateSNA('20120101000000')  
     97        date2 = DateSNA('20130101000000') 
     98        self.assertTrue( date1 < date2 ) 
     99         
     100    def test_dateAdd(self): 
     101        """ 
     102        Test DateSNA addition 
     103        """ 
     104        date3 = DateSNA('20370101000000') 
     105        sna1  = SNA(365*24*60*60) 
     106        date4 = date3 + sna1 
     107        self.assertEqual( date4.asInt(),  date3.asInt() + sna1.asInt()) 
     108 
     109    def test_asDate(self): 
     110        """ 
     111        Test DateSNA conversion 
     112        """ 
     113        date1 = '20120101000000' 
     114        date1Sna = DateSNA(date1) 
     115        self.assertEqual(date1Sna.asDate(), date1) 
     116         
     117    def test_roundTrip(self): 
     118        """ 
     119        Test DateSNA conversion 
     120        """ 
     121        date1 = '20370101000000' 
     122        date1Sna = DateSNA(date1) 
     123        intval = date1Sna.asInt() 
     124        sna1a = SNA(intval) 
     125         
     126        dateSna1a = DateSNA.fromSNA(sna1a) 
     127        self.assertEqual(date1Sna, dateSna1a) 
     128         
     129        dateSna2 = DateSNA.fromInt(intval) 
     130        self.assertEqual(date1Sna, dateSna2) 
     131         
     132 No newline at end of file