#!/usr/bin/env python3 import argparse import dns.rdataclass import dnsmgr import sys def main(): preparser = argparse.ArgumentParser(add_help=False) preparser.add_argument('-b', '--batch', action='store_true') preargs, args = preparser.parse_known_args() nargs = None if preargs.batch else '?' parser = argparse.ArgumentParser(description='Delete DNS records.') parser.add_argument('-a', '--all-zones', help='allow zones that are not managed', action='store_true') parser.add_argument('-A', '--all-types', help='allow unsupported record types', action='store_true') parser.add_argument('-b', '--batch', help='run in batch mode (no user input)', action='store_true') parser.add_argument('-c', '--config', help='path to config file', default=dnsmgr.DEFAULT_CFGFILE) parser.add_argument('zone', metavar='ZONE[@VIEWS]', nargs=nargs, help='DNS zone name and optional list of views (comma separated or asterisk to select all views)', default=None) parser.add_argument('name', metavar='NAME', nargs=nargs, help='DNS record name', default=None) parser.add_argument('type', metavar='TYPE', nargs=nargs, help='DNS record type', default=None) parser.add_argument('value', metavar='VALUE', nargs='*', help='DNS record value, multiple values are choined by a space character', default=None) args = parser.parse_args() try: manager = dnsmgr.DNSManager(cfgfile=args.config) except RuntimeError as e: dnsmgr.printe(f'config: {e}') sys.exit(100) try: if args.zone is None: zones = manager.select_zones(args.all_zones) else: zones = manager.get_zones(args.zone, args.all_zones) for zone in zones: manager.get_zone_content(zone) origin = zones[0].origin if args.name is None: names = sorted(set([name.to_unicode() for name in zone for zone in zones])) rows = [[name] for name in names] index = dnsmgr.prettyselect(['Record name'], rows, prompt='Select record name') args.name = names[index] name = dnsmgr.name_from_text(args.name, origin) for zone in zones: zone.filter_by_name(name, origin) zones = list(filter(lambda zone: zone.nodes, zones)) if not zones: raise RuntimeError(f"No such DNS record -- '{name.to_text(True)}'") if args.type is None: rdtypes = sorted(set([rdataset.rdtype for rdataset in zone.get_node(name) for zone in zones])) if not args.all_types: rdtypes = list(filter(lambda rdtype: rdtype in dnsmgr.RECORD_TYPES, rdtypes)) rdtypes = [rdtype.to_text(rdtype) for rdtype in rdtypes] rows = [[rdtype] for rdtype in rdtypes] index = dnsmgr.prettyselect(['Record type'], rows, prompt='Select record type') args.type = rdtypes[index] rdtype = dnsmgr.type_from_text(args.type, args.all_types) for zone in zones: zone.filter_by_rdtype(rdtype) zones = list(filter(lambda zone: zone.nodes, zones)) if not zones: raise RuntimeError(f"No such {rdtype.to_text(rdtype)} record -- '{name.to_text(True)}'") rdata = None if not args.value and not args.batch and not dnsmgr.input_yes_no(f'Delete all {rdtype.to_text(rdtype)}-records?'): values = [] for zone in zones: for rdataset in zone.get_node(name): for rdata in rdataset: values.append(rdata.to_text(origin=zone.origin, relativize=False)) values = sorted(set(values)) rows = [[value] for value in values] index = dnsmgr.prettyselect(['Record value'], rows, prompt='Select record value', truncate=True) args.value = [values[index]] if args.value: value = ' '.join(args.value) rdata = dnsmgr.rdata_from_text(rdtype, value, origin) for zone in zones: zone.filter_by_rdata(rdata) zones = list(filter(lambda zone: zone.nodes, zones)) if not zones: raise RuntimeError(f"No such DNS record found -- {name.to_text(True)} IN {rdtype.to_text(rdtype)} {value}") except RuntimeError as e: dnsmgr.printe(e) sys.exit(150) except KeyboardInterrupt: sys.exit(0) zones.sort(key=lambda zone: zone.view) if not args.batch: for zone in zones: print(f'View: {zone.view}') node = zone.find_node(name) rdataset = node.find_rdataset(dns.rdataclass.IN, rdtype) rdclassstr = rdataset.rdclass.to_text(rdataset.rdclass) rdtypestr = rdataset.rdtype.to_text(rdataset.rdtype) for rdata in rdataset: text = rdata.to_text(origin=zone.origin, relativize=False) print(f'\033[31m- {name} {rdataset.ttl} {rdclassstr} {rdtypestr} {text}\033[0m\n') if not dnsmgr.input_yes_no(): sys.exit(0) for zone in zones: origin = zone.origin.to_text(omit_final_dot=True) if len(zones) > 1 or zone.view != dnsmgr.NAMED_DEFAULT_VIEW: origin = f'{origin}@{zone.view}' print(f"Sending DDNS updates for '{origin}'... ", end='') node = zone.find_node(name) rdataset = node.find_rdataset(dns.rdataclass.IN, rdtype) try: manager.delete_zone_record(zone, name, rdataset) print('OK') except RuntimeError as e: dnsmgr.printe(e) sys.exit(160) if __name__ == '__main__': main()