def test_doh_response_headers(): """Checks that the correct response headers are returned from a DoH query. This runs against a base list of response headers that we care about; we also try to avoid redundancy as dnsdist has similar tests. """ message = dns.message.make_query("wikipedia.org", "A") # https://docs.python.org/3/library/base64.html#base64.urlsafe_b64encode # "The result can still contain =.", so let's remove it from the params. url_params = base64.urlsafe_b64encode(message.to_wire()).rstrip(b"=") headers = {"content-type": "application/dns-message"} doh_response = requests.get(RESOLVER_URL + "/dns-query", params={"dns": url_params}, headers=headers) doh_response.raise_for_status() response_headers = doh_response.headers # HSTS, set by customResponseHeaders. hsts_value = "max-age=106384710; includeSubDomains; preload" assert response_headers["strict-transport-security"] == hsts_value # cache-control, set by sendCacheControlHeaders. assert "cache-control" in response_headers.keys() assert "max-age" in response_headers["cache-control"]
async def resolve(self, hostname: str, timeout: float = 1.0) -> Optional[str]: name = dns.name.from_text(hostname) future: asyncio.Future[str] = asyncio.Future() if name in self.queries: # a query for this name is already pending self.queries[name].add(future) else: # no query for this name is pending, send a request self.queries[name] = set([future]) message = dns.message.make_query(name, rdtype=dns.rdatatype.A) message.id = 0 message.flags = 0 self.tx_transport.sendto(message.to_wire(), (MDNS_ADDRESS, MDNS_PORT)) try: return await asyncio.wait_for(future, timeout=timeout) except asyncio.TimeoutError: return None finally: if name in self.queries: self.queries[name].discard(future) if not self.queries[name]: del self.queries[name]
def handle_query(self, client): """ Receive query from client socket and send an answer. Returns: True if client socket should be closed by caller False if client socket should be kept open """ log = logging.getLogger('pydnstest.testserver.handle_query') server_addr = client.getsockname()[0] query, client_addr = mock_client.recvfrom_msg(client) if query is None: return False log.debug('server %s received query from %s: %s', server_addr, client_addr, query) message = self.scenario.reply(query, server_addr) if not message: log.debug('ignoring') return True elif isinstance(message, scenario.DNSReplyServfail): self.undefined_answers += 1 self.scenario.current_step.log.error( 'server %s has no response for question %s, answering with SERVFAIL', server_addr, '; '.join([str(rr) for rr in query.question])) else: log.debug('response: %s', message) mock_client.sendto_msg(client, message.to_wire(), client_addr) return True
def sendto_message(stream, message, addr): """ Send DNS/UDP message. """ if TEST_DEBUG > 0: syn_message("outgoing data") message = message.to_wire() stream.sendto(message, addr) if TEST_DEBUG > 0: syn_message("[Python] sent", len(message), "bytes to", addr)
async def user_registration(self, username, password, ip_address, ttl): #Get uuid for the user based on given id fqdn = self.fqdn_formation(ip_address, soa) message = self.ddns_update(fqdn, soa, ip_address, ttl) dns_socket = await self.dns_connection() '''Need to send update message to Server here''' dns_socket.sendto(message.to_wire(), dns_address) dns_socket.recv(1024) #query = "update host_ids set ipv4='{}' where fqdn='{}'".format(ip,fqdn) #data = await self.db_host.execute(query) return 'nothing'
def setup(url, message, head=False, post=False): c = pycurl.Curl() if head and post: print("test_server cannot use HEAD and POST", file=sys.stderr) sys.exit(1) if head: c.setopt(pycurl.NOBODY, True) if post: c.setopt(c.URL, url) data = message.to_wire() c.setopt(pycurl.POST, True) c.setopt(pycurl.POSTFIELDS, data) else: c.setopt( c.URL, url + ("?ct&dns=%s" % base64.urlsafe_b64encode(message.to_wire()).decode('UTF8'))) c.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-udpwireformat"]) # Does not work if pycurl was not compiled with nghttp2 (recent Debian # packages are OK) https://github.com/pycurl/pycurl/issues/477 c.setopt(pycurl.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_2) return c
def datagramReceived(self, data, address): # noqa: N802 """Receive a datagram from the wire.""" self.log.debug("received ({data!r}) from {address!s}", data=data, address=address) message = dns.message.from_wire(data) self.log.debug('request:\n{message!s}', message=message) self.log.debug('edns request:\n{message:}', message=message) data = message.to_wire() d = self.client.request(data) d.addCallback(self.return_response, address) d.addErrback(self.error_response, address)
def answer(domain, rr, endpoint, format_json=None, debug=None, verbose=None, response_time=None, request_dnssec=None): """ Sends query to DNS provider and prints the answer. """ message = dns.message.make_query(domain, rr) if request_dnssec: message.want_dnssec() dns_req = base64.urlsafe_b64encode(message.to_wire()).decode("UTF8").rstrip("=") start_time = time.time() * 1000 try: r = requests.get(endpoint, params={"dns": dns_req}, headers={"Content-type": "application/dns-message"}) r.raise_for_status() except requests.RequestException as reqerror: sys.stderr.write("{0}\n".format(reqerror)) sys.exit(1) query_time = time.time() * 1000 if "application/dns-message" not in r.headers["Content-Type"]: print("The answer from: {0} is not a DNS response!".format(endpoint)) sys.exit(1) response = dns.message.from_wire(r.content) if debug: debug = response.to_text() if verbose: delimeter = "?" if "?" not in endpoint else "&" verbose = endpoint + delimeter + "dns=" + dns_req if response_time: response_time = format(round((query_time - start_time), 3)) answers = [] for response in dns.message.from_wire(r.content).answer: answers.append(response.to_text().split("\n")) answers = list(itertools.chain.from_iterable(answers)) if format_json: jdns = [] for answer in answers: output_json = answer.split() jdns.append( {"Query": output_json[0], "TTL": output_json[1], "RR": output_json[3], "Answer": output_json[4:99]}) if debug: jdns.append({"Debug": debug}) if verbose: jdns.append({"Verbose": verbose}) if response_time: jdns.append({"Query Time": response_time}) return json.dumps(jdns) output_plain = "" for answer in answers: delimeter = "IN " + rr + " " if request_dnssec and 'IN RRSIG' in answer: delimeter = "IN RRSIG " + rr + " " output_plain += "{0}\n".format(answer.split(delimeter)[-1]) if debug: output_plain += "\nDebug: \n{0}\n".format(debug) if verbose: output_plain += "\nVerbose: \n{0}\n".format(verbose) if response_time: output_plain += "\nQuery Time: \n{0}\n".format(response_time) return output_plain
usage("POST or HEAD but not both") sys.exit(1) if len(args) != 2: usage("Wrong number of arguments") sys.exit(1) url = args[0] name = args[1] buffer = io.BytesIO() c = pycurl.Curl() message = dns.message.make_query(name, dns.rdatatype.ANY) message.id = 0 # DoH requests that if head: c.setopt(pycurl.NOBODY, True) if post: c.setopt(c.URL, url) data = message.to_wire() c.setopt(pycurl.POST, True) c.setopt(pycurl.POSTFIELDS, data) else: dns_req = base64.urlsafe_b64encode( message.to_wire()).decode('UTF8').rstrip('=') c.setopt(c.URL, url + ("?ct&dns=%s" % dns_req)) c.setopt(pycurl.HTTPHEADER, ["Content-type: application/dns-udpwireformat"]) c.setopt(c.WRITEDATA, buffer) if verbose: c.setopt(c.VERBOSE, True) if insecure: c.setopt(pycurl.SSL_VERIFYPEER, False) c.setopt(pycurl.SSL_VERIFYHOST, False) # Does not work if pycurl was not compiled with nghttp2 (recent Debian # packages are OK) https://github.com/pycurl/pycurl/issues/477
#!/usr/bin/env python3 import dns.message import requests import base64 import sys RRs = ('A', 'AAAA', 'CNAME') if len(sys.argv) != 3: print("Usage: python3 RFC.8484.py balaskas.gr AAAA") sys.exit(1) if sys.argv[2] not in RRs: print("Supported Reourse Records: A, AAAA & CNAME") sys.exit(1) message = dns.message.make_query(sys.argv[1], sys.argv[2]) dns_req = base64.b64encode(message.to_wire()).decode('UTF8').rstrip('=') url = "https://doh.libredns.gr/dns?dns=" + dns_req # url = "https://cloudflare-dns.com/dns-query?dns=" + dns_req # url = "https://dns.google/dns-query?dns=" + dns_req r = requests.get(url, headers={"Content-type": "application/dns-message"}) for answer in dns.message.from_wire(r.content).answer: print(answer.to_text().split()[-1])