Skip to content

Instantly share code, notes, and snippets.

@rfinnie
Last active April 30, 2022 05:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rfinnie/4f9f7f229d368a6a981320792d9ab7e9 to your computer and use it in GitHub Desktop.
Save rfinnie/4f9f7f229d368a6a981320792d9ab7e9 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
import os
import pathlib
import random
import subprocess
import sys
import tempfile
import yaml
BIND_DIR = pathlib.Path("/var/lib/bind/zones")
def process_zone(yaml_file):
with yaml_file.open() as f:
indata = yaml.safe_load(f)
zone = indata["zone"]
zone_ttl = indata.get("ttl", 3600)
intermediate_f = tempfile.NamedTemporaryFile(mode="w")
print("$TTL {}".format(zone_ttl), file=intermediate_f)
for record in indata["records"]:
if isinstance(record, (list, tuple)):
name, record_type, record_data = record
ttl = zone_ttl
record_class = "IN"
else:
name = record["name"]
ttl = record.get("ttl", zone_ttl)
record_class = record.get("class", "IN")
record_type = record["type"]
record_data = record["data"]
if name == "@":
name = zone
elif not name.endswith("."):
name = "{}.{}".format(name, zone)
print(
"{} {} {} {} {}".format(name, ttl, record_class, record_type, record_data),
file=intermediate_f,
)
for key_file in indata.get("key_files", []):
print("$INCLUDE {}".format(key_file), file=intermediate_f)
intermediate_f.flush()
salt = bytearray([random.randint(0, 255) for x in range(8)]).hex()
subprocess.check_call(
[
"dnssec-signzone",
"-A",
"-3",
salt,
"-N",
"UNIXTIME",
"-o",
zone,
"-f",
zone[:-1],
"-t",
intermediate_f.name,
],
cwd=BIND_DIR,
)
if os.environ["USER"] == "root":
print("Do not run as root!", file=sys.stderr)
sys.exit(1)
for fn in sys.argv[1:]:
process_zone(pathlib.Path(fn))
zone: nocache.vsix.us.
ttl: 3600
key_files: [Knocache.vsix.us.+008+41748.key, Knocache.vsix.us.+008+42640.key]
records:
- ['@', SOA, feh.colobox.com. dns.colobox.com. 0 3600 3600 2419200 3600]
- ['@', NS, feh.colobox.com.]
- ['@', NS, cromulent.colobox.com.]
- {name: '@', type: A, data: 67.207.166.26, ttl: 1}
- {name: '@', type: AAAA, data: '2607:f188:0:20::2', ttl: 1}
- {name: '*', type: A, data: 67.207.166.26, ttl: 1}
- {name: '*', type: AAAA, data: '2607:f188:0:20::2', ttl: 1}
#!/usr/bin/env python3
import pathlib
import re
import sys
import yaml
zone = sys.argv[1]
if not zone.endswith("."):
zone = zone + "."
out = {"zone": zone, "ttl": 3600}
key_files = (
list(pathlib.Path("/etc/bind/zones").glob("K{}*.key".format(zone)))
+ list(pathlib.Path("/var/lib/bind/zones").glob("K{}*.key".format(zone)))
+ list(pathlib.Path("/etc/bind/zones/reverse").glob("K{}*.key".format(zone)))
)
if key_files:
out["key_files"] = []
for key_file in key_files:
out["key_files"].append(key_file.name)
out["records"] = []
seen_soa = False
for line in sys.stdin.readlines():
line = line.strip()
if (not line) or line.startswith(";"):
continue
(name, ttl, record_class, record_type, record_data) = re.split(r"[\t ]+", line, 4)
if record_type in ("NSEC3", "RRSIG", "NSEC3PARAM", "DNSKEY"):
continue
if record_type == "SOA":
if seen_soa:
continue
seen_soa = True
if name == out["zone"]:
name = "@"
elif name.endswith(".{}".format(out["zone"])):
name = name[: (0 - len(out["zone"]) - 1)]
ttl = int(ttl)
if ttl == out["ttl"] and record_class == "IN":
record = [name, record_type, record_data]
else:
record = {"name": name, "type": record_type, "data": record_data}
if ttl != out["ttl"]:
record["ttl"] = ttl
if record_class != "IN":
record["class"] = record_class
out["records"].append(record)
out["records"].sort(key=lambda x: (x[0] if isinstance(x, (list, tuple)) else x["name"]))
yaml.dump(out, sys.stdout, default_flow_style=None, sort_keys=False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment