refactor dnscrypt parse
add test
This commit is contained in:
parent
ee37b9e95e
commit
a53b9c7a8e
10 changed files with 608 additions and 540 deletions
91
dnscrypt/parser.py
Normal file
91
dnscrypt/parser.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue