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"]
Esempio n. 2
0
    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]
Esempio n. 3
0
    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
Esempio n. 4
0
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
Esempio n. 7
0
    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)
Esempio n. 8
0
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
Esempio n. 9
0
    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
Esempio n. 10
0
#!/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])