openwrt-dns/dnscrypt/parser.py
2025-02-07 16:50:00 +08:00

92 lines
2.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

def props(b: bytes, i: int):
'''
``props`` is a little-endian 64 bit value that represents informal properties about the resolver. It is a logical OR
combination of the following values:
- ``1``: the server supports DNSSEC
- ``2``: the server doesnt keep logs
- ``4``: the server doesnt intentionally block domains
For example, a server that supports DNSSEC, stores logs, but doesnt block anything on its own should set ``props``
as the following 8 bytes sequence: ``[ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]``.
'''
props = b[i]
dnssec = not not ((props >> 0) & 1)
nolog = not not ((props >> 1) & 1)
nofilter = not not ((props >> 2) & 1)
i = i + 8
return i, dnssec, nolog, nofilter
def LP(b: bytes, i: int):
'''
``a || b`` is the concatenation of ``a`` and ``b``
``len(x)`` is a single byte representation of the length of ``x``, in bytes. Strings dont have to be zero-terminated
and do not require invidual encoding.
``LP(x)`` is ``len(x) || x``, i.e ``x`` prefixed by its length.
'''
x_len = b[i]
i = i + 1
x = b[i:i + x_len]
i = i + x_len
return i, x
def LP_decode(b: bytes, i: int, encoding='utf-8'):
i, x = LP(b, i)
return i, x.decode(encoding)
def LP_pk(b: bytes, i: int):
i, x = LP(b, i)
if len(x) != 32:
raise ValueError("LP(pk)")
hpk = x.hex().upper()
hpks = []
for j in range(0, 16):
hpks.append(hpk[j * 4: j * 4 + 4])
pk = ":".join(hpks)
return i, pk
def VLP(b: bytes, i: int):
'''
``a | b`` is the result of the logical ``OR`` operation between ``a`` and ``b``.
``vlen(x)`` is equal to ``len(x)`` if ``x`` is the last element of a set, and ``0x80 | len(x)`` if there are more
elements in the set.
``VLP(x1, x2, ...xn)`` encodes a set, as ``vlen(x1) || x1 || vlen(x2) || x2 ... || vlen(xn) || xn``.
Since ``vlen(xn) == len(xn)`` (length of the last element doesnt have the high bit set), for a set with a single
element, we have ``VLP(x) == LP(x)``.
'''
xx = []
last_element = False
while True:
if b[i] & 0x80 == 0:
last_element = True
x_len = b[i]
else:
x_len = b[i] ^ 0x80
i = i + 1
if x_len > 0:
x = b[i:i + x_len]
xx.append(x)
i = i + x_len
if last_element:
return i, xx
def VLP_hashs(b: bytes, i: int):
i, xx = VLP(b, i)
hashs = list(map(lambda x: x.hex(), xx))
return i, hashs
def VLP_bootstrap_ipi(b: bytes, i: int):
i, xx = VLP(b, i)
bootstrap_ipi = list(map(lambda x: x.decode("utf-8"), xx))
return i, bootstrap_ipi