Ejemplo n.º 1
0
    def tcp(self, query, timeout=None, af=None, source=None, source_port=0,
            one_rr_per_rrset=False):
        wire = self.__encrypt_query(query)
        (af, destination, source) = dns.query._destination_and_source(
            af, self.address, self.port, source, source_port)
        s = dns.query.socket_factory(af, socket.SOCK_STREAM)
        begin_time = None
        try:
            expiration = dns.query._compute_expiration(timeout)
            s.setblocking(0)
            begin_time = time.time()
            if source is not None:
                s.bind(source)
            dns.query._connect(s, destination)
            l = len(wire)
            tcpmsg = struct.pack('!H', l) + wire
            dns.query._net_write(s, tcpmsg, expiration)
            ldata = dns.query._net_read(s, 2, expiration)
            (l, ) = struct.unpack('!H', ldata)
            wire = dns.query._net_read(s, l, expiration)
        finally:
            if begin_time is None:
                response_time = 0
            else:
                response_time = time.time() - begin_time
            s.close()

        r = self.__decrypt_response(wire, one_rr_per_rrset)
        r.time = response_time
        if not query.is_response(r):
            raise dns.query.BadResponse
        return r
Ejemplo n.º 2
0
    def _process_response(self, wire_data):
        """
        Process the raw data retrieved from the remote name server.
        Match up the response with the original query and fire the
        L{twisted.internet.defer.Deferred} that is associated with the
        query.  Cancel the L{twisted.internet.base.DelayedCall} that
        may be associated with the query as well.

        @param wire_data: the raw data received from the remote DNS
        server, after removing any framing that may be required by the
        underlying transport.
        @type wire_data: C{str}
        """

        (query_id,) = struct.unpack('!H', wire_data[:2])
        
        if query_id not in self.pending:
            log.msg('No query with ID {} found to match received response!'.format(query_id))
            return

        query, query_response, delayed_call = self.pending.pop(query_id)
        
        if delayed_call and delayed_call.active():
            delayed_call.cancel()

        response = dns.message.from_wire(wire_data,
                                         keyring = query.keyring,
                                         request_mac = query.mac,
                                         one_rr_per_rrset = self.one_rr_per_rrset)
        
        if query.is_response(response):
            query_response.callback(response)
            
        else:
            query_response.errback(failure.Failure(dns.query.BadResponse()))
Ejemplo n.º 3
0
    def udp(self,
            query,
            timeout=None,
            af=None,
            source=None,
            source_port=0,
            ignore_unexpected=False,
            one_rr_per_rrset=False):
        wire = self.__encrypt_query(query)
        (af, destination,
         source) = dns.query._destination_and_source(af, self.address,
                                                     self.port, source,
                                                     source_port)

        s = dns.query.socket_factory(af, socket.SOCK_DGRAM)
        begin_time = None
        try:
            expiration = dns.query._compute_expiration(timeout)
            s.setblocking(0)
            if source is not None:
                print(source)
                s.bind(source)
            dns.query._wait_for_writable(s, expiration)
            begin_time = time.time()
            s.sendto(wire, destination)
            while 1:
                dns.query._wait_for_readable(s, expiration)
                (wire, from_address) = s.recvfrom(65535)
                if dns.query._addresses_equal(af, from_address, destination) \
                   or (is_multicast(self.address) and
                       from_address[1:] == destination[1:]):
                    break
                if not ignore_unexpected:
                    raise dns.query.UnexpectedSource(
                        'got a response from %s instead of %s' %
                        (from_address, destination))
        finally:
            if begin_time is None:
                response_time = 0
            else:
                response_time = time.time() - begin_time
            s.close()

        r = self.__decrypt_response(wire, one_rr_per_rrset)
        r.time = response_time
        if not query.is_response(r):
            raise dns.query.BadResponse
        return r
