92 lines
2.7 KiB
Python
92 lines
2.7 KiB
Python
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 doesn’t keep logs
|
||
- ``4``: the server doesn’t intentionally block domains
|
||
|
||
For example, a server that supports DNSSEC, stores logs, but doesn’t 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 don’t 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 doesn’t 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
|