--- /dev/null
+from struct import pack
+
+# A pattern to match the timestamp format that the tai64nlocal program
+# produces. It appears in both dnscache and tinydns lines, after
+# they've been piped through tai64nlocal, of course.
+timestamp_pat = r'[\d-]+ [\d:\.]+'
+
+# A dictionary mapping query type identifiers, in decimal, to their
+# friendly names for tinydns. Reference:
+#
+# https://en.wikipedia.org/wiki/List_of_DNS_record_types
+#
+# Note that mapping here is non-exhaustive, and that tinydns will
+# log responses for record types that it does not know about.
+query_type = {
+ 1: "a",
+ 2: "ns",
+ 5: "cname",
+ 6: "soa",
+ 12: "ptr",
+ 13: "hinfo",
+ 15: "mx",
+ 16: "txt",
+ 17: "rp",
+ 24: "sig",
+ 25: "key",
+ 28: "aaaa",
+ 33: "srv",
+ 35: "naptr",
+ 38: "a6",
+ 48: "dnskey",
+ 52: "tlsa",
+ 65: "https",
+ 252: "axfr",
+ 255: "any",
+ 257: "caa"
+}
+
+def convert_ip(ip : str) -> str:
+ r"""
+ Convert a hex string representing an IP address to
+ human-readable form.
+
+ Parameters
+ ----------
+
+ ip : str
+ The hexadecimal representation of either an IPv4 or an IPv6
+ address.
+
+ Returns
+ -------
+
+ The usual decimal dotted-quad representation is returned for an
+ IPv4 address. IPv6 addresses are returned almost as-is, but with
+ colons inserted in the appropriate places, between every four
+ characters.
+
+ Examples
+ --------
+
+ >>> convert_ip("7f000001")
+ '127.0.0.1'
+ >>> convert_ip("00000000000000000000ffff7f000001")
+ '0000:0000:0000:0000:0000:ffff:7f00:0001'
+ """
+ if len(ip) == 8:
+ # IPv4, eg. "7f000001" -> "7f 00 00 01" -> "127.0.0.1"
+ return ".".join(map(str, pack(">L", int(ip, 16))))
+ elif len(ip) == 32:
+ # IPv6 is actually simpler -- it's just a string-slicing operation.
+ return ":".join([ip[(4*i) : (4*i+4)] for i in range(8)])