Ejemplo n.º 4
0
def query_tcp(ip,
              port,
              query,
              query_encoder=PlainQueryEncoder,
              one_rr_per_rrset=False,
              **kwargs):
    """
    Sends a DNS query via TCP and returns the decoded response.

    Arguments:
        ip: The destination IP
        port: The destination port
        query: The query to send
        query_encoder: A `QueryEncoder` instance used for encoding the query and
            decoding the response (defaults to the PlainQueryEncoder)
        one_rr_per_rrset: whether to use only the first RRset for each section
            (defaults to False)
        **kwargs: passed to tcp_send_receive()

    Returns:
        dns.message.Message
    """

    wire, decode_args = query_encoder.encode(query)

    response_wire, response_time = tcp_send_receive(ip, port, wire, **kwargs)

    response = query_encoder.decode(response_wire,
                                    decode_args,
                                    keyring=query.keyring,
                                    request_mac=query.mac,
                                    one_rr_per_rrset=one_rr_per_rrset)

    response.time = response_time
    if not query.is_response(response):
        raise dns.query.BadResponse()
    return response
Ejemplo n.º 5
0
    def _soa_query_server(self, zone_name):
        """
        Use dnspython to read the SOA record of a Zone from the DNS server.

        This function returns whether the server is speaking inteligible DNS
        or not.  It function is as a keep alive check.
        """
        zone = dns.name.from_text(zone_name)
        rdtype = dns.rdatatype.from_text(RRTYPE_SOA)
        rdclass = dns.rdataclass.IN
        query = dns.message.make_query(zone, rdtype, rdclass)
        exc = None
        try:
            # Use TCP as dnspython can't track replies to multithreaded
            # queries
            answer = dns.query.tcp(query,
                                   self.address,
                                   timeout=float(
                                       settings['dns_query_timeout']))
            if not query.is_response(answer):
                msg = ("Server '%s': SOA query - reply from unexpected source,"
                       " retrying" % self.name)
                raise CantSoaQueryServer(msg)
        except dns.query.BadResponse as exc:
            msg = ("Server '%s': SOA query - received incorrectly"
                   " formatted query." % self.name)
            raise BrokenServer(msg)
        except dns.exception.Timeout:
            msg = ("Server '%s': SOA query - timeout waiting for response,"
                   " retrying" % self.name)
            raise CantSoaQueryServer(msg)
        except dns.query.UnexpectedSource as exc:
            # For UDP, FormError and BadResponse here are also failures
            msg = ("Server '%s': SOA query - reply from unexpected source,"
                   " retrying" % self.name)
            raise CantSoaQueryServer(msg)
        except dns.exception.FormError as exc:
            msg = ("Server '%s': SOA query - remote responded incorrectly"
                   " formatted query." % self.name)
            raise BrokenServer(msg)
        except (socket.error, OSError, IOError) as exc:
            if errno in (errno.EACCES, errno.EPERM, errno.ECONNREFUSED,
                         errno.ENETUNREACH, errno.ETIMEDOUT):
                msg = ("Server '%s': SOA query - can't query server %s - %s" %
                       (self.name, self.address, exc.strerror))
                raise CantSoaQueryServer(msg)
            msg = ("Server '%s': server %s, SOA query - fatal error %s." %
                   (self.name, self.address, exc.strerror))
            raise BrokenServer(msg)
        finally:
            # Clean up memory
            del query
        try:
            # Check and process result codes
            # with 0, check that answer.answer contains stuff, and check type of
            # 1st element is dns.rrset.RRset via isinstance()
            rcode = answer.rcode()
            rcode_text = dns.rcode.to_text(answer.rcode())
            if rcode in _soaquery_rcodes['success']:
                if (len(answer.answer)
                        and isinstance(answer.answer[0], dns.rrset.RRset)):
                    return
                msg = ("Server '%s': SOA query - bad response received." %
                       self.name)
                raise BrokenServer(msg)
            elif rcode in _soaquery_rcodes['ok']:
                return
            elif rcode in _soaquery_rcodes['retry']:
                msg = (
                    "Server '%s': SOA query - temporary failure - rcode '%s'" %
                    (self.name, rcode_text))
                raise CantSoaQueryServer(msg)
            elif rcode in _soaquery_rcodes['broken']:
                msg = ("Server '%s': SOA query - broken - rcode '%s'" %
                       (self.name, rcode_text))
                raise BrokenServer(msg)
            else:
                msg = ("Server '%s': SOA query - response with indeterminate"
                       " error - broken?" % self.name)
                raise BrokenServer(msg)

        finally:
            # clean up memory
            del answer