]>
gitweb.michael.orlitzky.com - djbdns-logparse.git/blob - djbdns/tinydns.py
2 Functions and data specific to tinydns logs.
4 # Don't clobber the global compile() with a named import.
7 from typing
import Optional
8 from djbdns
.common
import QUERY_TYPE_NAME
, TIMESTAMP_PAT
, convert_ip
10 # The "hex4" pattern matches a string of four hexadecimal digits. This
11 # is used, for example, by tinydns to encode the query type
13 HEX4_PAT
= r
'[0-9a-f]{4}'
15 # The IP pattern matches a string of either 8 or 32 hexadecimal
16 # characters, which correspond to IPv4 and IPv6 addresses,
17 # respectively, in tinydns logs.
18 IP_PAT
= r
'[0-9a-f]{8,32}'
20 # The regex to match tinydns log lines.
21 TINYDNS_LOG_RE
= re
.compile(
22 rf
'({TIMESTAMP_PAT}) ({IP_PAT}):({HEX4_PAT}):({HEX4_PAT}) ([\+\-IC/]) ({HEX4_PAT}) (.*)'
25 # tinydns can drop a query for one of three reasons; this dictionary
26 # maps the symbol that gets logged in each case to a human-readable
27 # reason. We include the "+" case here, indicating that the query was
28 # NOT dropped, to avoid a special case later on when we're formatting
29 # the human-readable output.
39 def handle_tinydns_log(line
: str) -> Optional
[str]:
41 Handle a single log line if it matches the ``TINYDNS_LOG_RE`` regex.
47 The log line that might match ``TINYDNS_LOG_RE``.
52 Either the human-readable string if the log line was handled (that
53 is, if it was really a tinydns log line), or ``None`` if it was
59 >>> line = "2022-09-14 21:04:40.206516500 7f000001:9d61:be69 - 0001 www.example.com"
60 >>> handle_tinydns_log(line)
61 '2022-09-14 21:04:40.206516500 dropped query (no authority) from 127.0.0.1:40289 (id 48745): a www.example.com'
63 >>> line = "this line is nonsense"
64 >>> handle_tinydns_log(line)
67 match
= TINYDNS_LOG_RE
.match(line
)
71 (timestamp
, ip
, port
, request_id
, code
, query_type
, name
) = match
.groups()
74 request_id
= int(request_id
, 16)
76 # Convert the "type" field to a human-readable record type name
77 # using the query_type dictionary.
78 query_type
= int(query_type
, 16) # "001c" -> 28
79 query_type
= QUERY_TYPE_NAME
.get(query_type
) # 28 -> "aaaa"
81 line_tpl
= "{timestamp} "
83 reason
= QUERY_DROP_REASON
[code
]
85 line_tpl
+= "sent response to {ip}:{port} (id {request_id}): "
86 line_tpl
+= "{query_type} {name}"
88 line_tpl
+= "dropped query ({reason}) from {ip}:{port}"
90 # If the query can actually be parsed, the log line is a
91 # bit more informative than it would have been otherwise.
92 line_tpl
+= " (id {request_id}): {query_type} {name}"
94 return line_tpl
.format(timestamp
=timestamp
,
98 request_id
=request_id
,
99 query_type
=query_type
,