re2o-ns/main.py

272 lines
5.9 KiB
Python
Raw Normal View History

2021-04-04 13:13:30 +02:00
#! /bin/env python3
import argparse
2021-04-04 20:40:46 +02:00
import collections
2021-04-04 13:13:30 +02:00
import configparser
import dns.name
import dns.rdataset
import dns.rdatatype
2021-04-05 18:34:38 +02:00
from dns.rdtypes.ANY import CNAME, DNAME, MX, NS, SOA, SSHFP, TXT
from dns.rdtypes.IN import AAAA, SRV, A
2021-04-04 13:13:30 +02:00
from re2oapi import Re2oAPIClient
def format_rname(mail: str):
"""
Format a email given by re2o API to a rname dnspython object.
Given an email address in the standard string format `mail@example.tld`
return an email address in the format required by RFC 1035
`mail.example.tld.`
Return a `dns.name.Name` object.
"""
2021-04-04 20:40:46 +02:00
local, domain = mail.split("@")
rname = dns.name.Name((local, *dns.name.from_text(domain)))
2021-04-04 20:40:46 +02:00
return rname
2021-04-04 20:40:46 +02:00
def format_mname(name: str):
"""
Format a zone name given by the re2o API to a mname dnspython object.
Given a a name of the format `.zone.domain.tld` output the
2021-04-04 20:46:12 +02:00
`zone.domain.tld.`, formatted accordingly to the RFC 1035.
Return a `dns.name.name` object.
"""
2021-04-04 20:40:46 +02:00
if name[0] == ".":
name = name[1:]
mname = dns.name.from_text(name)
return mname
2021-04-04 20:46:12 +02:00
def soa_handler(zone, records):
"""Handler for SOA record"""
2021-04-05 00:28:23 +02:00
soa = zone["soa"]
2021-04-04 20:40:46 +02:00
2021-04-05 00:28:23 +02:00
records["@"].append(
2021-04-05 18:01:35 +02:00
SOA.SOA(
2021-04-04 20:40:46 +02:00
dns.rdataclass.IN,
dns.rdatatype.SOA,
format_mname(soa["name"]),
format_rname(soa["mail"]),
soa["serial"],
soa["refresh"],
soa["retry"],
soa["expire"],
soa["ttl"],
)
)
2021-04-05 00:28:23 +02:00
2021-04-05 00:32:41 +02:00
def originv4_handler(zone, records):
2021-04-04 20:40:46 +02:00
"""Handler for the IPv4 origin"""
ipv4_addr = zone["originv4"]["ipv4"]
2021-04-05 00:28:23 +02:00
records["@"].append(
2021-04-05 18:01:35 +02:00
A.A(
dns.rdataclass.IN,
dns.rdatatype.A,
ipv4_addr
)
2021-04-05 00:28:23 +02:00
)
2021-04-04 20:40:46 +02:00
def originv6_handler(zone, records):
"""Handler for the IPv6 origin"""
2021-04-04 20:40:46 +02:00
ipv6_addr = zone["originv6"] # Yes, re2o is this weird and inconsistent
2021-04-05 00:28:23 +02:00
records["@"].append(
2021-04-05 18:01:35 +02:00
AAAA.AAAA(
dns.rdataclass.IN,
dns.rdatatype.AAAA,
ipv6_addr
2021-04-05 00:28:40 +02:00
)
2021-04-05 00:28:23 +02:00
)
2021-04-04 20:40:46 +02:00
def ns_records_handler(zone, records):
2021-04-05 00:28:23 +02:00
"""Handler for the NS record"""
2021-04-04 20:40:46 +02:00
for record in zone["ns_records"]:
2021-04-05 00:28:23 +02:00
2021-04-04 20:40:46 +02:00
target = record["target"]
2021-04-04 20:40:46 +02:00
records["@"].append(
2021-04-05 18:01:35 +02:00
NS.NS(
dns.rdataclass.IN,
dns.rdatatype.NS,
target
)
2021-04-04 20:40:46 +02:00
)
2021-04-05 00:28:23 +02:00
2021-04-04 20:40:46 +02:00
def sshfp_record_handler(zone, records):
"""Handler for the SSHFP record"""
2021-04-04 20:40:46 +02:00
for record in zone["sshfp"]:
for fp in record["sshfp"]:
2021-04-05 00:28:23 +02:00
2021-04-04 20:40:46 +02:00
algorithm = fp["algo_id"]
2021-04-04 20:40:46 +02:00
for fp_type in fp["hash"]:
2021-04-05 00:28:23 +02:00
fingerprint = fp["hash"][fp_type]
2021-04-04 20:40:46 +02:00
records[record["hostname"]].append(
2021-04-05 18:01:35 +02:00
SSHFP.SSHFP(
2021-04-04 20:40:46 +02:00
dns.rdataclass.IN,
2021-04-04 20:46:12 +02:00
dns.rdatatype.SSHFP,
2021-04-04 20:40:46 +02:00
algorithm,
fp_type,
2021-04-05 00:28:23 +02:00
fingerprint,
2021-04-04 20:40:46 +02:00
)
)
2021-04-05 00:40:39 +02:00
def mx_records_handler(zone, records):
"""Handler for the MX record"""
for record in zone["mx_records"]:
preference = record["priority"]
exchange = record["target"]
records["@"].append(
2021-04-05 18:01:35 +02:00
MX.MX(
dns.rdataclass.IN,
dns.rdatatype.MX,
preference,
exchange
2021-04-05 00:40:39 +02:00
)
)
2021-04-05 00:28:23 +02:00
2021-04-04 20:40:46 +02:00
def txt_records_handler(zone, records):
"""Handler for TXT record"""
for record in zone["txt_records"]:
2021-04-04 20:46:12 +02:00
name = record["field1"]
2021-04-04 20:40:46 +02:00
2021-04-04 20:46:12 +02:00
records[name].append(
2021-04-05 18:01:35 +02:00
TXT.TXT(
2021-04-05 18:07:28 +02:00
dns.rdataclass.IN,
dns.rdatatype.TXT,
2021-04-05 18:01:35 +02:00
record["field2"]
2021-04-04 20:40:46 +02:00
)
2021-04-05 00:27:01 +02:00
)
2021-04-04 20:40:46 +02:00
2021-04-05 00:28:23 +02:00
2021-04-04 20:40:46 +02:00
def srv_records_handler(zone, records):
"""Handler for SRV record"""
for record in zone["srv_records"]:
name = dns.name.from_text(f"{record['service']}_{record['protocol']}")
name_key = name.to_text()
records[name_key].append(
2021-04-05 18:01:35 +02:00
SRV.SRV(
2021-04-04 20:40:46 +02:00
dns.rdataclass.IN,
dns.rdatatype.SRV,
2021-04-05 00:28:23 +02:00
record["priority"],
record["weight"],
record["port"],
2021-04-05 18:01:35 +02:00
record["target"]
2021-04-04 20:40:46 +02:00
)
)
2021-04-05 00:28:23 +02:00
2021-04-04 20:40:46 +02:00
2021-04-05 00:42:41 +02:00
def a_records_handler(zone, records):
2021-04-04 20:40:46 +02:00
"""Handler for A Record"""
for record in zone["a_records"]:
2021-04-05 00:44:51 +02:00
ipv4_addr = record["ipv4"]
2021-04-04 20:40:46 +02:00
records[record["hostname"]].append(
2021-04-05 18:01:35 +02:00
A.A(
2021-04-04 20:40:46 +02:00
dns.rdataclass.IN,
dns.rdatatype.A,
2021-04-05 18:01:35 +02:00
ipv4_addr
2021-04-05 00:44:51 +02:00
)
)
2021-04-05 00:44:51 +02:00
def aaaa_records_handler(zone, records):
"""Handler for AAAA Record"""
for record in zone["aaaa_records"]:
2021-04-05 18:21:11 +02:00
ipv6_addr = record["ipv6"][0]["ipv6"] # thanks re2o
2021-04-05 00:44:51 +02:00
records[record["hostname"]].append(
2021-04-05 18:01:35 +02:00
AAAA.AAAA(
2021-04-05 00:44:51 +02:00
dns.rdataclass.IN,
dns.rdatatype.AAAA,
2021-04-05 18:01:35 +02:00
ipv6_addr
2021-04-04 20:40:46 +02:00
)
)
def pass_handler(zone, records):
pass
HANDLERS = {
"soa": soa_handler,
"originv4": originv4_handler,
"originv6": originv6_handler,
"ns_records": ns_records_handler,
"sshfp": sshfp_record_handler,
"mx_records": mx_records_handler,
"txt_records": txt_records_handler,
"srv_records": srv_records_handler,
"a_records": a_records_handler,
"aaaa_records": aaaa_records_handler,
"name": pass_handler,
}
2021-04-05 00:28:23 +02:00
2021-04-04 13:13:30 +02:00
parser = argparse.ArgumentParser()
2021-04-04 20:40:46 +02:00
parser.add_argument(
"-c",
"--config",
help="Path to the config file",
type=str,
default="config.ini",
)
2021-04-04 13:13:30 +02:00
args = parser.parse_args()
config = configparser.ConfigParser()
config.read(args.config)
2021-04-04 20:40:46 +02:00
api_client = Re2oAPIClient(
config["Re2o"]["hostname"],
config["Re2o"]["username"],
config["Re2o"]["password"],
use_tls=False,
)
2021-04-04 13:13:30 +02:00
zones = api_client.list("dns/zones")
records = collections.defaultdict(list)
2021-04-04 20:40:46 +02:00
for zone in zones:
2021-04-05 00:56:22 +02:00
for record in zone:
if zone[record]:
# only apply handler if record in not `None` or `[]`
HANDLERS[record](zone, records)