Ticket #5454: addEdsn0AndDnssec5454V03.patch

File addEdsn0AndDnssec5454V03.patch, 101.7 KB (added by BobNovas, 2 years ago)

replaces V02 file of similar name

  • doc/names/examples/index.xhtml

     
    1515        <li><a href="testdns.py">testdns.py</a></li> 
    1616        <li><a href="dns-service.py">dns-service.py</a></li> 
    1717        <li><a href="gethostbyname.py">gethostbyname.py</a></li> 
     18        <li><a href="dnssecTest.py">dnssecTest.py</a></li> 
    1819    </ul> 
    1920</body> 
    2021</html> 
  • doc/names/examples/testdnssec.py

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

     
    4949directives are not yet supported. 
    5050</p> 
    5151 
     52<h2>Using DNS Security Extensions (DNSSEC)</h2> 
     53 
     54<p>DNSSEC adds data origin authentication and data integrity to the Domain Name System (see RFC4033.) To use DNSSEC requires EDNS0, because to enable DNSSEC requires setting the DNSSEC OK (DO) bit which is in the EDNS0 OPT Record. RFC4035 discusses how a non-validating security aware resolver (which is what twisted.names is with the DNSSEC change) should handle the DO, CD and AD bits. 
     55</p> 
     56 
     57<p><a href="../../../doc/names/examples/dnssecTest.py" class="py-listings">dnssecTest.py</a> is an example of using DNSSEC to check the AD bit of a domain that should validate. 
     58</p> 
     59 
    5260</body></html> 
  • twisted/names/client.py

     
    7171    protocol = property(_getProtocol) 
    7272 
    7373 
    74     def __init__(self, resolv=None, servers=None, timeout=(1, 3, 11, 45), reactor=None): 
     74    def __init__(self, 
     75                 resolv=None, 
     76                 servers=None, 
     77                 timeout=(1, 3, 11, 45), 
     78                 reactor=None, 
     79                 dnssecConfig=None): 
    7580        """ 
    7681        Construct a resolver which will query domain name servers listed in 
    7782        the C{resolv.conf(5)}-format file given by C{resolv} as well as 
     
    99104            for DNS datagrams, and enforce timeouts.  If not provided, the 
    100105            global reactor will be used. 
    101106 
     107        @param dnssecConfig: An L{DnssecConfig} - see common.DnssecConfig() 
     108 
    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) 
    385391 
     392        #if dnssecOk is enabled, return a reference to the message as the 
     393        #4th member of the tuple, so the caller can access the message header 
     394        #flags. There are more flags than just AD (authentic Data) that are 
     395        #set in a response that may be of interest (e.g., Truncate-TC). 
     396        if self.dnssecConfig.dnssecOk: 
     397            return (message.answers, message.authority, 
     398                    message.additional, message) 
     399        else: 
     400            #dnssecOk was not requested - return a legacy 3-tuple 
     401            return (message.answers, message.authority, message.additional) 
    386402 
     403 
    387404    def _lookup(self, name, cls, type, timeout): 
    388405        """ 
    389406        Build a L{dns.Query} for the given parameters and dispatch it via UDP. 
     
    953970    @rtype: C{Deferred} 
    954971    """ 
    955972    return getResolver().lookupNamingAuthorityPointer(name, timeout) 
     973 
     974 
     975def lookupDNSKey(name, timeout=None): 
     976    """ 
     977    DNSKEY lookup. 
     978 
     979    @type name: C{str} 
     980    @param name: DNS name to resolve. 
     981 
     982    @type timeout: Sequence of C{int} 
     983    @param timeout: Number of seconds after which to reissue the query. 
     984        When the last timeout expires, the query is considered failed. 
     985 
     986    @rtype: C{Deferred} 
     987    """ 
     988    return getResolver().lookupDNSKey(name, timeout) 
     989 
     990 
     991def lookupDS(name, timeout=None): 
     992    """ 
     993    DS lookup. 
     994 
     995    @type name: C{str} 
     996    @param name: DNS name to resolve. 
     997 
     998    @type timeout: Sequence of C{int} 
     999    @param timeout: Number of seconds after which to reissue the query. 
     1000        When the last timeout expires, the query is considered failed. 
     1001 
     1002    @rtype: C{Deferred} 
     1003    """ 
     1004    return getResolver().lookupDS(name, timeout) 
     1005 
     1006 
     1007def lookupNSEC(name, timeout=None): 
     1008    """ 
     1009    NSEC lookup. 
     1010 
     1011    @type name: C{str} 
     1012    @param name: DNS name to resolve. 
     1013 
     1014    @type timeout: Sequence of C{int} 
     1015    @param timeout: Number of seconds after which to reissue the query. 
     1016        When the last timeout expires, the query is considered failed. 
     1017 
     1018    @rtype: C{Deferred} 
     1019    """ 
     1020    return getResolver().lookupNSEC(name, timeout) 
     1021 
     1022 
     1023def lookupNSEC3(name, timeout=None): 
     1024    """ 
     1025    NSEC3 lookup. 
     1026 
     1027    @type name: C{str} 
     1028    @param name: DNS name to resolve. 
     1029 
     1030    @type timeout: Sequence of C{int} 
     1031    @param timeout: Number of seconds after which to reissue the query. 
     1032        When the last timeout expires, the query is considered failed. 
     1033 
     1034    @rtype: C{Deferred} 
     1035    """ 
     1036    return getResolver().lookupNSEC3(name, timeout) 
     1037 
     1038 
     1039def lookupNSEC3Param(name, timeout=None): 
     1040    """ 
     1041    NSEC3 Param lookup. 
     1042 
     1043    @type name: C{str} 
     1044    @param name: DNS name to resolve. 
     1045 
     1046    @type timeout: Sequence of C{int} 
     1047    @param timeout: Number of seconds after which to reissue the query. 
     1048        When the last timeout expires, the query is considered failed. 
     1049 
     1050    @rtype: C{Deferred} 
     1051    """ 
     1052    return getResolver().lookupNSEC3Param(name, timeout) 
     1053 
     1054 
     1055def lookupRRSIG(name, timeout=None): 
     1056    """ 
     1057    RRSIG lookup. 
     1058 
     1059    @type name: C{str} 
     1060    @param name: DNS name to resolve. 
     1061 
     1062    @type timeout: Sequence of C{int} 
     1063    @param timeout: Number of seconds after which to reissue the query. 
     1064        When the last timeout expires, the query is considered failed. 
     1065 
     1066    @rtype: C{Deferred} 
     1067    """ 
     1068    return getResolver().lookupRRSIG(name, timeout) 
  • twisted/names/common.py

     
    1818 
    1919EMPTY_RESULT = (), (), () 
    2020 
     21 
     22 
     23class DnssecConfig(): 
     24    """ 
     25    Sets recDes and the DNSSEC parameters. See RFC's 4033, 4034 and 4035. 
     26 
     27    recDes (RD)   - Recursion Desired. Not a DNSSEC parameter and does not 
     28                    require ednsEnabled, but still nice to be able to control 
     29                    whether or not you're asking for recursion. 
     30                    (bool) 
     31 
     32    ednsEnabled   - EDNS Enabled adds an OPT record to the query. The OPT record 
     33                    contains a version field that indicates the version of EDNS 
     34                    that you can handle. 
     35                    (bool) 
     36 
     37    maxUdpPktSz   - The max size UDP packet (bytes) that your end-to-end network 
     38                    can handle (on a modern network a reliable size is 1492, 
     39                    although up to 65535 is possible). Requires ednsEnabled. 
     40                    (int) 
     41 
     42    dnssecOK (DO) - Dnssec Ok. A bit that indicates you want DNSSEC RR's and 
     43                    validation if the resolver validates. If DO is set, AD 
     44                    will be set in the response if the answer validates. 
     45                    Requires ednsEnabled. 
     46                    (bool) 
     47 
     48    chkDis (CD)   - Checking Disabled. If DO and CD are set, a validating 
     49                    resolver won't do validation but will return the DNSSEC 
     50                    RR's so that YOU can. 
     51                    (bool) 
     52 
     53    version       - sets the edns version level. Currently, only version 0 is 
     54                    defined and supported by RFC2671. 
     55                    (int) 
     56    """ 
     57    def __init__(self, 
     58                 recDes=True, 
     59                 ednsEnabled=False, 
     60                 maxUdpPktSz=512, 
     61                 dnssecOk=False, 
     62                 chkDis=False, 
     63                 version=0): 
     64 
     65        self.recDes = recDes 
     66        self.ednsEnabled = ednsEnabled 
     67        self.maxUdpPktSz = maxUdpPktSz 
     68        self.dnssecOk = dnssecOk 
     69        self.chkDis = chkDis 
     70        self.version = version 
     71 
     72        assert not self.ednsEnabled or 512 <= self.maxUdpPktSz <= 65535 
     73        assert version == 0 
     74 
     75 
     76 
    2177class ResolverBase: 
    2278    """ 
    2379    L{ResolverBase} is a base class for L{IResolver} implementations which 
     
    3692 
    3793    typeToMethod = None 
    3894 
    39     def __init__(self): 
     95    def __init__(self, dnssecConfig=None): 
    4096        self.typeToMethod = {} 
    4197        for (k, v) in typeToMethod.items(): 
    4298            self.typeToMethod[k] = getattr(self, v) 
     99        self.dnssecConfig = dnssecConfig 
     100        if self.dnssecConfig == None: 
     101            self.dnssecConfig = DnssecConfig() 
    43102 
    44  
    45103    def exceptionForCode(self, responseCode): 
    46104        """ 
    47105        Convert a response code (one of the possible values of 
     
    201259        """ 
    202260        return self._lookup(name, dns.IN, dns.ALL_RECORDS, timeout) 
    203261 
     262 
     263    def lookupDNSKey(self, name, timeout=None): 
     264        """ 
     265        @see: twisted.names.client.lookupDNSKey 
     266        """ 
     267        return self._lookup(name, dns.IN, dns.DNSKEY, timeout) 
     268 
     269 
     270    def lookupDS(self, name, timeout=None): 
     271        """ 
     272        @see: twisted.names.client.lookupDS 
     273        """ 
     274        return self._lookup(name, dns.IN, dns.DS, timeout) 
     275 
     276 
     277    def lookupNSEC(self, name, timeout=None): 
     278        """ 
     279        @see: twisted.names.client.lookupNSEC 
     280        """ 
     281        return self._lookup(name, dns.IN, dns.NSEC, timeout) 
     282 
     283 
     284    def lookupNSEC3(self, name, timeout=None): 
     285        """ 
     286        @see: twisted.names.client.lookupNSEC3 
     287        """ 
     288        return self._lookup(name, dns.IN, dns.NSEC3, timeout) 
     289 
     290 
     291    def lookupNSEC3Param(self, name, timeout=None): 
     292        """ 
     293        @see: twisted.names.client.lookupNSEC3Param 
     294        """ 
     295        return self._lookup(name, dns.IN, dns.NSEC3PARAM, timeout) 
     296 
     297 
     298    def lookupRRSIG(self, name, timeout=None): 
     299        """ 
     300        @see: twisted.names.client.lookupRRSIG 
     301        """ 
     302        return self._lookup(name, dns.IN, dns.RRSIG, timeout) 
     303 
     304 
    204305    def getHostByName(self, name, timeout = None, effort = 10): 
    205306        """ 
    206307        @see: twisted.names.client.getHostByName 
     
    268369    dns.MX:    'lookupMailExchange', 
    269370    dns.TXT:   'lookupText', 
    270371    dns.SPF:   'lookupSenderPolicy', 
     372    dns.DNSKEY:'lookupDNSKey', 
     373    dns.DS:    'lookupDS', 
     374    dns.NSEC:  'lookupNSEC', 
     375    dns.NSEC3: 'lookupNSEC3', 
     376    dns.NSEC3PARAM: 'lookupNSEC3Param', 
     377    dns.RRSIG: 'lookupRRSIG', 
    271378 
    272379    dns.RP:    'lookupResponsibility', 
    273380    dns.AFSDB: 'lookupAFSDatabase', 
  • twisted/names/dns.py

     
    1515__all__ = [ 
    1616    'IEncodable', 'IRecord', 
    1717 
    18     'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'HINFO', 
     18    'A', 'A6', 'AAAA', 'AFSDB', 'CNAME', 'DNAME', 'DNSKEY', 'DS', 'HINFO', 
    1919    'MAILA', 'MAILB', 'MB', 'MD', 'MF', 'MG', 'MINFO', 'MR', 'MX', 
    20     'NAPTR', 'NS', 'NULL', 'PTR', 'RP', 'SOA', 'SPF', 'SRV', 'TXT', 'WKS', 
     20    'NAPTR', 'NS', 'NSEC', 'NSEC3', 'NSEC3PARAM', 'NULL', 'OPT', 'PTR', 
     21    'RP', 'RRSIG', 'SOA', 'SPF', 'SRV', 'TXT', 'WKS', 
    2122 
    2223    'ANY', 'CH', 'CS', 'HS', 'IN', 
    2324 
     
    2627    'EFORMAT', 'ENAME', 'ENOTIMP', 'EREFUSED', 'ESERVER', 
    2728 
    2829    'Record_A', 'Record_A6', 'Record_AAAA', 'Record_AFSDB', 'Record_CNAME', 
    29     'Record_DNAME', 'Record_HINFO', 'Record_MB', 'Record_MD', 'Record_MF', 
     30    'Record_DNAME', 'Record_DNSKEY', 'Record_DS', 'Record_HINFO', 'Record_MB', 
     31    'Record_MD', 'Record_MF', 
    3032    'Record_MG', 'Record_MINFO', 'Record_MR', 'Record_MX', 'Record_NAPTR', 
    31     'Record_NS', 'Record_NULL', 'Record_PTR', 'Record_RP', 'Record_SOA', 
    32     'Record_SPF', 'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 
     33    'Record_NS', 'Record_NSEC', 'Record_NSEC3', 'Record_NULL', 'Record_OPT', 
     34    'Record_PTR', 'Record_RP', 'Record_RRSIG', 'Record_SOA', 'Record_SPF', 
     35    'Record_SRV', 'Record_TXT', 'Record_WKS', 'UnknownRecord', 
    3336 
    3437    'QUERY_CLASSES', 'QUERY_TYPES', 'REV_CLASSES', 'REV_TYPES', 'EXT_QUERIES', 
    3538 
    36     'Charstr', 'Message', 'Name', 'Query', 'RRHeader', 'SimpleRecord', 
    37     'DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', 
     39    'Charstr', 'Message', 'Name', 'OPTHeader', 'Query', 'RRHeader', 
     40    'SimpleRecord','DNSDatagramProtocol', 'DNSMixin', 'DNSProtocol', 
    3841 
    3942    'OK', 'OP_INVERSE', 'OP_NOTIFY', 'OP_QUERY', 'OP_STATUS', 'OP_UPDATE', 
    4043    'PORT', 
     
    4649# System imports 
    4750import warnings 
    4851 
     52import re 
    4953import struct, random, types, socket 
    5054 
    5155import cStringIO as StringIO 
     
    5458 
    5559from zope.interface import implements, Interface, Attribute 
    5660 
     61from base64 import b64decode, b64encode 
    5762 
    5863# Twisted imports 
    5964from twisted.internet import protocol, defer 
     
    6166from twisted.python import log, failure 
    6267from twisted.python import util as tputil 
    6368from twisted.python import randbytes 
     69from twisted.names.ser_num_arith import SNA, DateSNA 
    6470 
    6571 
    6672def randomSource(): 
     
    7985NAPTR = 35 
    8086A6 = 38 
    8187DNAME = 39 
     88OPT = 41 
     89DS = 43 
     90RRSIG = 46 
     91NSEC = 47 
     92DNSKEY = 48 
     93NSEC3 = 50 
     94NSEC3PARAM = 51 
    8295SPF = 99 
    8396 
    8497QUERY_TYPES = { 
     
    108121    NAPTR: 'NAPTR', 
    109122    A6: 'A6', 
    110123    DNAME: 'DNAME', 
    111     SPF: 'SPF' 
     124    OPT: 'OPT', 
     125    DS: 'DS', 
     126    RRSIG: 'RRSIG', 
     127    NSEC: 'NSEC', 
     128    DNSKEY: 'DNSKEY', 
     129    NSEC3: 'NSEC3', 
     130    NSEC3PARAM: 'NSEC3PARAM', 
     131    SPF: 'SPF', 
    112132} 
    113133 
    114134IXFR, AXFR, MAILB, MAILA, ALL_RECORDS = range(251, 256) 
     
    371391    def __str__(self): 
    372392        return self.name 
    373393 
     394class Sigstr(object): 
     395    ''' 
     396    for signatures and keys. display as b64 encoded 
     397    ''' 
     398    implements(IEncodable) 
     399 
     400    def __init__(self, string=''): 
     401        if not isinstance(string, str): 
     402            raise ValueError("%r is not a string" % (string, )) 
     403        self.string = string #b64encoded string 
     404 
     405    def encode(self, strio, compDict=None): 
     406        ''' 
     407        Write the byte representation (the un-b64-encoded string) 
     408        to the file. 
     409 
     410        @type strio: file 
     411        @param srio: The byte representation of this signature or key 
     412        will be written to this file 
     413 
     414        @type compDict: dict 
     415        @param compDict: not used. 
     416        ''' 
     417        strio.write(b64decode(self.string)) 
     418 
     419    def decode(self, strio, length=None): 
     420        ''' 
     421        Decode a signature or a key. 
     422 
     423        @type strio: file 
     424        @param strio: Exactly length bytes will be read from this file 
     425        to decode the full signature or key 
     426 
     427        @type length: int 
     428        @param lenth: length must always be given. A signature or key 
     429        is always the last thing in an RR and so you can always determine 
     430        its length. 
     431        ''' 
     432        self.string = '' 
     433        if length == None: 
     434            return 
     435 
     436        assert isinstance(length, int) 
     437        buff = readPrecisely(strio, length) 
     438        self.string = b64encode(buff) 
     439 
     440    def __eq__(self, other): 
     441        if isinstance(other, Sigstr): 
     442            return self.string == other.string 
     443        return False 
     444 
     445    def __hash__(self): 
     446        return hash(self.string) 
     447 
     448    def __str__(self): 
     449        return self.string 
     450 
     451 
     452class TypeBitmaps(object): 
     453    ''' 
     454    bitmap encoding scheme used by NSEC and NSEC3 RR's 
     455    to indicate the RRset types that exist at the 
     456    NSEC/NSEC3 RR's original owner name or hashed name. 
     457    See RFC 4034 and RFC 5155. 
     458    ''' 
     459    fmt = 'BB' 
     460    typeRegex = re.compile('TYPE(\d+)') 
     461 
     462    def __init__(self, string=''): 
     463        self.string = string 
     464 
     465    def encode(self, strio, compDict=None): 
     466        """ 
     467        Encode the string field, which consists of a set 
     468        of type names, into an NSEC/NSEC3 type bitmap. 
     469 
     470        @type strio: file 
     471        @param strio: the byte representation of the type bitmap 
     472        will be written to this file. 
     473 
     474        @type compDict: dict 
     475        @param compDict: not used. 
     476        """ 
     477        if not self.string: 
     478            return; 
     479 
     480        #get a sorted list of RR Type Values 
     481        mnus = self.string.split(' ') 
     482        mnuVals = [] 
     483        for mnu in mnus: 
     484            mnuVal = REV_TYPES.get(mnu, None) 
     485            if not mnuVal: 
     486                m = self.typeRegex.match(mnu) 
     487                if m.groups(): 
     488                    mnuVal = int(m.group(1)) 
     489                    assert mnuVal < 65536 
     490                else: 
     491                    log.err("can't parse %s in %s" % (mnu, self.string, )) 
     492                    continue; 
     493            mnuVals.append(mnuVal) 
     494        mnuVals.sort() 
     495 
     496        #convert that to a dict of windows and lists 
     497        windDict = {} 
     498        for v in mnuVals: 
     499            window = (v >> 8) & 0xFF 
     500            if window not in windDict: 
     501                windDict[window] = [] 
     502            windDict[window].append(v & 0xFF) 
     503 
     504        #have to sort the keys - they're not in order! 
     505        windows = windDict.keys() 
     506        windows.sort() 
     507 
     508        #create the bitmaps 
     509        bmap = bytearray() 
     510        for w in windows: 
     511            bmapseg = bytearray(32) 
     512            maxoff = 0 
     513            for v in windDict[w]: 
     514                vm1 = v - 1 
     515                off = vm1 >> 3 
     516                bit = vm1 & 0x7 
     517                msk = 1 << bit 
     518                bmapseg[off] |= msk 
     519                maxoff = max(off, maxoff) 
     520            bmapseg = bmapseg[0:maxoff+1] 
     521            bmap += chr(w) + chr(maxoff+1) + bmapseg 
     522 
     523        strio.write(str(bmap)) 
     524 
     525    def decode(self, strio, length=None): 
     526        """ 
     527        Decode an NSEC/NSEC3 type bitmap into a string 
     528        representation of type names. 
     529        """ 
     530        self.type_bitmaps = "" 
     531        if length == None: 
     532            return 
     533 
     534        type_bitmaps = bytearray() 
     535        l = struct.calcsize(self.fmt) 
     536        parsed_length = 0 
     537        while parsed_length < length: 
     538            buff = readPrecisely(strio, l) 
     539            wb_num, bm_len = struct.unpack(self.fmt, buff) 
     540            assert parsed_length + 2 + bm_len <= length 
     541            bm = readPrecisely(strio, bm_len) 
     542            byteNum = -1 
     543            for b in bm: 
     544                byteNum += 1 
     545                ob = ord(b) 
     546                if ob == 0: 
     547                    continue 
     548 
     549                for v in range(8): 
     550                    msk = 1<<v 
     551                    if ob & msk: 
     552                        val = wb_num*256 + byteNum*8 + v + 1 
     553                        mnu = QUERY_TYPES.get(val, None) 
     554                        if not mnu: 
     555                            mnu = 'TYPE' + str(val) 
     556                        type_bitmaps += (mnu + ' ') 
     557 
     558            parsed_length += 2 + bm_len 
     559 
     560        self.type_bitmaps = str(type_bitmaps[0:-1]) 
     561 
     562    def __eq__(self, other): 
     563        if isinstance(other, TypeBitmaps): 
     564            return self.string == other.string 
     565        return False 
     566 
     567    def __hash__(self): 
     568        return hash(self.string) 
     569 
     570    def __str__(self): 
     571        return self.string 
     572 
    374573class Query: 
    375574    """ 
    376575    Represent a single DNS query. 
     
    434633        return 'Query(%r, %r, %r)' % (str(self.name), self.type, self.cls) 
    435634 
    436635 
    437 class RRHeader(tputil.FancyEqMixin): 
     636 
     637class OPTHeader(tputil.FancyEqMixin): 
    438638    """ 
     639    A OPT record header. 
     640 
     641    @cvar fmt: C{str} specifying the byte format of an OPT Header. 
     642 
     643    @ivar name: Root (0, 8-bits) 
     644    @ivar type: 41 (OPT Record) 
     645    @ivar payload: An object that implements the IEncodable interface 
     646    @ivar auth: Whether this header is authoritative or not. 
     647    """ 
     648 
     649    implements(IEncodable) 
     650 
     651    compareAttributes = ('name', 'type', 'payload', 'auth') 
     652 
     653    fmt = "!H" 
     654 
     655    name = None 
     656    type = None 
     657    payload = None 
     658 
     659    #OPTHeader _really_ has no ttl or rdlength, but the 
     660    #existence of the attributes is required. 
     661    ttl = None 
     662    rdlength = None 
     663 
     664    cachedResponse = None 
     665 
     666 
     667    def __init__(self, payload=None, auth=False): 
     668        """ 
     669        @type name: C{str} 
     670        @param name: Root (0) 
     671 
     672        @type type: C{int} 
     673        @param type: Query type 41. 
     674 
     675        @type payload: An object implementing C{IEncodable} 
     676        @param payload: The OPT payload 
     677        """ 
     678        assert (payload is None) or (payload.TYPE == OPT) 
     679 
     680        self.name = 0 
     681        self.type = OPT 
     682        self.payload = payload 
     683        self.auth = auth 
     684 
     685 
     686    def encode(self, strio, compDict=None): 
     687        strio.write(struct.pack('!B', 0)) 
     688        strio.write(struct.pack(self.fmt, self.type)) 
     689        if self.payload: 
     690            prefix = strio.tell() 
     691            self.payload.encode(strio, compDict) 
     692            aft = strio.tell() 
     693            strio.seek(prefix - 2, 0) 
     694            strio.write(struct.pack('!H', aft - prefix)) 
     695            strio.seek(aft, 0) 
     696 
     697 
     698    def decode(self, strio, length = None): 
     699        self.name.decode(strio) 
     700        l = struct.calcsize(self.fmt) 
     701        buff = readPrecisely(strio, l) 
     702        r = struct.unpack(self.fmt, buff) 
     703        self.type = r[0] 
     704 
     705 
     706    def isAuthoritative(self): 
     707        return self.auth 
     708 
     709 
     710    def __str__(self): 
     711        return '<OPT auth=%s>' % (self.auth and 'True' or 'False') 
     712 
     713 
     714    @classmethod 
     715    def _headerFactory(cls, strio, auth=False): 
     716        ''' 
     717        reads enough of the stream to figure out if what is there is 
     718        an OPTHeader or an RRHeader 
     719        ''' 
     720        beginPos = strio.tell() 
     721        name = Name() 
     722        name.decode(strio) 
     723        type = struct.unpack(cls.fmt, readPrecisely(strio, 2))[0] 
     724 
     725        if len(name.name) == 0 and type == OPT: 
     726            return cls() 
     727        else: 
     728            #back up to the beginning and try again 
     729            strio.seek(beginPos, 0) 
     730            rrh = RRHeader(auth=auth) 
     731            rrh.decode(strio) 
     732            return rrh 
     733 
     734    __repr__ = __str__ 
     735 
     736 
     737 
     738class RRHeader(OPTHeader): 
     739    """ 
    439740    A resource record header. 
    440741 
    441742    @cvar fmt: C{str} specifying the byte format of an RR. 
     
    445746    @ivar cls: The query class of the original request. 
    446747    @ivar ttl: The time-to-live for this record. 
    447748    @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. 
     749    @ivar auth: Whether this header is authoritative or not. 
    451750    """ 
    452751 
    453752    implements(IEncodable) 
     
    10501349 
    10511350    fancybasename = 'SRV' 
    10521351    compareAttributes = ('priority', 'weight', 'target', 'port', 'ttl') 
    1053     showAttributes = ('priority', 'weight', ('target', 'target', '%s'), 'port', 'ttl') 
     1352    showAttributes = ('priority', 'weight', 
     1353                      ('target', 'target', '%s'), 'port', 'ttl') 
    10541354 
    10551355    def __init__(self, priority=0, weight=0, port=0, target='', ttl=None): 
    10561356        self.priority = int(priority) 
     
    14701770 
    14711771 
    14721772 
     1773class Record_OPT(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1774    """ 
     1775    EDNS0 Option record. 
     1776 
     1777    @type payload_size: C{int} 
     1778    @ivar payload_size: Specifies the max UDP Packet size (bytes) that your 
     1779        network can handle. 
     1780 
     1781    @type dnssecOk: C{bool} 
     1782    @ivar dnssecOk: Requests the server to send DNSSEC RRs and to do DNSSEC 
     1783        validation (and set the AD bit if the response validates). 
     1784 
     1785    @type version: C{int} 
     1786    @ivar version: The version of DNSSEC used. Currently only version 0 
     1787        is defined. 
     1788    """ 
     1789    implements(IEncodable, IRecord) 
     1790    TYPE = OPT 
     1791    fmt = '!HBBHH' 
     1792 
     1793    fancybasename = 'OPT' 
     1794    showAttributes = ('payload_size', ('flags', 'flags', '0x%x'), 'version') 
     1795    compareAttributes = ('payload_size', 'flags', 'version') 
     1796 
     1797 
     1798    def __init__(self, payload_size=512, dnssecOk=0, version=0, ttl=None): 
     1799        self.payload_size = payload_size 
     1800        self.version = version 
     1801        self.flags = (dnssecOk & 1) << 15 
     1802 
     1803 
     1804    def encode(self, strio, compDict = None): 
     1805        OPTHeader().encode(strio) 
     1806        strio.write(struct.pack('!H', self.payload_size)) 
     1807        strio.write(struct.pack('!B', 0)) # high order 0 
     1808        strio.write(struct.pack('!B', self.version)) 
     1809        strio.write(struct.pack('!H', self.flags)) # DO(bit) + Z's 
     1810        strio.write(struct.pack('!H', 0)) # Data length: 0 
     1811 
     1812 
     1813    def decode(self, strio, length=None): 
     1814        ''' 
     1815        are OPT Records always 0 rdlength? 
     1816        ''' 
     1817        l = struct.calcsize(self.fmt) 
     1818        buff = readPrecisely(strio, l) 
     1819        r = struct.unpack(self.fmt, buff) 
     1820        self.payload_size, z, self.version, self.flags, length = r 
     1821        assert length == 0 
     1822 
     1823 
     1824    def __hash__(self): 
     1825        return hash((self.payload_size, self.version, self.flags)) 
     1826 
     1827 
     1828 
     1829class Record_RRSIG(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1830    """ 
     1831    DNSSEC RRSIG record.  See RFC 4034 for details. 
     1832 
     1833    @type type_covered: C{int} 
     1834    @ivar type_covered: Identifies the type of the RRset that this RRSIG covers. 
     1835 
     1836    @type algo: C{int} 
     1837    @ivar algo: Identifies the crypto algorithm type used to create the 
     1838        signature. 
     1839        (5 - RSH/SHA-1 is mandatory. See RFC 4034 App A.1 for the full list.) 
     1840 
     1841    @type labels: C{int} 
     1842    @ivar labels: Specifies the number of labels in the original RRSIG RR 
     1843        owner name. A validator can use this to determine whether the answer 
     1844        was synthesized from a wildcard. 
     1845 
     1846    @type original_ttl: C{int} 
     1847    @ivar original_ttl: Specifies the TTL of the covered RRset as it appears 
     1848        in the authoritative zone. 
     1849 
     1850    @type sig_expiration: C{int} 
     1851    @ivar sig_expiration: This RRSIG must NOT be used after this time. Seconds 
     1852        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1853 
     1854    @type sig_inception: C{int} 
     1855    @ivar sig_inception: This RRSIG must NOT be used prior to this time. Seconds 
     1856        since 1/1/1970, Modulo 2**32, compare using DNS Serial Number Arithmetic 
     1857 
     1858    @type key_tag: C{int} 
     1859    @ivar key_tag: Contains the key tag value of the DNSKEY RR that validates 
     1860        this signature, in network byte order. See RFC 4034 App B. 
     1861 
     1862    @type signers_name: L{Name} 
     1863    @ivar signers_name: Identifies the owner name of the DNSKEY RR that a 
     1864        validator should use to validate this signature. Must not use DNS 
     1865        name compression. 
     1866 
     1867    @type signature: L{Sigstr} 
     1868    @ivar signature: Contains the cryptographic signature that covers the RRSIG 
     1869        RDATA (excluding the Signature field and the RRset specified by the 
     1870        RRSIG owner name, RRSIG class and RRSIG Type Covered fields. 
     1871 
     1872    @type ttl: C{int} 
     1873    @ivar ttl: The maximum number of seconds which this record should be 
     1874        cached. 
     1875    """ 
     1876    implements(IEncodable, IRecord) 
     1877    TYPE = RRSIG 
     1878    fmt = '!HBBIIIH' 
     1879 
     1880    fancybasename = 'RRSIG' 
     1881    showAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 
     1882                         ('_sig_expiration', 'sig_expiration', '%s'), 
     1883                         ('_sig_inception', 'sig_inception', '%s'), 
     1884                         'key_tag', 
     1885                         ('signers_name', 'signers_name', '%s'), 
     1886                         ('_signature', 'signature', '%s'), 'ttl') 
     1887    compareAttributes = ('type_covered', 'algo', 'labels', 'original_ttl', 
     1888                         'sig_expiration', 'sig_inception', 'key_tag', 
     1889                         'signers_name', 'signature', 'ttl') 
     1890 
     1891    _sig_expiration = property(lambda self: str(self.sig_expiration)) 
     1892    _sig_inception = property(lambda self: str(self.sig_inception)) 
     1893    _signature = property(lambda self: self.signature.string) 
     1894 
     1895 
     1896    def __init__(self, type_covered=A, algo=0, labels=0, original_ttl=0, 
     1897                 sig_expiration='', sig_inception='', key_tag=0, 
     1898                 signers_name='', signature='', ttl=None): 
     1899        self.type_covered = type_covered 
     1900        self.algo = algo 
     1901        self.labels = labels 
     1902        self.original_ttl = original_ttl 
     1903        self.sig_expiration = DateSNA(sig_expiration) 
     1904        self.sig_inception = DateSNA(sig_inception) 
     1905        self.key_tag = key_tag 
     1906        self.signers_name = Name(signers_name) 
     1907        self.signature = Sigstr(signature) 
     1908        self.ttl = str2time(ttl) 
     1909 
     1910 
     1911    def encode(self, strio, compDict = None): 
     1912        strio.write(struct.pack(self.fmt, 
     1913                                self.type_covered, 
     1914                                self.algo, 
     1915                                self.labels, 
     1916                                self.original_ttl, 
     1917                                self.sig_expiration.asInt(), 
     1918                                self.sig_inception.asInt(), 
     1919                                self.key_tag)) 
     1920        self.signers_name.encode(strio, None) 
     1921        self.signature.encode(strio, compDict) 
     1922 
     1923 
     1924    def decode(self, strio, length=None): 
     1925        start = strio.tell() 
     1926        l = struct.calcsize(self.fmt) 
     1927        buff = readPrecisely(strio, l) 
     1928        r = struct.unpack(self.fmt, buff) 
     1929        self.type_covered, self.algo, self.labels, self.original_ttl, \ 
     1930            sig_expiration, sig_inception, self.key_tag = r 
     1931        self.sig_expiration = DateSNA.fromInt(sig_expiration) 
     1932        self.sig_inception = DateSNA.fromInt(sig_inception) 
     1933        self.signers_name.decode(strio) 
     1934        here = strio.tell() 
     1935        self.signature.decode(strio, length + start - here if length else None) 
     1936 
     1937 
     1938    def __hash__(self): 
     1939        return hash((self.type_covered, self.algo, self.labels, self.original_ttl, 
     1940                     self.sig_expiration, self.sig_inception, self.key_tag, 
     1941                     self.signers_name, self.signature)) 
     1942 
     1943 
     1944 
     1945class Record_DS(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     1946    """ 
     1947    A DNSSEC DS record. 
     1948 
     1949    @type key_tag: C{int} 
     1950    @ivar key_tag: Lists the key tag of the DNSKEY RR referred to by this DS 
     1951        record. 
     1952 
     1953    @type algo: C{int} 
     1954    @ivar algo: Lists the algorithm number of the DNSKEY RR referenced by this 
     1955        DS record. 
     1956 
     1957    @type digest_type: C{int} 
     1958    @ivar digest_type: Identifies the algorithm used to construct the digest 
     1959        field. 
     1960 
     1961    @type digest: L{Sigstr} 
     1962    @ivar digest: Contains a digest of the refeerenced DNSKEY RR calculated by 
     1963        the algorithm identified by the digest_type field. 
     1964 
     1965    @type ttl: C{int} 
     1966    @ivar ttl: The maximum number of seconds which this record should be 
     1967        cached. 
     1968    """ 
     1969    implements(IEncodable, IRecord) 
     1970    TYPE = DS 
     1971    fmt = '!HBB' 
     1972 
     1973    fancybasename = 'DS' 
     1974    showAttributes = ('key_tag', 'algo', 'digest_type', 
     1975                      ('_digest', 'digest', '%s'), 'ttl') 
     1976    compareAttributes = ('key_tag', 'algo', 'digest_type', 'digest', 'ttl') 
     1977 
     1978    _digest = property(lambda self: self.digest.string) 
     1979 
     1980 
     1981    def __init__(self, key_tag=0, algo=0, digest_type=0, digest='', ttl=None): 
     1982        self.key_tag = key_tag 
     1983        self.algo = algo 
     1984        self.digest_type = digest_type 
     1985        self.digest = Sigstr(digest) 
     1986        self.ttl = str2time(ttl) 
     1987 
     1988 
     1989    def encode(self, strio, compDict = None): 
     1990        strio.write(struct.pack(self.fmt, 
     1991                                self.key_tag, 
     1992                                self.algo, 
     1993                                self.digest_type)) 
     1994        self.digest.encode(strio, None) 
     1995 
     1996 
     1997    def decode(self, strio, length=None): 
     1998        start = strio.tell() 
     1999        l = struct.calcsize(self.fmt) 
     2000        buff = readPrecisely(strio, l) 
     2001        r = struct.unpack(self.fmt, buff) 
     2002        self.key_tag, self.algo, self.digest_type = r 
     2003        here = strio.tell() 
     2004        self.digest.decode(strio, length + start - here if length else None) 
     2005 
     2006 
     2007    def __hash__(self): 
     2008        return hash((self.key_tag, self.algo, self.digest_type, self.digest)) 
     2009 
     2010 
     2011 
     2012class Record_DNSKEY(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2013    """ 
     2014    A DNSSEC DNSKEY record. Holds the public key for a signed RRset. 
     2015 
     2016    @type flags: C{int} 
     2017    @ivar flags: Bit 7 is the Zone Key flag. If bit 7 has value 1, then the 
     2018        DNSKEY record holds a DNS zone key and the DNSKEY RR's owner name is 
     2019        the name of a zone.  If bit 7 has value 0, then the DNSKEY record 
     2020        holds some other type of DNS public key and MUST NOT be used to 
     2021        verify RRSIGs that cover RRsets. 
     2022        Bit 15 is the Secure Entry Point flag. See RFC 3757.) 
     2023        All other bits are reserved and must be zero. 
     2024 
     2025    @type protocol: C{int} 
     2026    @ivar protocol: Must have value 3. The DNSKEY RR must be treated as invalid 
     2027        if this field does not contain 3. 
     2028 
     2029    @type algo: C{int} 
     2030    @ivar algo: Identifies the public key's cryptographic algorithm and 
     2031        determines the format of the pub_key field.  See RFC 4034 App A. 
     2032 
     2033    @type pub_key: L{Sigstr} 
     2034    @ivar pub_key: Holds the public key material. 
     2035 
     2036    @type ttl: C{int} 
     2037    @ivar ttl: The maximum number of seconds which this record should be 
     2038        cached. 
     2039    """ 
     2040    implements(IEncodable, IRecord) 
     2041    TYPE = DNSKEY 
     2042    fmt = '!HBB' 
     2043 
     2044    fancybasename = 'DNSKEY' 
     2045    showAttributes = ('flags', 'protocol', 'algo', 
     2046                      ('_pub_key', 'pub_key', '%s'), 'ttl') 
     2047    compareAttributes = ('flags', 'protocol', 'algo', 'pub_key', 'ttl') 
     2048 
     2049    _pub_key = property(lambda self: self.pub_key.string) 
     2050 
     2051 
     2052    def __init__(self, flags=0, protocol=0, algo=0, pub_key='', ttl=None): 
     2053        self.flags = flags 
     2054        self.protocol = protocol 
     2055        self.algo = algo 
     2056        self.pub_key = Sigstr(pub_key) 
     2057        self.ttl = str2time(ttl) 
     2058 
     2059 
     2060    def encode(self, strio, compDict = None): 
     2061        strio.write(struct.pack(self.fmt, 
     2062                                self.flags, 
     2063                                self.protocol, 
     2064                                self.algo)) 
     2065        self.pub_key.encode(strio, None) 
     2066 
     2067 
     2068    def decode(self, strio, length=None): 
     2069        start = strio.tell() 
     2070        l = struct.calcsize(self.fmt) 
     2071        buff = readPrecisely(strio, l) 
     2072        r = struct.unpack(self.fmt, buff) 
     2073        self.flags, self.protocol, self.algo = r 
     2074        here = strio.tell() 
     2075        self.pub_key.decode(strio, length + start - here if length else None) 
     2076 
     2077 
     2078    def __hash__(self): 
     2079        return hash((self.flags, self.protocol, self.algo, self.pub_key)) 
     2080 
     2081 
     2082 
     2083class Record_NSEC(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2084    """ 
     2085    A DNSSEC NSEC record provides authenticated denial of existance for DNS 
     2086    data. 
     2087 
     2088    A DNSSEC NSEC record lists: 
     2089 
     2090        1) the next owner name in canonical ordering of the zone that contains 
     2091           authoritative data or a delegation point NS RRset. 
     2092 
     2093        2) the set of RR types present at the NSEC RR's owner name. 
     2094 
     2095    @type nxt_name: L{Name} 
     2096    @ivar nxt_name: The next owner name that has authoritative data or contains 
     2097        a delegation point NS RRset. 
     2098 
     2099    @type type_bitmaps: L{TypeBitmaps} 
     2100    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC RR's 
     2101        owner name. 
     2102 
     2103    @type ttl: C{int} 
     2104    @ivar ttl: The maximum number of seconds which this record should be 
     2105        cached. 
     2106    """ 
     2107    implements(IEncodable, IRecord) 
     2108    TYPE = NSEC 
     2109 
     2110    fancybasename = 'NSEC' 
     2111    showAttributes = (('nxt_name', 'nxt_name', '%s'), 
     2112                      ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2113    compareAttributes = ('nxt_name', 'type_bitmaps', 'ttl') 
     2114 
     2115    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2116 
     2117 
     2118    def __init__(self, nxt_name='', type_bitmaps=None, ttl=None): 
     2119        self.nxt_name = Name(nxt_name) 
     2120        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2121        self.ttl = str2time(ttl) 
     2122 
     2123 
     2124    def encode(self, strio, compDict = None): 
     2125        self.nxt_name.encode(strio, None) 
     2126        self.type_bitmaps.encode(strio, None) 
     2127 
     2128 
     2129    def decode(self, strio, length=None): 
     2130        start = strio.tell() 
     2131        self.nxt_name.decode(strio, None) 
     2132        here = strio.tell() 
     2133        self.type_bitmaps.decode(strio, length + start - here if length 
     2134                                 else None) 
     2135 
     2136 
     2137    def __hash__(self): 
     2138        return hash((self.nxt_name, self.type_bitmaps)) 
     2139 
     2140 
     2141 
     2142class Record_NSEC3PARAM(tputil.FancyEqMixin, tputil.FancyStrMixin): 
     2143    """ 
     2144    A DNSSEC NSEC3PARAM record contains the NSEC3 parameters (hash algorithm, 
     2145    flags, iterations and salt) needed by authoritative servers to calculate 
     2146    hashed owner names.  The presence of an NSEC3PARAM RR at a zone apex 
     2147    indicates that the specified parameters may be used by authoritative 
     2148    servers to choose an appropriate set of NSEC3 RRs for negative responses. 
     2149 
     2150    @type hash_algo: C{int} 
     2151    @ivar hash_algo: Identifies the cryptographic hash algorithm used to 
     2152        construct the hash value. 
     2153 
     2154    @type flags: C{int} 
     2155    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined is 
     2156        the opt-out flag. If the opt-out flag is set, the NSEC3 record covers 
     2157        zero or more unsigned delegations. If the opt-out flag is clear, the 
     2158        NSEC3 record covers zero unsigned delegations. 
     2159 
     2160    @type iterations: C{int} 
     2161    @ivar iterations: Defines the nubmer of additional times the hash algorithm 
     2162        has been performed. 
     2163 
     2164    @type salt: L{Charset} 
     2165    @ivar salt: Identifies the salt value provided to the hash. 
     2166 
     2167    @type ttl: C{int} 
     2168    @ivar ttl: The maximum number of seconds which this record should be 
     2169        cached. 
     2170    """ 
     2171    implements(IEncodable, IRecord) 
     2172    TYPE = NSEC3 
     2173    fmt = '!BBH' 
     2174 
     2175    fancybasename = 'NSEC3' 
     2176    showAttributes = ('hash_algo', 'flags', 'iterations', 
     2177                      ('_salt', 'salt', '%s'), 'ttl') 
     2178    compareAttributes = ('hash_algo', 'flags', 'iterations', 'salt', 'ttl') 
     2179 
     2180    _salt = property(lambda self: self.salt.string) 
     2181 
     2182 
     2183    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', ttl=None): 
     2184        self.hash_algo = hash_algo 
     2185        self.flags = flags 
     2186        self.iterations = iterations 
     2187        self.salt = Charstr(salt) 
     2188        self.ttl = str2time(ttl) 
     2189 
     2190 
     2191    def encode(self, strio, compDict = None): 
     2192        strio.write(struct.pack(self.fmt, 
     2193                                self.hash_algo, 
     2194                                self.flags, 
     2195                                self.iterations)) 
     2196        self.salt.encode(strio, None) 
     2197 
     2198 
     2199    def decode(self, strio, length=None): 
     2200        start = strio.tell() 
     2201        l = struct.calcsize(self.fmt) 
     2202        buff = readPrecisely(strio, l) 
     2203        r = struct.unpack(self.fmt, buff) 
     2204        self.hash_algo, self.flags, self.iterations = r 
     2205        self.salt.decode(strio) 
     2206        here = strio.tell() 
     2207 
     2208 
     2209    def __hash__(self): 
     2210        return hash((self.hash_algo, self.flags, self.iterations, self.salt)) 
     2211 
     2212 
     2213 
     2214class Record_NSEC3(Record_NSEC3PARAM): 
     2215    """ 
     2216    A DNSSEC NSEC3 record provides non-zone-enumerable authenticated denial of 
     2217    existence for DNS data and permits a gradual expansion of delegation-centric 
     2218    zones. 
     2219 
     2220    A DNSSEC NSEC3 record lists: 
     2221 
     2222        1) the set of RR types present at the original owner name of the NSEC 
     2223           RR. 
     2224 
     2225        2) the next hashed owner name in the hash order of the zone. 
     2226 
     2227    @type hash_algo: C{int} 
     2228    @ivar hash_algo: Identifies the cryptographic hash algorithm used to 
     2229        construct the hash value. 
     2230 
     2231    @type flags: C{int} 
     2232    @ivar flags: Identifies 8 1-bit flags. The only flag presently defined 
     2233        is the opt-out flag. If the opt-out flag is set, the NSEC3 record 
     2234        covers zero or more unsigned delegations. If the opt-out flag is 
     2235        clear, the NSEC3 record covers zero unsigned delegations. 
     2236 
     2237    @type iterations: C{int} 
     2238    @ivar iterations: Defines the nubmer of additional times the hash algorithm 
     2239        has been performed. 
     2240 
     2241    @type salt: L{Charset} 
     2242    @ivar salt: Identifies the salt value provided to the hash. 
     2243 
     2244    @type nxt_hash_owner_name: L{Charset} 
     2245    @ivar nxt_hash_owner_name: Contains the next hashed owner name in the zone 
     2246        in hash order. 
     2247 
     2248    @type type_bitmaps: L{TypeBitmaps} 
     2249    @ivar type_bitmaps: Identifies the RRset types that exist at the NSEC3 RR's 
     2250        original owner name. 
     2251 
     2252    @type ttl: C{int} 
     2253    @ivar ttl: The maximum number of seconds which this record should be 
     2254        cached. 
     2255    """ 
     2256    implements(IEncodable, IRecord) 
     2257    TYPE = NSEC3 
     2258    fmt = '!BBH' 
     2259 
     2260    fancybasename = 'NSEC3' 
     2261    showAttributes = ('hash_algo', 'flags', 'iterations', 
     2262                      ('_salt', 'salt', '%s'), 
     2263                      ('nxt_hash_owner_name', 'nxt_hash_owner_name', '%s'), 
     2264                      ('_type_bitmaps', 'type_bitmaps', '%s'), 'ttl') 
     2265    compareAttributes = ('hash_algo', 'flags', 'iterations', 
     2266                         'salt', 'nxt_hash_owner_name', 'type_bitmaps', 'ttl') 
     2267 
     2268    _salt = property(lambda self: self.salt.string) 
     2269    _type_bitmaps = property(lambda self: self.type_bitmaps.string) 
     2270 
     2271 
     2272    def __init__(self, hash_algo=0, flags=0, iterations=0, salt='', 
     2273                 nxt_hash_owner='', type_bitmaps=None, ttl=None): 
     2274        Record_NSEC3PARAM.__init__(self, hash_algo, flags, 
     2275                                   iterations, salt, ttl) 
     2276        self.nxt_hash_owner_name = Charstr(nxt_hash_owner) 
     2277        self.type_bitmaps = TypeBitmaps(type_bitmaps) 
     2278 
     2279 
     2280    def encode(self, strio, compDict = None): 
     2281        Record_NSEC3PARAM.encode(self, strio, compDict) 
     2282        self.nxt_hash_owner_name.encode(strio, None) 
     2283        self.type_bitmaps.encode(strio, None) 
     2284 
     2285 
     2286    def decode(self, strio, length=None): 
     2287        start = strio.tell() 
     2288        Record_NSEC3PARAM.decode(self, strio, compDict) 
     2289        self.nxt_hash_owner_name.decode(strio) 
     2290        here = strio.tell() 
     2291        self.type_bitmaps.decode(strio, length + start - here if length 
     2292                                 else None) 
     2293 
     2294 
     2295    def __hash__(self): 
     2296        return hash((self.hash_algo, self.flags, self.iterations, self.salt, 
     2297                     self.nxt_hash_owner_name, self.type_bitmaps)) 
     2298 
     2299 
     2300 
    14732301# This is a fallback record 
    14742302class UnknownRecord(tputil.FancyEqMixin, tputil.FancyStrMixin, object): 
    14752303    """ 
     
    14902318    compareAttributes = ('data', 'ttl') 
    14912319    showAttributes = ('data', 'ttl') 
    14922320 
     2321 
    14932322    def __init__(self, data='', ttl=None): 
    14942323        self.data = data 
    14952324        self.ttl = str2time(ttl) 
     
    15462375    queries = answers = add = ns = None 
    15472376 
    15482377    def __init__(self, id=0, answer=0, opCode=0, recDes=0, recAv=0, 
    1549                        auth=0, rCode=OK, trunc=0, maxSize=512): 
     2378                 auth=0, rCode=OK, trunc=0, maxSize=512, authData=0, chkDis=0): 
    15502379        self.maxSize = maxSize 
    15512380        self.id = id 
    15522381        self.answer = answer 
    15532382        self.opCode = opCode 
    1554         self.auth = auth 
    1555         self.trunc = trunc 
    1556         self.recDes = recDes 
    1557         self.recAv = recAv 
     2383        self.auth = auth            #AA - Authoritative Answer 
     2384        self.trunc = trunc          #TC - TrunCated 
     2385        self.recDes = recDes        #RD - Recursion Desired 
     2386        self.recAv = recAv          #RA - Recursion Available 
     2387        self.authData = authData    #AD - Authentic Data 
     2388        self.chkDis = chkDis        #CD - Checking Disabled 
    15582389        self.rCode = rCode 
    15592390        self.queries = [] 
    15602391        self.answers = [] 
     
    15942425        if self.maxSize and size > self.maxSize: 
    15952426            self.trunc = 1 
    15962427            body = body[:self.maxSize - self.headerSize] 
    1597         byte3 = (( ( self.answer & 1 ) << 7 ) 
    1598                  | ((self.opCode & 0xf ) << 3 ) 
    1599                  | ((self.auth & 1 ) << 2 ) 
    1600                  | ((self.trunc & 1 ) << 1 ) 
    1601                  | ( self.recDes & 1 ) ) 
    1602         byte4 = ( ( (self.recAv & 1 ) << 7 ) 
    1603                   | (self.rCode & 0xf ) ) 
     2428        byte3 = (((self.answer & 1) << 7) 
     2429                 | ((self.opCode & 0xf) << 3) 
     2430                 | ((self.auth & 1 ) << 2) 
     2431                 | ((self.trunc & 1 ) << 1) 
     2432                 | (self.recDes & 1)) 
     2433        byte4 = (((self.recAv & 1) << 7) 
     2434                 | ((self.authData & 1) << 5) 
     2435                 | ((self.chkDis & 1) << 4) 
     2436                 | (self.rCode & 0xf)) 
    16042437 
    16052438        strio.write(struct.pack(self.headerFmt, self.id, byte3, byte4, 
    16062439                                len(self.queries), len(self.answers), 
     
    16132446        header = readPrecisely(strio, self.headerSize) 
    16142447        r = struct.unpack(self.headerFmt, header) 
    16152448        self.id, byte3, byte4, nqueries, nans, nns, nadd = r 
    1616         self.answer = ( byte3 >> 7 ) & 1 
    1617         self.opCode = ( byte3 >> 3 ) & 0xf 
    1618         self.auth = ( byte3 >> 2 ) & 1 
    1619         self.trunc = ( byte3 >> 1 ) & 1 
     2449        self.answer = (byte3 >> 7) & 1 
     2450        self.opCode = (byte3 >> 3) & 0xf 
     2451        self.auth = (byte3 >> 2) & 1 
     2452        self.trunc = (byte3 >> 1) & 1 
    16202453        self.recDes = byte3 & 1 
    1621         self.recAv = ( byte4 >> 7 ) & 1 
     2454        self.recAv = (byte4 >> 7) & 1 
     2455        self.authData = (byte4 >> 5) & 1 
     2456        self.chkDis = (byte4 >> 4) & 1 
    16222457        self.rCode = byte4 & 0xf 
    16232458 
    16242459        self.queries = [] 
     
    16302465                return 
    16312466            self.queries.append(q) 
    16322467 
    1633         items = ((self.answers, nans), (self.authority, nns), (self.additional, nadd)) 
     2468        items = ((self.answers, nans), 
     2469                 (self.authority, nns), 
     2470                 (self.additional, nadd)) 
    16342471        for (l, n) in items: 
    16352472            self.parseRecords(l, n, strio) 
    16362473 
    16372474 
    16382475    def parseRecords(self, list, num, strio): 
    16392476        for i in range(num): 
    1640             header = RRHeader(auth=self.auth) 
    16412477            try: 
    1642                 header.decode(strio) 
     2478                header = OPTHeader._headerFactory(strio, auth=self.auth) 
    16432479            except EOFError: 
    16442480                return 
    16452481            t = self.lookupRecordType(header.type) 
     
    17492585            query, or errbacked with any errors that could happen (exceptions 
    17502586            during writing of the query, timeout errors, ...). 
    17512587        """ 
    1752         m = Message(id, recDes=1) 
     2588        dnssecConfig = self.controller.dnssecConfig 
     2589        chkDis = dnssecConfig.chkDis 
     2590        m = Message(id, recDes=dnssecConfig.recDes, chkDis=chkDis) 
    17532591        m.queries = queries 
     2592        if dnssecConfig.ednsEnabled: 
     2593            m.additional = [Record_OPT(payload_size = dnssecConfig.maxUdpPktSz, 
     2594                                       version = dnssecConfig.version, 
     2595                                       dnssecOk = dnssecConfig.dnssecOk)] 
    17542596 
    17552597        try: 
    17562598            writeMessage(m) 
     
    18042646        self.transport.write(message.toStr(), address) 
    18052647 
    18062648    def startListening(self): 
    1807         self._reactor.listenUDP(0, self, maxPacketSize=512) 
     2649        maxPacketSize = 512 
     2650        if self.controller.dnssecConfig.ednsEnabled: 
     2651            maxPacketSize = self.controller.dnssecConfig.maxUdpPktSz 
     2652        self._reactor.listenUDP(0, self, maxPacketSize=maxPacketSize) 
    18082653 
    18092654    def datagramReceived(self, data, addr): 
    18102655        """ 
  • twisted/names/secondary.py

     
    9090 
    9191    @ivar _reactor: The reactor to use to perform the zone transfers, or C{None} 
    9292        to use the global reactor. 
     93 
     94    @ivar dnssecConfig: a L{DnssecConfig} giving the DNSSEC configuration to set 
     95        on the resolver. 
    9396    """ 
    9497 
    9598    transferring = False 
     
    97100    _port = 53 
    98101    _reactor = None 
    99102 
    100     def __init__(self, primaryIP, domain): 
    101         common.ResolverBase.__init__(self) 
     103    def __init__(self, primaryIP, domain, dnssecConfig=None): 
     104        common.ResolverBase.__init__(self, dnssecConfig) 
    102105        self.primary = primaryIP 
    103106        self.domain = domain 
    104107 
     
    164167                r.setdefault(str(rec.name).lower(), []).append(rec.payload) 
    165168 
    166169    def _ebZone(self, failure): 
    167         log.msg("Updating %s from %s failed during zone transfer" % (self.domain, self.primary)) 
     170        log.msg("Updating %s from %s failed during zone transfer" 
     171                % (self.domain, self.primary)) 
    168172        log.err(failure) 
    169173 
    170174    def update(self): 
     
    175179 
    176180    def _ebTransferred(self, failure): 
    177181        self.transferred = False 
    178         log.msg("Transferring %s from %s failed after zone transfer" % (self.domain, self.primary)) 
     182        log.msg("Transferring %s from %s failed after zone transfer" 
     183                % (self.domain, self.primary)) 
    179184        log.err(failure) 
  • twisted/names/ser_num_arith.py

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

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

     
    88 
    99from cStringIO import StringIO 
    1010 
     11import re 
    1112import struct 
    1213 
    1314from twisted.python.failure import Failure 
    1415from twisted.internet import address, task 
    1516from twisted.internet.error import CannotListenError, ConnectionDone 
    1617from twisted.trial import unittest 
    17 from twisted.names import dns 
     18from twisted.names import dns, common 
    1819 
    1920from twisted.test import proto_helpers 
    2021 
     
    2526    dns.Record_WKS, dns.Record_SRV, dns.Record_AFSDB, dns.Record_RP, 
    2627    dns.Record_HINFO, dns.Record_MINFO, dns.Record_MX, dns.Record_TXT, 
    2728    dns.Record_AAAA, dns.Record_A6, dns.Record_NAPTR, dns.UnknownRecord, 
     29    dns.Record_OPT, dns.Record_RRSIG, dns.Record_DS, dns.Record_DNSKEY, 
     30    dns.Record_NSEC, dns.Record_NSEC3PARAM, dns.Record_NSEC3, 
    2831    ] 
    2932 
    3033class NameTests(unittest.TestCase): 
     
    189192    """Encoding and then decoding various objects.""" 
    190193 
    191194    names = ["example.org", "go-away.fish.tv", "23strikesback.net"] 
     195    sigs = ["Qm12VZVaZgKS0/DZx35SGECDwPiTTf3ngChb7OkgSv5iupVmJGhPWudm " 
     196            "/18qBSXKyv9hxMlEXFFgpBieNqLfSBkP1bwKnlqPfr1Hx7ctDwDUpkT3 " 
     197            "cS8u/ms9yo3Fu1ybpO4Hfsb1HbA2N3zzQnjWKnyk26AAQSz8KgjNTFzD " 
     198            "tJM=", 
     199            "ZH2kahMD1g2WOieIotAcBwB0e/o30Zq6YR//M/xwP1ktkYuclmcR56iv " 
     200            "XiR3QFWqmN5Xz3YpgmM4tZkjIeSMp2doYa7XYORZ7OpzG7oyfo8IoXxc " 
     201            "j1VGDeAn1CeNCpBtoSGapRABG1gjY7oeRj/smPQPp2Gkf79+WZfuzRom " 
     202            "/t4=", 
     203            "AZpaboyNQAmbnBO1K66QmZ0c+VCdY/wu9QpEdRnMpnIOLPD28pNVu6hk " 
     204            "GQMz6eg5WYkPYDdJK+1D/oyAQkDmRgn10+O9EdeFDyLqYqq/htEAvDm4 " 
     205            "CziMSOpD/mkg1bSWCZ2mdln/GBk8WooCeeM7LEHmRjmHMMj0xb6N4SKa " 
     206            "MEc=", 
     207            "AwEAAbi5VQa3x+R3WQouBDNts+ZX2zIKZNoj9pzl7ew446kI/2omv3j6 " 
     208            "c/4RQ6VneYE3mK7r0fFIKhVagmiRroFO1rRUJ8sVidssZ35CldE0sju+ " 
     209            "E7wymVg3tV+ZUUO/+5v6Sfj+tw3rlp6eKqm7EGKKM88t+KuXiGYMu0Vw " 
     210            "Rm9OUO1n", 
     211            "AwEAAbmTL+kuV45kAxGN//iBKz93Y6lutgxoptp+I1+PZZMsBkhm/dZj " 
     212            "q57040Pz/Hr3f2zQX7z6fFu7/Ml3MHPH1eQDiVXDvOkeNq2x4IbCO7x+ " 
     213            "0p6bGYj4fw/tEfh/8dUzyzvMwfuAMsOvXza8Kh+UP4jvFc95cUuGgYus " 
     214            "uEjUOp40PsL7EtYvAks3UssA6/OZP4w/1Z5m/VFx4PzgY0dkEuc=", 
     215            "VGPxa8A81eV1dtUxVhz9b9Jsp6FF4M5H6J0QhzbNCUTHTHjLNR2VHYfE " 
     216            "fM+Akwo3/qKq3D6vzTfzqtyPAXP8CmGfdD8hfv0s7Hae9c7Is8usdlrk " 
     217            "ZpoXEFMW+YVG8G9OieYViq6tBIpUvKgMVZ+oXKo63KJ/tC/yBW0H0VQP " 
     218            "YwdzZ3ZvYRDmZDvrXoX7T0YNU+0HYHnb7g7nUECIJ/4HHg==", 
     219            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K+oeC7Y81HIOFE " 
     220            "h9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffp " 
     221            "Z9pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55 " 
     222            "Y1k="] 
     223    type_bitmaps = ["A MX RRSIG NSEC TYPE1234", 
     224                    "AAAA NS CNAME MX TXT RRSIG NSEC3 DNAME", 
     225                    "NSEC3 A AAAA RRSIG DS NS " 
     226                    "TYPE5000 TYPE1000 TYPE2000 TYPE3000 TYPE4000", 
     227                    None] 
    192228 
    193229    def testName(self): 
    194230        for n in self.names: 
     
    276312            self.assertEqual(result.string, n) 
    277313 
    278314 
     315    def test_Sigstr(self): 
     316        """ 
     317        Test L{dns.Sigstr} encode and decode. 
     318        """ 
     319        for s in self.sigs: 
     320            # encode the signature/key 
     321            f = StringIO() 
     322            dns.Sigstr(s).encode(f) 
     323            l = f.tell() 
     324 
     325            # decode the signature/key 
     326            f.seek(0, 0) 
     327            result = dns.Sigstr() 
     328            result.decode(f,l) 
     329            #spaces are free, and dig sticks them in 
     330            self.assertEqual(result.string, s.replace(' ', '')) 
     331 
     332 
     333    def test_TypeBitmaps(self): 
     334        """ 
     335        Test L{dns.TypeBitmaps} encode and decode. 
     336        """ 
     337        typeRegex = re.compile('TYPE(\d+)') 
     338 
     339        for b in self.type_bitmaps: 
     340            # encode the type_bitmaps 
     341            f = StringIO() 
     342            dns.TypeBitmaps(b).encode(f) 
     343            l = f.tell() 
     344 
     345            # decode the type_bitmaps 
     346            f.seek(0, 0) 
     347            result = dns.TypeBitmaps() 
     348            result.decode(f,l) 
     349 
     350            def mnuVal(mnu): 
     351                mnuVal = dns.REV_TYPES.get(mnu, None) 
     352                if not mnuVal: 
     353                    m = typeRegex.match(mnu) 
     354                    if m.groups(): 
     355                        mnuVal = int(m.group(1)) 
     356                        assert mnuVal < 65536 
     357                    else: 
     358                        log.err("can't parse %s in %s" % (mnu, self.string, )) 
     359                        mnuVal = 0 
     360                return mnuVal 
     361 
     362            def sorttok(string): 
     363                if not string: 
     364                    return '' 
     365 
     366                toks = string.split(' ') 
     367                toks.sort(key = mnuVal) 
     368                return ' '.join(toks) 
     369 
     370            self.assertEqual(result.type_bitmaps, sorttok(b)) 
     371 
     372 
    279373    def test_NAPTR(self): 
    280374        """ 
    281375        Test L{dns.Record_NAPTR} encode and decode. 
     
    325419        msg = dns.Message() 
    326420        msg.fromStr( 
    327421            '\x01\x00' # Message ID 
    328             '\x00' # answer bit, opCode nibble, auth bit, trunc bit, recursive bit 
    329             '\x00' # recursion bit, empty bit, empty bit, empty bit, response code nibble 
     422            '\x00' # answer bit, opCode nibble, auth, trunc, recursive bits 
     423            '\x00' # recursion bit, 3 empty bits, response code nibble 
    330424            '\x00\x00' # number of queries 
    331425            '\x00\x00' # number of answers 
    332426            '\x00\x00' # number of authorities 
     
    439533        Initialize the controller: create a list of messages. 
    440534        """ 
    441535        self.messages = [] 
     536        self.dnssecConfig = common.DnssecConfig() 
    442537 
    443538 
    444539    def messageReceived(self, msg, proto, addr): 
     
    893988            repr(dns.UnknownRecord("foo\x1fbar", 12)), 
    894989            "<UNKNOWN data='foo\\x1fbar' ttl=12>") 
    895990 
     991    def test_dnskey(self): 
     992        """ 
     993        The repr of a L{dns.DNSKEY} instance includes the flags, protocol, 
     994        algo, pub_key and ttl fields of the record. 
     995        """ 
     996        self.assertEqual( 
     997            repr(dns.Record_DNSKEY(10, 20, 30, "foo\x1fbar", ttl=20)), 
     998            "<DNSKEY flags=10 protocol=20 algo=30 pub_key=foo\x1fbar ttl=20>") 
    896999 
     1000    def test_ds(self): 
     1001        """ 
     1002        The repr of a L{dns.DS} instance includes the key_tag, algo, digest_type, 
     1003        digest and ttl fields of the record. 
     1004        """ 
     1005        self.assertEqual( 
     1006            repr(dns.Record_DS(11, 22, 33, "foo\x1fbar1", ttl=21)), 
     1007            "<DS key_tag=11 algo=22 digest_type=33 digest=foo\x1fbar1 ttl=21>") 
    8971008 
     1009    def test_nsec(self): 
     1010        """ 
     1011        The repr of a L{dns.NSEC} instance includes the nxt_name, type_bitmaps 
     1012        and ttl fields of the record. 
     1013        """ 
     1014        self.assertEqual( 
     1015            repr(dns.Record_NSEC('bob', "\x1fabcd", ttl=31)), 
     1016            "<NSEC nxt_name=bob type_bitmaps=\x1fabcd ttl=31>") 
     1017 
     1018    def test_nsec3param(self): 
     1019        """ 
     1020        The repr of a L{dns.NSEC3PARAM} instance includes the hash_algo, flags, 
     1021        iterations, salt and ttl fields of the record. 
     1022        """ 
     1023        self.assertEqual( 
     1024            repr(dns.Record_NSEC3PARAM(1, 2, 3, '\x12\x34', ttl=31)), 
     1025            "<NSEC3 hash_algo=1 flags=2 iterations=3 salt=\x12\x34 ttl=31>") 
     1026 
     1027    def test_nsec3(self): 
     1028        """ 
     1029        The repr of a L{dns.NSEC3} instance includes the hash_algo, flags, 
     1030        iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl fields 
     1031        of the record. 
     1032        """ 
     1033        self.assertEqual( 
     1034            repr(dns.Record_NSEC3(1, 2, 3, '\x12\x34', 'bob', 
     1035                                  "\x1fabcd", ttl=31)), 
     1036            "<NSEC3 hash_algo=1 flags=2 iterations=3 " 
     1037            "salt=\x12\x34 nxt_hash_owner_name=bob " 
     1038            "type_bitmaps=\x1fabcd ttl=31>") 
     1039 
     1040    def test_opt(self): 
     1041        """ 
     1042        The repr of a L{dns.OPT} instance includes the payload_size, dnssecOk 
     1043        flag, and version fields of the record. 
     1044        (The OPT record has no ttl field.) 
     1045        """ 
     1046        self.assertEqual( 
     1047            repr(dns.Record_OPT(payload_size=1492, dnssecOk=1, version=0)), 
     1048                 "<OPT payload_size=1492 flags=0x8000 version=0>") 
     1049 
     1050    def test_rrsig(self): 
     1051        """ 
     1052        The repr of a L{dns.RRSIG} instance includes the algo, labels, 
     1053        original_ttl sig_expiration, sig_inception, key_tag, signers_name, 
     1054        signature and ttl fields of the record. 
     1055        """ 
     1056        self.assertEqual( 
     1057            repr(dns.Record_RRSIG(type_covered=dns.A, 
     1058                                  algo=2, 
     1059                                  labels=3, 
     1060                                  original_ttl=30, 
     1061                                  sig_expiration='20110101123456', 
     1062                                  sig_inception= '20110202112233', 
     1063                                  key_tag=60, 
     1064                                  signers_name='bob', 
     1065                                  signature='\x12\x34sig', 
     1066                                  ttl=70)), 
     1067        "<RRSIG type_covered=1 algo=2 labels=3 original_ttl=30" 
     1068        " sig_expiration=20110101123456 sig_inception=20110202112233 key_tag=60" 
     1069        " signers_name=bob signature=\x12\x34sig ttl=70>") 
     1070 
    8981071class _Equal(object): 
    8991072    """ 
    9001073    A class the instances of which are equal to anything and everything. 
     
    9611134            cls('example.com', 123), 
    9621135            cls('example.org', 123)) 
    9631136 
     1137    def test_optheader(self): 
     1138        """ 
     1139        Two OptHeader instances comapare equal iff the have the same 
     1140        (Record_OPT) payload and auth bit. 
     1141        """ 
     1142        self._equalityTest( 
     1143            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, 
     1144                                                 dnssecOk=True, 
     1145                                                 version=0, 
     1146                                                 ttl=30)), 
     1147            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1024, 
     1148                                                 dnssecOk=True, 
     1149                                                 version=0, 
     1150                                                 ttl=30)), 
     1151            dns.OPTHeader(payload=dns.Record_OPT(payload_size=1492, 
     1152                                                 dnssecOk=False, 
     1153                                                 version=0, 
     1154                                                 ttl=40), auth=True)) 
    9641155 
    9651156    def test_rrheader(self): 
    9661157        """ 
     
    9681159        the same name, type, class, time to live, payload, and authoritative 
    9691160        bit. 
    9701161        """ 
     1162        aRec = dns.Record_A('1.2.3.4') 
     1163 
    9711164        # Vary the name 
    9721165        self._equalityTest( 
    973             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
    974             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
    975             dns.RRHeader('example.org', payload=dns.Record_A('1.2.3.4'))) 
     1166            dns.RRHeader('example.com', payload=aRec), 
     1167            dns.RRHeader('example.com', payload=aRec), 
     1168            dns.RRHeader('example.org', payload=aRec)) 
    9761169 
    9771170        # Vary the payload 
    9781171        self._equalityTest( 
    979             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
    980             dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.4')), 
     1172            dns.RRHeader('example.com', payload=aRec), 
     1173            dns.RRHeader('example.com', payload=aRec), 
    9811174            dns.RRHeader('example.com', payload=dns.Record_A('1.2.3.5'))) 
    9821175 
    9831176        # Vary the type.  Leave the payload as None so that we don't have to 
     
    9891182 
    9901183        # Probably not likely to come up.  Most people use the internet. 
    9911184        self._equalityTest( 
    992             dns.RRHeader('example.com', cls=dns.IN, payload=dns.Record_A('1.2.3.4')), 
    993             dns.RRHeader('example.com', cls=dns.IN, payload=dns.Record_A('1.2.3.4')), 
    994             dns.RRHeader('example.com', cls=dns.CS, payload=dns.Record_A('1.2.3.4'))) 
     1185            dns.RRHeader('example.com', cls=dns.IN, payload=aRec), 
     1186            dns.RRHeader('example.com', cls=dns.IN, payload=aRec), 
     1187            dns.RRHeader('example.com', cls=dns.CS, payload=aRec)) 
    9951188 
    9961189        # Vary the ttl 
    9971190        self._equalityTest( 
    998             dns.RRHeader('example.com', ttl=60, payload=dns.Record_A('1.2.3.4')), 
    999             dns.RRHeader('example.com', ttl=60, payload=dns.Record_A('1.2.3.4')), 
    1000             dns.RRHeader('example.com', ttl=120, payload=dns.Record_A('1.2.3.4'))) 
     1191            dns.RRHeader('example.com', ttl=60, payload=aRec), 
     1192            dns.RRHeader('example.com', ttl=60, payload=aRec), 
     1193            dns.RRHeader('example.com', ttl=120, payload=aRec)) 
    10011194 
    10021195        # Vary the auth bit 
    10031196        self._equalityTest( 
    1004             dns.RRHeader('example.com', auth=1, payload=dns.Record_A('1.2.3.4')), 
    1005             dns.RRHeader('example.com', auth=1, payload=dns.Record_A('1.2.3.4')), 
    1006             dns.RRHeader('example.com', auth=0, payload=dns.Record_A('1.2.3.4'))) 
     1197            dns.RRHeader('example.com', auth=1, payload=aRec), 
     1198            dns.RRHeader('example.com', auth=1, payload=aRec), 
     1199            dns.RRHeader('example.com', auth=0, payload=aRec)) 
    10071200 
    10081201 
    10091202    def test_ns(self): 
     
    14831676            dns.UnknownRecord('foo', ttl=10), 
    14841677            dns.UnknownRecord('foo', ttl=10), 
    14851678            dns.UnknownRecord('foo', ttl=100)) 
     1679 
     1680    def test_rrsig(self): 
     1681        """ 
     1682        L(dns.RRSIG) instances compare equal iff they have the same 
     1683        type_covered, algo, labels, original_ttl, sig_expiration, sig_inception, 
     1684        key_tag, signers_name, signature, and ttl 
     1685        """ 
     1686        self._equalityTest( 
     1687            dns.Record_RRSIG(type_covered=dns.A), 
     1688            dns.Record_RRSIG(type_covered=dns.A), 
     1689            dns.Record_RRSIG(type_covered=dns.AAAA)) 
     1690        self._equalityTest( 
     1691            dns.Record_RRSIG(algo=1), 
     1692            dns.Record_RRSIG(algo=1), 
     1693            dns.Record_RRSIG(algo=2)) 
     1694        self._equalityTest( 
     1695            dns.Record_RRSIG(labels=3), 
     1696            dns.Record_RRSIG(labels=3), 
     1697            dns.Record_RRSIG(labels=4)) 
     1698        self._equalityTest( 
     1699            dns.Record_RRSIG(original_ttl=5), 
     1700            dns.Record_RRSIG(original_ttl=5), 
     1701            dns.Record_RRSIG(original_ttl=6)) 
     1702        self._equalityTest( 
     1703            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1704            dns.Record_RRSIG(sig_expiration='20110101000000'), 
     1705            dns.Record_RRSIG(sig_expiration='20110101000001')) 
     1706        self._equalityTest( 
     1707            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1708            dns.Record_RRSIG(sig_inception='20120101000000'), 
     1709            dns.Record_RRSIG(sig_inception='20120101000001')) 
     1710        self._equalityTest( 
     1711            dns.Record_RRSIG(key_tag=11), 
     1712            dns.Record_RRSIG(key_tag=11), 
     1713            dns.Record_RRSIG(key_tag=12)) 
     1714        self._equalityTest( 
     1715            dns.Record_RRSIG(signers_name='bob'), 
     1716            dns.Record_RRSIG(signers_name='bob'), 
     1717            dns.Record_RRSIG(signers_name='joe')) 
     1718        self._equalityTest( 
     1719            dns.Record_RRSIG(signature='abcdef'), 
     1720            dns.Record_RRSIG(signature='abcdef'), 
     1721            dns.Record_RRSIG(signature='abcdefg')) 
     1722        self._equalityTest( 
     1723            dns.Record_RRSIG(ttl=10), 
     1724            dns.Record_RRSIG(ttl=10), 
     1725            dns.Record_RRSIG(ttl=20)) 
     1726 
     1727    def test_ds(self): 
     1728        """ 
     1729        L(dns.DS) instances compare equal iff they have the same 
     1730        key_tag, algo, digest_type, digest and ttl 
     1731        """ 
     1732        self._equalityTest( 
     1733            dns.Record_DS(key_tag=1), 
     1734            dns.Record_DS(key_tag=1), 
     1735            dns.Record_DS(key_tag=2)) 
     1736        self._equalityTest( 
     1737            dns.Record_DS(algo=3), 
     1738            dns.Record_DS(algo=3), 
     1739            dns.Record_DS(algo=4)) 
     1740        self._equalityTest( 
     1741            dns.Record_DS(digest_type=5), 
     1742            dns.Record_DS(digest_type=5), 
     1743            dns.Record_DS(digest_type=6)) 
     1744        self._equalityTest( 
     1745            dns.Record_DS(digest='abcdef-digest'), 
     1746            dns.Record_DS(digest='abcdef-digest'), 
     1747            dns.Record_DS(digest='abcdef-digest-f')) 
     1748        self._equalityTest( 
     1749            dns.Record_DS(ttl=10), 
     1750            dns.Record_DS(ttl=10), 
     1751            dns.Record_DS(ttl=20)) 
     1752 
     1753    def test_dnskey(self): 
     1754        """ 
     1755        L(dns.DNSKEY) instances compare equal iff they have the same 
     1756        flags, protocol, algo, pub_key and ttl 
     1757        """ 
     1758        self._equalityTest( 
     1759            dns.Record_DNSKEY(flags=1), 
     1760            dns.Record_DNSKEY(flags=1), 
     1761            dns.Record_DNSKEY(flags=2)) 
     1762        self._equalityTest( 
     1763            dns.Record_DNSKEY(protocol=3), 
     1764            dns.Record_DNSKEY(protocol=3), 
     1765            dns.Record_DNSKEY(protocol=4)) 
     1766        self._equalityTest( 
     1767            dns.Record_DNSKEY(algo=5), 
     1768            dns.Record_DNSKEY(algo=5), 
     1769            dns.Record_DNSKEY(algo=6)) 
     1770        self._equalityTest( 
     1771            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1772            dns.Record_DNSKEY(pub_key='abcdef-digest'), 
     1773            dns.Record_DNSKEY(pub_key='abcdef-digest-f')) 
     1774        self._equalityTest( 
     1775            dns.Record_DNSKEY(ttl=10), 
     1776            dns.Record_DNSKEY(ttl=10), 
     1777            dns.Record_DNSKEY(ttl=20)) 
     1778 
     1779    def test_nsec(self): 
     1780        """ 
     1781        L(dns.DNSKEY) instances compare equal iff they have the same 
     1782        nxt_name, type_bitmaps and ttl 
     1783        """ 
     1784        self._equalityTest( 
     1785            dns.Record_NSEC(nxt_name="example.com"), 
     1786            dns.Record_NSEC(nxt_name="example.com"), 
     1787            dns.Record_NSEC(nxt_name="a.example.com")) 
     1788        self._equalityTest( 
     1789            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1790            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3"), 
     1791            dns.Record_NSEC(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1792        self._equalityTest( 
     1793            dns.Record_NSEC(ttl=5), 
     1794            dns.Record_NSEC(ttl=5), 
     1795            dns.Record_NSEC(ttl=6)) 
     1796 
     1797    def test_nsec3param(self): 
     1798        """ 
     1799        L(dns.DNSKEY) instances compare equal iff they have the same 
     1800        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps and ttl 
     1801        """ 
     1802        self._equalityTest( 
     1803            dns.Record_NSEC3PARAM(hash_algo=1), 
     1804            dns.Record_NSEC3PARAM(hash_algo=1), 
     1805            dns.Record_NSEC3PARAM(hash_algo=2)) 
     1806        self._equalityTest( 
     1807            dns.Record_NSEC3PARAM(flags=1), 
     1808            dns.Record_NSEC3PARAM(flags=1), 
     1809            dns.Record_NSEC3PARAM(flags=2)) 
     1810        self._equalityTest( 
     1811            dns.Record_NSEC3PARAM(iterations=5), 
     1812            dns.Record_NSEC3PARAM(iterations=5), 
     1813            dns.Record_NSEC3PARAM(iterations=6)) 
     1814        self._equalityTest( 
     1815            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1816            dns.Record_NSEC3PARAM(salt="abcdef"), 
     1817            dns.Record_NSEC3PARAM(salt="abcdefg")) 
     1818        self._equalityTest( 
     1819            dns.Record_NSEC3PARAM(ttl=5), 
     1820            dns.Record_NSEC3PARAM(ttl=5), 
     1821            dns.Record_NSEC3PARAM(ttl=6)) 
     1822 
     1823    def test_nsec3(self): 
     1824        """ 
     1825        L(dns.DNSKEY) instances compare equal iff they have the same 
     1826        hash_algo, flags, iterations, salt, nxt_hash_owner_name, type_bitmaps 
     1827        and ttl 
     1828        """ 
     1829        self._equalityTest( 
     1830            dns.Record_NSEC3(hash_algo=1), 
     1831            dns.Record_NSEC3(hash_algo=1), 
     1832            dns.Record_NSEC3(hash_algo=2)) 
     1833        self._equalityTest( 
     1834            dns.Record_NSEC3(flags=1), 
     1835            dns.Record_NSEC3(flags=1), 
     1836            dns.Record_NSEC3(flags=2)) 
     1837        self._equalityTest( 
     1838            dns.Record_NSEC3(iterations=5), 
     1839            dns.Record_NSEC3(iterations=5), 
     1840            dns.Record_NSEC3(iterations=6)) 
     1841        self._equalityTest( 
     1842            dns.Record_NSEC3(salt="abcdef"), 
     1843            dns.Record_NSEC3(salt="abcdef"), 
     1844            dns.Record_NSEC3(salt="abcdefg")) 
     1845        self._equalityTest( 
     1846            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1847            dns.Record_NSEC3(nxt_hash_owner="example.com"), 
     1848            dns.Record_NSEC3(nxt_hash_owner="a.example.com")) 
     1849        self._equalityTest( 
     1850            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1851            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3"), 
     1852            dns.Record_NSEC3(type_bitmaps="A AAAA NS NSEC3 RRSIG")) 
     1853        self._equalityTest( 
     1854            dns.Record_NSEC3(ttl=5), 
     1855            dns.Record_NSEC3(ttl=5), 
     1856            dns.Record_NSEC3(ttl=6)) 
     1857 
     1858 
  • twisted/names/test/test_names.py

     
    9898                           '\x12\x01\x16\xfe\xc1\x00\x01'), 
    9999            dns.Record_NAPTR(100, 10, "u", "sip+E2U", 
    100100                             "!^.*$!sip:information@domain.tld!"), 
    101             dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF')], 
     101            dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF'), 
     102            dns.Record_DNSKEY(0x10, 3, 5, 
     103                              "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T" 
     104                              "/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q" 
     105                              "845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBT" 
     106                              "AvdTboGmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8" 
     107                              "LJ55Y1k=" 
     108                             )], 
    102109        'http.tcp.test-domain.com': [ 
    103110            dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool') 
    104111        ], 
    105112        'host.test-domain.com': [ 
    106113            dns.Record_A('123.242.1.5'), 
    107114            dns.Record_A('0.255.0.255'), 
     115            dns.Record_RRSIG(dns.A, 5, 3, 86400, 
     116                             '20120101000000', '20120201000000', 
     117                             2642, 'test-domain.com', 
     118                            "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9H4T/K" 
     119                            "+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5Z/+0/Q845K" 
     120                            "ya8Lmkp/ikJVe/9id2TC2hoffpZ9pbZRjIeBTAvdTbo" 
     121                            "GmGuqG/ljnDLJrJpoF6g8g6fHR9eekIWis8LJ55Y1k=") 
    108122        ], 
    109123        'host-two.test-domain.com': [ 
    110124# 
     
    224238        """Test DNS 'A' record queries with multiple answers""" 
    225239        return self.namesTest( 
    226240            self.resolver.lookupAddress('host.test-domain.com'), 
    227             [dns.Record_A('123.242.1.5', ttl=19283784), dns.Record_A('0.255.0.255', ttl=19283784)] 
     241            [dns.Record_A('123.242.1.5', ttl=19283784), 
     242             dns.Record_A('0.255.0.255', ttl=19283784)] 
    228243        ) 
    229244 
    230245 
     
    232247        """Test DNS 'A' record queries with edge cases""" 
    233248        return self.namesTest( 
    234249            self.resolver.lookupAddress('host-two.test-domain.com'), 
    235             [dns.Record_A('255.255.255.254', ttl=19283784), dns.Record_A('0.0.0.0', ttl=19283784)] 
     250            [dns.Record_A('255.255.255.254', ttl=19283784), 
     251             dns.Record_A('0.0.0.0', ttl=19283784)] 
    236252        ) 
    237253 
    238254 
     
    264280        """Test DNS 'HINFO' record queries""" 
    265281        return self.namesTest( 
    266282            self.resolver.lookupHostInfo('test-domain.com'), 
    267             [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', ttl=19283784)] 
     283            [dns.Record_HINFO(os='Linux', cpu='A Fast One, Dontcha know', 
     284                              ttl=19283784)] 
    268285        ) 
    269286 
    270287    def testPTR(self): 
     
    286303        """Test additional processing for CNAME records""" 
    287304        return self.namesTest( 
    288305        self.resolver.lookupAddress('cname.test-domain.com'), 
    289         [dns.Record_CNAME('test-domain.com', ttl=19283784), dns.Record_A('127.0.0.1', ttl=19283784)] 
     306        [dns.Record_CNAME('test-domain.com', ttl=19283784), 
     307         dns.Record_A('127.0.0.1', ttl=19283784)] 
    290308    ) 
    291309 
    292310    def testMB(self): 
     
    317335        """Test DNS 'MINFO' record queries""" 
    318336        return self.namesTest( 
    319337            self.resolver.lookupMailboxInfo('test-domain.com'), 
    320             [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', ttl=19283784)] 
     338            [dns.Record_MINFO(rmailbx='r mail box', emailbx='e mail box', 
     339                              ttl=19283784)] 
    321340        ) 
    322341 
    323342 
     
    325344        """Test DNS 'SRV' record queries""" 
    326345        return self.namesTest( 
    327346            self.resolver.lookupService('http.tcp.test-domain.com'), 
    328             [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl=19283784)] 
     347            [dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', 
     348                            ttl=19283784)] 
    329349        ) 
    330350 
    331351    def testAFSDB(self): 
    332352        """Test DNS 'AFSDB' record queries""" 
    333353        return self.namesTest( 
    334354            self.resolver.lookupAFSDatabase('test-domain.com'), 
    335             [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', ttl=19283784)] 
     355            [dns.Record_AFSDB(subtype=1, hostname='afsdb.test-domain.com', 
     356                              ttl=19283784)] 
    336357        ) 
    337358 
    338359 
     
    340361        """Test DNS 'RP' record queries""" 
    341362        return self.namesTest( 
    342363            self.resolver.lookupResponsibility('test-domain.com'), 
    343             [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', ttl=19283784)] 
     364            [dns.Record_RP(mbox='whatever.i.dunno', txt='some.more.text', 
     365                           ttl=19283784)] 
    344366        ) 
    345367 
    346368 
     
    348370        """Test DNS 'TXT' record queries""" 
    349371        return self.namesTest( 
    350372            self.resolver.lookupText('test-domain.com'), 
    351             [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', ttl=19283784), 
    352              dns.Record_TXT('Some more text, haha!  Yes.  \0  Still here?', ttl=19283784)] 
     373            [dns.Record_TXT('A First piece of Text', 'a SecoNd piece', 
     374                            ttl=19283784), 
     375             dns.Record_TXT('Some more text, haha!  Yes.  \0  Still here?', 
     376                            ttl=19283784)] 
    353377        ) 
    354378 
    355379 
     
    359383        """ 
    360384        return self.namesTest( 
    361385            self.resolver.lookupSenderPolicy('test-domain.com'), 
    362             [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all', ttl=19283784), 
    363             dns.Record_SPF('v=spf1 +mx a:\0colo', '.example.com/28 -all not valid', ttl=19283784)] 
     386            [dns.Record_SPF('v=spf1 mx/30 mx:example.org/30 -all', 
     387                            ttl=19283784), 
     388            dns.Record_SPF('v=spf1 +mx a:\0colo', 
     389                           '.example.com/28 -all not valid', 
     390                           ttl=19283784)] 
    364391        ) 
    365392 
    366393 
     
    368395        """Test DNS 'WKS' record queries""" 
    369396        return self.namesTest( 
    370397            self.resolver.lookupWellKnownServices('test-domain.com'), 
    371             [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] 
     398            [dns.Record_WKS('12.54.78.12', socket.IPPROTO_TCP, 
     399                            '\x12\x01\x16\xfe\xc1\x00\x01', ttl=19283784)] 
    372400        ) 
    373401 
    374402 
     
    381409             dns.Record_A('1.2.3.4', ttl='1S'), 
    382410             dns.Record_NS('ns1.domain', ttl='2M'), 
    383411             dns.Record_NS('ns2.domain', ttl='3H'), 
    384              dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', ttl='4D')] 
     412             dns.Record_SRV(257, 16383, 43690, 'some.other.place.fool', 
     413                            ttl='4D')] 
    385414            ) 
    386415 
    387416 
     
    389418        """Test DNS 'AAAA' record queries (IPv6)""" 
    390419        return self.namesTest( 
    391420            self.resolver.lookupIPV6Address('test-domain.com'), 
    392             [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', ttl=19283784)] 
     421            [dns.Record_AAAA('AF43:5634:1294:AFCB:56AC:48EF:34C3:01FF', 
     422                             ttl=19283784)] 
    393423        ) 
    394424 
    395425    def testA6(self): 
     
    398428            self.resolver.lookupAddress6('test-domain.com'), 
    399429            [dns.Record_A6(0, 'ABCD::4321', '', ttl=19283784), 
    400430             dns.Record_A6(12, '0:0069::0', 'some.network.tld', ttl=19283784), 
    401              dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 'tra.la.la.net', ttl=19283784)] 
     431             dns.Record_A6(8, '0:5634:1294:AFCB:56AC:48EF:34C3:01FF', 
     432                           'tra.la.la.net', ttl=19283784)] 
    402433         ) 
    403434 
    404435 
     
    407438        Test DNS 'AXFR' queries (Zone transfer) 
    408439        """ 
    409440        default_ttl = soa_record.expire 
    410         results = [copy.copy(r) for r in reduce(operator.add, test_domain_com.records.values())] 
     441        results = [copy.copy(r) 
     442                   for r in reduce(operator.add, 
     443                                   test_domain_com.records.values())] 
    411444        for r in results: 
    412445            if r.ttl is None: 
    413446                r.ttl = default_ttl 
     
    435468                              "!^.*$!sip:information@domain.tld!", 
    436469                              ttl=19283784)]) 
    437470 
     471    def test_DNSKEY(self): 
     472        """Test DNS 'DNSKEY' record queries.""" 
     473        return self.namesTest( 
     474            self.resolver.lookupDNSKey('test-domain.com'), 
     475            [dns.Record_DNSKEY(0x10, 3, 5, 
     476                               "M+u8Uxm2y2Q142qED0kVNIiSOHBkfiU3xBhMq9" 
     477                               "H4T/K+oeC7Y81HIOFEh9k6ZS/Ba5X0/Fr1yyq5" 
     478                               "Z/+0/Q845Kya8Lmkp/ikJVe/9id2TC2hoffpZ9" 
     479                               "pbZRjIeBTAvdTboGmGuqG/ljnDLJrJpoF6g8g6" 
     480                               "fHR9eekIWis8LJ55Y1k=", 
     481                               ttl=19283784)]) 
    438482 
    439  
    440483class DNSServerFactoryTests(unittest.TestCase): 
    441484    """ 
    442485    Tests for L{server.DNSServerFactory}. 
     
    523566        self.d.addCallback(self._gotResults) 
    524567        self.controller = client.AXFRController('fooby.com', self.d) 
    525568 
    526         self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, ttl=86400, auth=False, 
     569        self.soa = dns.RRHeader(name='fooby.com', type=dns.SOA, cls=dns.IN, 
     570                                ttl=86400, auth=False, 
    527571                                payload=dns.Record_SOA(mname='fooby.com', 
    528572                                                       rname='hooj.fooby.com', 
    529573                                                       serial=100, 
     
    535579 
    536580        self.records = [ 
    537581            self.soa, 
    538             dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, auth=False, 
    539                          payload=dns.Record_NS(name='ns.twistedmatrix.com', ttl=700)), 
     582            dns.RRHeader(name='fooby.com', type=dns.NS, cls=dns.IN, ttl=700, 
     583                         auth=False, 
     584                         payload=dns.Record_NS(name='ns.twistedmatrix.com', 
     585                                               ttl=700)), 
    540586 
    541             dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, auth=False, 
    542                          payload=dns.Record_MX(preference=10, exchange='mail.mv3d.com', ttl=700)), 
     587            dns.RRHeader(name='fooby.com', type=dns.MX, cls=dns.IN, ttl=700, 
     588                         auth=False, 
     589                         payload=dns.Record_MX(preference=10, 
     590                                               exchange='mail.mv3d.com', 
     591                                               ttl=700)), 
    543592 
    544             dns.RRHeader(name='fooby.com', type=dns.A, cls=dns.IN, ttl=700, auth=False, 
    545                          payload=dns.Record_A(address='64.123.27.105', ttl=700)), 
     593            dns.RRHeader(name='fooby.com', type=dns.A, cls=dns.IN, 
     594                         ttl=700, auth=False, 
     595                         payload=dns.Record_A(address='64.123.27.105', 
     596                                              ttl=700)), 
    546597            self.soa 
    547598            ] 
    548599 
    549600    def _makeMessage(self): 
    550601        # hooray they all have the same message format 
    551         return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, auth=1, rCode=0, trunc=0, maxSize=0) 
     602        return dns.Message(id=999, answer=1, opCode=0, recDes=0, recAv=1, 
     603                           auth=1, rCode=0, trunc=0, maxSize=0) 
    552604 
    553605    def testBindAndTNamesStyle(self): 
    554606        # Bind style = One big single message 
     
    890942        self.assertEqual(service.domains[1].domain, 'example.edu') 
    891943 
    892944 
    893  
    894945class SecondaryAuthorityTests(unittest.TestCase): 
    895946    """ 
    896947    L{twisted.names.secondary.SecondaryAuthority} correctly constructs objects 
  • twisted/names/test/test_ser_num_arith.py

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

     
     1Twisted Names 12.1.0 (2012-03-13) 
     2================================= 
     3 
     4Features 
     5-------- 
     6 - The main features introduced by this change are EDNS0 and support 
     7   for DNSSEC. Enabling EDNS0 adds to a query an OPT record that carries 
     8   two pieces of information. The first is the maximum size UDP packet  
     9   that the network can handle (see RFC2671.) The second is the DNSSEC  
     10   OK (DO) bit which tells an upstream resolver that the querying resolver  
     11   is able to accept DNSSEC security data (See RFC3225.) Although this 
     12   change fully implements EDNS0, it only enables twisted.names to  
     13   ask for DNSSEC data and pass that data to the user. The user may 
     14   check the Authentic Data (AD) bit in the message header to determine 
     15   if the upstream resolver validates the data. (See RFC 4035, Section  
     16   4.9.3 regarding only using the AD bit from a trusted resolver  
     17   on a secure channel.) 
     18 - Processing DNSSEC data and validating DNS answers requires doing  
     19   cryptographic processing using a library such as openssl. This may  
     20   be part of a future feature set but is not in the current feature. 
     21 - The new class twisted.names.common.DnssecConfig allows configuring 
     22   DNSSEC and EDNS0 parameters, as well as the recursion desired DNS 
     23   parameter, for a resolver. DnssecConfig is an optional input argument  
     24   to ResolverBase and is implemented for client.Resolver and  
     25   secondaryAuthority.Resolver 
     26 - ResolverBase now has new lookup methods for lookupDNSKey, lookupDS,  
     27   lookupNSEC, lookupNSEC3, lookupNSEC3Param and lookupRRSIG records. 
     28 - twisted.names.client.Resolver now returns a 4-tuple to a query when  
     29   configured with dnssecOk. The 4-tuple includes a new reference  
     30   to the message so that the caller can obtain the AD flag (and  
     31   any of the other flags) in the message. 
     32 - twisted.names.client now has new lookup methods for the six new  
     33   DNSSEC record types. 
     34 - twisted.names.dns now supports six new DNS record types - DNSKey, 
     35   DS, NSEC, NSEC3, NSEC3Param and RRSIG. 
     36 - The new twisted.names.dns.Sigstr class encodes/decodes signatures and keys. 
     37 - The new twisted.names.dns.TypeBitmaps class encodes/decoes the type bitmap 
     38   field in an NSEC3 resource record. 
     39 - The new OptHeader and Record_OPT classes support the EDNS and DNSSEC  
     40   options. 
     41 - twisted.names.dns now has new classes added for the six DNSSEC record types. 
     42 - The dns.Message class now has new AD and CD flags for AuthenticData and Checking Disabled. 
     43 - twisted.names.dns now adds the OPT record to EDNS queries. 
     44 - twisted.names.dns.Message.startListening now listens for larger UDP  
     45   packets, as set by maxUdpPktSz. 
     46 - The new twisted.names.ser_num_arith class implements DNS Serial Number 
     47   Arithmetic (SNA) and Date SNA for handling numbers and dates that 
     48   roll through a 32-bit integer. 
     49 - New tests are added for all new features. 
     50 No newline at end of file