Ejemplo n.º 1
0
def query_uri(hosts):
    """
    Return a list containing two answers, one for each uri type
    """
    answers = []
    if version.MAJOR < 2 or (version.MAJOR == 2 and version.MINOR == 0):
        m = message.Message()
    elif version.MAJOR == 2 and version.MINOR > 0:
        m = message.QueryMessage()  # pylint: disable=E1101
        m = message.make_response(m)  # pylint: disable=E1101

    rdtype = rdatatype.URI
    for name in ('_kerberos.', '_kpasswd.'):
        qname = DNSName(name + m_api.env.domain)
        qname = qname.make_absolute()
        if version.MAJOR < 2:
            # pylint: disable=unexpected-keyword-arg
            answer = Answer(qname,
                            rdataclass.IN,
                            rdtype,
                            m,
                            raise_on_no_answer=False)
            # pylint: enable=unexpected-keyword-arg
        else:
            if version.MAJOR == 2 and version.MINOR > 0:
                question = rrset.RRset(qname, rdataclass.IN, rdtype)
                m.question = [question]
            answer = Answer(qname, rdataclass.IN, rdtype, m)

        rl = []
        for host in hosts:
            rlist = rrset.from_text_list(
                qname, 86400, rdataclass.IN, rdatatype.URI, [
                    '0 100 "krb5srv:m:tcp:%s."' % host,
                    '0 100 "krb5srv:m:udp:%s."' % host,
                ])
            rl.extend(rlist)
        answer.rrset = rl
        answers.append(answer)
    return answers
Ejemplo n.º 2
0
def fake_query(qname,
               rdtype=rdatatype.A,
               rdclass=rdataclass.IN,
               count=1,
               fake_txt=False):
    """Fake a DNS query, returning count responses to the request

       Three kinds of lookups are faked:
       1. A query for A records for a service will return the count
          as requested in the test. This simulates lookups for the
          ipa-ca A record. To force a difference in responses one can
          vary the count.
       2. AAAA records are not yet supported, return no answer
       3. TXT queries will return the Kerberos realm

       fake_txt will set an invalid Kerberos realm entry to provoke a
       warning.
    """
    m = message.Message()
    if rdtype == rdatatype.A:
        fqdn = DNSName(qname)
        fqdn = fqdn.make_absolute()

        answers = Answer(fqdn,
                         rdataclass.IN,
                         rdatatype.A,
                         m,
                         raise_on_no_answer=False)

        rlist = rrset.from_text_list(fqdn, 86400, rdataclass.IN, rdatatype.A,
                                     gen_addrs(count))

        answers.rrset = rlist
    elif rdtype == rdatatype.AAAA:
        raise NoAnswer(response=Response('no AAAA'))
    elif rdtype == rdatatype.TXT:
        if fake_txt:
            realm = 'FAKE_REALM'
        else:
            realm = m_api.env.realm
        qname = DNSName('_kerberos.' + m_api.env.domain)
        qname = qname.make_absolute()

        answers = Answer(qname,
                         rdataclass.IN,
                         rdatatype.TXT,
                         m,
                         raise_on_no_answer=False)

        rlist = rrset.from_text_list(qname, 86400, rdataclass.IN,
                                     rdatatype.TXT, [realm])

        answers.rrset = rlist

    return answers
Ejemplo n.º 3
0
def create_answer(name, rrset):
    rdtype = rrset.rdtype
    rdclass = rrset.rdclass

    if not isinstance(name, Name):
        name = from_text(name)

    query = make_query(name, rdtype, rdclass)
    response = make_response(query)
    response.answer = [rrset]
    response.index = {(ANSWER, name, rdclass, rdtype, 0, None): rrset}
    response.find_rrset(response.answer, name, rdclass=rdclass, rdtype=rdtype)

    rdtype = RdataType.make(rdtype)
    rdclass = RdataClass.make(rdclass)

    answer = Answer(name, rdtype, rdclass, response)
    return answer
Ejemplo n.º 4
0
    def main(self, host=[], *args):
        """
        Main function
        """
        target = self.ip

        if self.host:
            try:
                target = gethostbyname(self.host)
            except:
                raise InvalidTarget('Host not found.')

        domain = None

        if not host or not host[0]:
            raise NoHostName('No host name specified.')

        for domain in host:
            if not domain:
                continue

            self._check_stop()

            self._write_result('%s:' % domain)
            results = []

            try:
                # make DNS query manually, clearing the RD (recursion desired) flag
                query = make_query(domain, rdatatype.A, rdataclass.IN)
                query.flags = flags.RD

                found = False

                try:
                    response = dns_query.udp(query, target, self.DNS_TIMEOUT, self.DNS_PORT, None)

                except Exception:
                    response = None

                if response and response.rcode() == rcode.NXDOMAIN:
                    raise NXDOMAIN

                if response and response.rcode() == rcode.NOERROR:
                    found = True
                else:
                    raise NXDOMAIN

                a_records = Answer(dns_name.from_text(domain), rdatatype.A, rdataclass.IN, response, True)
                a_records = map(lambda x: str(x), a_records)

                for a in a_records:
                    if str(a) not in results:
                        results.append(str(a))
                        self._write_result(str(a))

                if len(results) == 0:
                    self._write_result('No A records.')

            except ( NoAnswer, NXDOMAIN ):
                self._write_result('Host not found.')

            except Timeout:
                self._write_result('DNS request timeout.')

            except DNSException:
                self._write_result('DNS error.')

            self._write_result('')

        self._check_stop()
Ejemplo n.º 5
0
def fake_query(qname, rdtype=rdatatype.A, rdclass=rdataclass.IN, count=1,
               fake_txt=False):
    """Fake a DNS query, returning count responses to the request

       Three kinds of lookups are faked:
       1. A query for A/AAAA records for a service will return the count
          as requested in the test. This simulates lookups for the
          ipa-ca A/AAAA record. To force a difference in responses one can
          vary the count.
       2. TXT queries will return the Kerberos realm

       fake_txt will set an invalid Kerberos realm entry to provoke a
       warning.
    """
    if version.MAJOR < 2 or (version.MAJOR == 2 and version.MINOR == 0):
        m = message.Message()
    elif version.MAJOR == 2 and version.MINOR > 0:
        m = message.QueryMessage()
        m = message.make_response(m)
    if rdtype in (rdatatype.A, rdatatype.AAAA):
        fqdn = DNSName(qname)
        fqdn = fqdn.make_absolute()

        if version.MAJOR < 2:
            # pylint: disable=unexpected-keyword-arg
            answers = Answer(fqdn, rdataclass.IN, rdtype, m,
                             raise_on_no_answer=False)
            # pylint: enable=unexpected-keyword-arg
        else:
            if version.MAJOR == 2 and version.MINOR > 0:
                question = rrset.RRset(fqdn, rdataclass.IN, rdtype)
                m.question = [question]
            answers = Answer(fqdn, rdataclass.IN, rdtype, m)

        rlist = rrset.from_text_list(fqdn, 86400, rdataclass.IN,
                                     rdtype, gen_addrs(rdtype, count))

        answers.rrset = rlist
    elif rdtype == rdatatype.TXT:
        if fake_txt:
            realm = 'FAKE_REALM'
        else:
            realm = m_api.env.realm
        qname = DNSName('_kerberos.' + m_api.env.domain)
        qname = qname.make_absolute()

        if version.MAJOR < 2:
            # pylint: disable=unexpected-keyword-arg
            answers = Answer(qname, rdataclass.IN, rdatatype.TXT, m,
                             raise_on_no_answer=False)
            # pylint: enable=unexpected-keyword-arg
        else:
            if version.MAJOR == 2 and version.MINOR > 0:
                question = rrset.RRset(qname, rdataclass.IN, rdtype)
                m.question = [question]
            answers = Answer(qname, rdataclass.IN, rdatatype.TXT, m)

        rlist = rrset.from_text_list(qname, 86400, rdataclass.IN,
                                     rdatatype.TXT, [realm])

        answers.rrset = rlist

    return answers
Ejemplo n.º 6
0
    def query(self,
              qname,
              rdtype=dns.rdatatype.A,
              rdclass=dns.rdataclass.IN,
              tcp=False,
              source=None,
              raise_on_no_answer=True,
              source_port=0):
        """Query nameservers to find the answer to the question.

        The I{qname}, I{rdtype}, and I{rdclass} parameters may be objects
        of the appropriate type, or strings that can be converted into objects
        of the appropriate type.  E.g. For I{rdtype} the integer 2 and the
        the string 'NS' both mean to query for records with DNS rdata type NS.

        @param qname: the query name
        @type qname: dns.name.Name object or string
        @param rdtype: the query type
        @type rdtype: int or string
        @param rdclass: the query class
        @type rdclass: int or string
        @param tcp: use TCP to make the query (default is False).
        @type tcp: bool
        @param source: bind to this IP address (defaults to machine default IP).
        @type source: IP address in dotted quad notation
        @param raise_on_no_answer: raise NoAnswer if there's no answer
        (defaults is True).
        @type raise_on_no_answer: bool
        @param source_port: The port from which to send the message.
        The default is 0.
        @type source_port: int
        @rtype: dns.resolver.Answer instance
        @raises Timeout: no answers could be found in the specified lifetime
        @raises NXDOMAIN: the query name does not exist
        @raises YXDOMAIN: the query name is too long after DNAME substitution
        @raises NoAnswer: the response did not contain an answer and
        raise_on_no_answer is True.
        @raises NoNameservers: no non-broken nameservers are available to
        answer the question."""

        if isinstance(qname, (str, unicode)):
            qname = dns.name.from_text(qname, None)
        if isinstance(rdtype, (str, unicode)):
            rdtype = dns.rdatatype.from_text(rdtype)
        if dns.rdatatype.is_metatype(rdtype):
            raise NoMetaqueries
        if isinstance(rdclass, (str, unicode)):
            rdclass = dns.rdataclass.from_text(rdclass)
        if dns.rdataclass.is_metaclass(rdclass):
            raise NoMetaqueries
        qnames_to_try = []
        if qname.is_absolute():
            qnames_to_try.append(qname)
        else:
            if len(qname) > 1:
                qnames_to_try.append(qname.concatenate(dns.name.root))
            if self.search:
                for suffix in self.search:
                    qnames_to_try.append(qname.concatenate(suffix))
            else:
                qnames_to_try.append(qname.concatenate(self.domain))
        all_nxdomain = True
        start = time.time()
        for qname in qnames_to_try:
            if self.cache:
                answer = self.cache.get((qname, rdtype, rdclass))
                if not answer is None:
                    if answer.rrset is None and raise_on_no_answer:
                        raise NoAnswer
                    else:
                        return answer
            request = dns.message.make_query(qname, rdtype, rdclass)
            if not self.keyname is None:
                request.use_tsig(self.keyring,
                                 self.keyname,
                                 algorithm=self.keyalgorithm)
            request.use_edns(self.edns, self.ednsflags, self.payload)
            if self.flags is not None:
                request.flags = self.flags
            response = None
            #
            # make a copy of the servers list so we can alter it later.
            #
            nameservers = self.nameservers[:]
            backoff = 0.10
            while response is None:
                if len(nameservers) == 0:
                    raise NoNameservers
                for nameserver in nameservers[:]:
                    timeout = self._compute_timeout(start)
                    try:
                        if tcp:
                            response = dns.query.tcp(request,
                                                     nameserver,
                                                     timeout,
                                                     self.port,
                                                     source=source,
                                                     source_port=source_port)
                        else:
                            response = dns.query.udp(request,
                                                     nameserver,
                                                     timeout,
                                                     self.port,
                                                     source=source,
                                                     source_port=source_port)
                            if response.flags & dns.flags.TC and not self.no_tcp_on_tc:
                                # Response truncated; retry with TCP.
                                timeout = self._compute_timeout(start)
                                response = dns.query.tcp(
                                    request,
                                    nameserver,
                                    timeout,
                                    self.port,
                                    source=source,
                                    source_port=source_port)
                    except (socket.error, dns.exception.Timeout):
                        #
                        # Communication failure or timeout.  Go to the
                        # next server
                        #
                        response = None
                        continue
                    except dns.query.UnexpectedSource:
                        #
                        # Who knows?  Keep going.
                        #
                        response = None
                        continue
                    except dns.exception.FormError:
                        #
                        # We don't understand what this server is
                        # saying.  Take it out of the mix and
                        # continue.
                        #
                        nameservers.remove(nameserver)
                        response = None
                        continue
                    except EOFError:
                        #
                        # We're using TCP and they hung up on us.
                        # Probably they don't support TCP (though
                        # they're supposed to!).  Take it out of the
                        # mix and continue.
                        #
                        nameservers.remove(nameserver)
                        response = None
                        continue
                    rcode = response.rcode()
                    if rcode == dns.rcode.YXDOMAIN:
                        raise YXDOMAIN
                    if rcode == dns.rcode.NOERROR or \
                           rcode == dns.rcode.NXDOMAIN or \
                           (rcode == dns.rcode.SERVFAIL and self.return_servfail) or \
                           (rcode == dns.rcode.REFUSED and self.return_refused):
                        break
                    #
                    # We got a response, but we're not happy with the
                    # rcode in it.  Remove the server from the mix if
                    # the rcode isn't SERVFAIL.
                    #
                    if rcode != dns.rcode.SERVFAIL or not self.retry_servfail:
                        nameservers.remove(nameserver)
                    response = None
                if not response is None:
                    break
                #
                # All nameservers failed!
                #
                if len(nameservers) > 0:
                    #
                    # But we still have servers to try.  Sleep a bit
                    # so we don't pound them!
                    #
                    timeout = self._compute_timeout(start)
                    sleep_time = min(timeout, backoff)
                    backoff *= 2
                    time.sleep(sleep_time)
            if response.rcode() == dns.rcode.NXDOMAIN:
                continue
            all_nxdomain = False
            break
        if all_nxdomain:
            raise NXDOMAIN
        answer = Answer(qname, rdtype, rdclass, response, raise_on_no_answer)
        if self.cache:
            self.cache.put((qname, rdtype, rdclass), answer)
        return answer