Ejemplo n.º 1
0
    def on_answer(self, request, dnsr=None, dnsq=None):
        headers = CIMultiDict()

        if dnsr is None:
            dnsr = dns.message.make_response(dnsq)
            dnsr.set_rcode(dns.rcode.SERVFAIL)
        elif len(dnsr.answer):
            ttl = min(r.ttl for r in dnsr.answer)
            headers["cache-control"] = "max-age={}".format(ttl)

        clientip = utils.get_client_ip(request.transport)
        interval = int((time.time() - self.time_stamp) * 1000)
        self.logger.info("[HTTPS] {} (Original IP: {}) {} {}ms".format(
            clientip, request.remote, utils.dnsans2log(dnsr), interval))
        if request.method == "HEAD":
            body = b""
        else:
            body = dnsr.to_wire()

        return aiohttp.web.Response(
            status=200,
            body=body,
            content_type=constants.DOH_MEDIA_TYPE,
            headers=headers,
        )
Ejemplo n.º 2
0
async def doh1handler(request):
    path, params = utils.extract_path_params(request.rel_url.path_qs)

    if request.method in ["GET", "HEAD"]:
        try:
            ct, body = utils.extract_ct_body(params)
        except DOHParamsException as e:
            return aiohttp.web.Response(status=400, body=e.body())
    elif request.method == "POST":
        body = await request.content.read()
        ct = request.headers.get("content-type")
    else:
        return aiohttp.web.Response(status=501, body=b"Not Implemented")
    if ct != constants.DOH_MEDIA_TYPE:
        return aiohttp.web.Response(status=415,
                                    body=b"Unsupported content type")

    # Do actual DNS Query
    try:
        dnsq = utils.dns_query_from_body(body, debug=request.app.debug)
    except DOHDNSException as e:
        return aiohttp.web.Response(status=400, body=e.body())

    clientip = utils.get_client_ip(request.transport)
    request.app.logger.info("[HTTPS] {} (Original IP: {}) {}".format(
        clientip, request.remote, utils.dnsquery2log(dnsq)))
    return await request.app.resolve(request, dnsq)
Ejemplo n.º 3
0
    def on_answer(self, stream_id, dnsr=None, dnsq=None):
        try:
            request_data = self.stream_data[stream_id]
        except KeyError:
            # Just return, we probably 405'd this already
            return

        response_headers = [
            (":status", "200"),
            ("content-type", constants.DOH_MEDIA_TYPE),
            ("server", "asyncio-h2"),
        ]
        if dnsr is None:
            dnsr = dns.message.make_response(dnsq)
            dnsr.set_rcode(dns.rcode.SERVFAIL)
        elif len(dnsr.answer):
            ttl = min(r.ttl for r in dnsr.answer)
            response_headers.append(
                ("cache-control", "max-age={}".format(ttl)))

        clientip = utils.get_client_ip(self.transport)
        interval = int((time.time() - self.time_stamp) * 1000)
        self.logger.info("[HTTPS] {} {} {}ms".format(clientip,
                                                     utils.dnsans2log(dnsr),
                                                     interval))
        if request_data.headers[":method"] == "HEAD":
            body = b""
        else:
            body = dnsr.to_wire()
        response_headers.append(("content-length", str(len(body))))

        self.conn.send_headers(stream_id, response_headers)
        self.conn.send_data(stream_id, body, end_stream=True)
        self.transport.write(self.conn.data_to_send())
Ejemplo n.º 4
0
    async def resolve(self, dnsq, stream_id):
        clientip = utils.get_client_ip(self.transport)
        dnsclient = DNSClient(self.upstream_resolver, self.upstream_port,
                              logger=self.logger)
        dnsr = await dnsclient.query(dnsq, clientip, ecs=self.ecs)

        if dnsr is None:
            self.on_answer(stream_id, dnsq=dnsq)
        else:
            self.on_answer(stream_id, dnsr=dnsr)
Ejemplo n.º 5
0
    def stream_complete(self, stream_id: int):
        """
        When a stream is complete, we can send our response.
        """
        try:
            request_data = self.stream_data[stream_id]
        except KeyError:
            # Just return, we probably 405'd this already
            return

        headers = request_data.headers
        method = request_data.headers[':method']

        # Handle the actual query
        path, params = utils.extract_path_params(headers[':path'])

        if path != self.uri:
            self.return_404(stream_id)
            return

        if method in ['GET', 'HEAD']:
            try:
                ct, body = utils.extract_ct_body(params)
            except DOHParamsException as e:
                self.return_400(stream_id, body=e.body())
                return
        elif method == 'POST':
            body = request_data.data.getvalue()
            ct = headers.get('content-type')
        else:
            self.return_501(stream_id)
            return

        if ct != constants.DOH_MEDIA_TYPE:
            self.return_415(stream_id)
            return

        # Do actual DNS Query
        try:
            dnsq = utils.dns_query_from_body(body, self.debug)
        except DOHDNSException as e:
            self.return_400(stream_id, body=e.body())
            return

        clientip = utils.get_client_ip(self.transport)
        self.logger.info(
            '[HTTPS] {} {}'.format(
                clientip,
                utils.dnsquery2log(dnsq)
            )
        )
        self.time_stamp = time.time()
        asyncio.ensure_future(self.resolve(dnsq, stream_id))
Ejemplo n.º 6
0
 def receive_data(self, data: bytes, stream_id: int):
     """
     We've received some data on a stream. If that stream is one we're
     expecting data on, save it off. Otherwise, reset the stream.
     """
     try:
         stream_data = self.stream_data[stream_id]
     except KeyError:
         # Unknown stream, log and ignore (the stream may already be ended)
         clientip = utils.get_client_ip(self.transport)
         self.logger.info("[HTTPS] %s Unknown stream %d", clientip,
                          stream_id)
     else:
         stream_data.data.write(data)