File: doh.py

package info (click to toggle)
dnspython 2.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,448 kB
  • sloc: python: 34,885; sh: 7; makefile: 4
file content (65 lines) | stat: -rw-r--r-- 2,144 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license

import base64
import functools
import socket

import hypercorn.config
import hypercorn.trio
import quart
import quart_trio


def setup(server, connection_type):
    name = f"{__name__}-{connection_type.name}"
    app = quart_trio.QuartTrio(name)
    app.logger.handlers = []

    @app.route("/dns-query", methods=["GET", "POST"])
    async def dns_query():
        if quart.request.method == "POST":
            wire = await quart.request.body
        else:
            encoded = quart.request.args["dns"]
            remainder = len(encoded) % 4
            if remainder != 0:
                encoded += "=" * (4 - remainder)
            wire = base64.urlsafe_b64decode(encoded)
        for body in server.handle_wire(
            wire,
            quart.request.remote_addr,
            quart.request.server,
            connection_type,
        ):
            if body is not None:
                return quart.Response(body, mimetype="application/dns-message")
            else:
                return quart.Response(status=500)

    return app


def make_server(server, sock, connection_type, tls_chain, tls_key):
    doh_app = setup(server, connection_type)
    hconfig = hypercorn.config.Config()
    fd = sock.fileno()
    if sock.type == socket.SOCK_STREAM:
        # We put http/1.1 in the ALPN as we don't mind, but DoH is
        # supposed to be H2 officially.
        hconfig.alpn_protocols = ["h2", "http/1.1"]
        hconfig.bind = [f"fd://{fd}"]
        hconfig.quic_bind = []
    else:
        hconfig.alpn_protocols = ["h3"]
        # We should be able to pass bind=[], but that triggers a bug in
        # hypercorn.  So, create a dummy socket and bind to it.
        tmp_sock = socket.create_server(("127.0.0.1", 0))
        hconfig.bind = [f"fd://{tmp_sock.fileno()}"]
        tmp_sock.detach()
        hconfig.quic_bind = [f"fd://{fd}"]
    sock.detach()
    hconfig.certfile = tls_chain
    hconfig.keyfile = tls_key
    hconfig.accesslog = None
    hconfig.errorlog = None
    return functools.partial(hypercorn.trio.serve, doh_app, hconfig)