Ticket #5454: addEdsn0AndDnssec5454V03.patch

File addEdsn0AndDnssec5454V03.patch, 101.7 KB (added by BobNovas, 5 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