Twisted Names如何为查询构建搜索结果?

时间:2012-09-16 22:33:12

标签: python dns twisted

具体来说,在authority.FileAuthority类下的_lookup调用中会发生什么,以及它如何返回结果?这是Names的未记录区域之一。

1 个答案:

答案 0 :(得分:0)

以下是Twisted Names 11.1的authority.py文件中的FileAuthority._lookup调用的注释版本。此方法负责同步搜索已从BIND区域文件,Python区域文件等编制索引的DNS信息。

def _lookup(self, name, cls, type, timeout = None):
    """Return a list of results.
    name: Queried host name.
    cls: An enum of the query class. See dns.py:

        IN, CS, CH, HS = range(1, 5)

        QUERY_CLASSES = {
            IN: 'IN',
            CS: 'CS',
            CH: 'CH',
            HS: 'HS',
            ANY: 'ANY'
        }

    type: The type of record to search for (or ANY/255 for any and all). 
          See dns.py:

        (A, NS, MD, MF, CNAME, SOA, MB, MG, MR, NULL, WKS, PTR, HINFO, MINFO, MX, TXT,
         RP, AFSDB) = range(1, 19)
        AAAA = 28
        SRV = 33
        NAPTR = 35
        A6 = 38
        DNAME = 39
        SPF = 99

        QUERY_TYPES = {
            A: 'A',
            NS: 'NS',
            MD: 'MD',
            MF: 'MF',
            CNAME: 'CNAME',
            SOA: 'SOA',
            MB: 'MB',
            MG: 'MG',
            MR: 'MR',
            NULL: 'NULL',
            WKS: 'WKS',
            PTR: 'PTR',
            HINFO: 'HINFO',
            MINFO: 'MINFO',
            MX: 'MX',
            TXT: 'TXT',
            RP: 'RP',
            AFSDB: 'AFSDB',

            # 19 through 27?  Eh, I'll get to 'em.

            AAAA: 'AAAA',
            SRV: 'SRV',
            NAPTR: 'NAPTR',
            A6: 'A6',
            DNAME: 'DNAME',
            SPF: 'SPF'
        }

    timeout: The retention time for this record, in seconds.
    """
    cnames = []
    results = []
    authority = []
    additional = []
    default_ttl = max(self.soa[1].minimum, self.soa[1].expire)

    # Do records search. Get a list of classes like Record_A and Record_MX 
    # back. These are defined in dns.py .
    domain_records = self.records.get(name.lower())

    # Structure the results so as to present them the way that DNS records 
    # usually come back.

    if domain_records:
        # Loop through all of the results.
        for record in domain_records:
            if record.ttl is not None:
                ttl = record.ttl
            else:
                ttl = default_ttl

            # If we're looking at a [subdomain?] NS record, note it.
            if record.TYPE == dns.NS and name.lower() != self.soa[0].lower():
                # NS record belong to a child zone: this is a referral.  As
                # NS records are authoritative in the child zone, ours here
                # are not.  RFC 2181, section 6.1.
                authority.append(
                    dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=False)
                )

            # Was the record what was requested, or did we want everything?
            elif record.TYPE == type or type == dns.ALL_RECORDS:
                results.append(
                    dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=True)
                )

            # If we're looking at a CNAME record, note it.
            if record.TYPE == dns.CNAME:
                cnames.append(
                    dns.RRHeader(name, record.TYPE, dns.IN, ttl, record, auth=True)
                )

        # If no requested records were found, use the CNAME records (if any).
        if not results:
            results = cnames

        # Go through any NS, CNAME, or MX records found, and find the IPs 
        # for those hosts.
        #
        # NOTE: The "additional" list doesn't appear to be populated.
        for record in results + authority:
            section = {dns.NS: additional, dns.CNAME: results, dns.MX: additional}.get(record.type)
            if section is not None:
                n = str(record.payload.name)
                for rec in self.records.get(n.lower(), ()):
                    if rec.TYPE == dns.A:
                        section.append(
                            dns.RRHeader(n, dns.A, dns.IN, rec.ttl or default_ttl, rec, auth=True)
                        )

        # Not found. Return an SOA record with the name that was requested 
        # (the normal response that you'll see at the console).
        if not results and not authority:
            # Empty response. Include SOA record to allow clients to cache
            # this response.  RFC 1034, sections 3.7 and 4.3.4, and RFC 2181
            # section 7.1.
            authority.append(
                dns.RRHeader(self.soa[0], dns.SOA, dns.IN, ttl, self.soa[1], auth=True)
                )

        # We return a tuple of individual result lists. Each of the records 
        # is an instance of RRHeader, which wraps the Record_* classes in 
        # dns.py for returning as a result (Resource Record). 
        #
        # The first item in the tuple refers to the "ANSWER SECTION" in the 
        # DiG output, and the third item refers to the "ADDITIONAL 
        # SECTION". As "authority" was an empty list in the example, no 
        # output relates to it. It will have NS records if any are present, 
        # or contain an SOA record for what was requested if nothing was 
        # found.
        # 
        #;; QUESTION SECTION:
        #;example-domain.com.            IN      ANY
        #
        #;; ANSWER SECTION:
        #example-domain.com.     3600    IN      SOA     ns1.example-domain.com. root.example-domain.com. 2003010601 3600 3600 3600 3600
        #example-domain.com.     3600    IN      A       127.9.9.9
        #example-domain.com.     3600    IN      NS      ns1.example-domain.com.
        #example-domain.com.     3600    IN      MX      0 mail.example-domain.com.
        #
        #;; ADDITIONAL SECTION:
        #mail.example-domain.com. 3600   IN      A       123.0.16.43

        return defer.succeed((results, authority, additional))
    else:
        if name.lower().endswith(self.soa[0].lower()):
            # We are the authority and we didn't find it.  Goodbye.
            return defer.fail(failure.Failure(dns.AuthoritativeDomainError(name)))
        return defer.fail(failure.Failure(dns.DomainError(name)))