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
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()))
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
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
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