def main(): parser = argparse.ArgumentParser( description='Extract zonefiles from named.conf.') parser.add_argument('named_conf', metavar='FILE', type=str, nargs=1, help='the named.conf to parse') parser.add_argument('-w', '--write', metavar='DIR', type=str, help='Wwrite each extracted zonefile as its own file' ' in DIR') parser.add_argument('-v', '--verbose', action='store_true', help='verbose output') args = parser.parse_args() if args.verbose: LOG.setLevel(logging.INFO) else: LOG.setLevel(logging.WARNING) try: x = Extractor(args.named_conf[0]) for zone in x.extract(): if args.write is not None: zone.to_file(args.write) else: zone.to_stdout() except IOError as e: LOG.error(e)
def deleteHost(self, host): """ Delete host. @param host string: host """ host = host.rstrip(".") map = self.map record = map.get(host) if not record: raise j.exceptions.RuntimeError("Invalid host name") for r in record: file = r["file"] old_ip = r["ip"] zone = dns.zone.from_file(file, os.path.basename(file), relativize=False) for k, v in zone.nodes.copy().items(): if k.to_text() == "%s." % host: zone.delete_node(k) # update version for k, v in zone.nodes.items(): for ds in v.rdatasets: if ds.rdtype == dns.rdatatype.SOA: for item in ds.items: item.serial += 1 zone.to_file(file, relativize=False) self.restart()
def updateHostIp(self, host, ip): """ Update the IP of a host. @param host string: hostname @param ip string: ip """ map = self.map record = map.get(host) if not record: raise j.exceptions.RuntimeError("Invalid host name") for r in record: file = r["file"] old_ip = r["ip"] zone = dns.zone.from_file(file, os.path.basename(file), relativize=False) for k, v in zone.items(): for dataset in v.rdatasets: for item in dataset.items: if hasattr(item, "address") and item.address == old_ip: item.address = ip zone.to_file(file) self.restart()
def addRecord(self, domain, host, ip, klass, type, ttl): host = "%s." % host records = [x for x in self.zones if x.domain == domain] if not records: raise RuntimeError("Invalid domain") record = records[0] file = record.file zone = dns.zone.from_file(file, os.path.basename(file),relativize=False) node = zone.get_node(host, create=True) if type == "A": t = dns.rdatatype.A if klass == "IN": k = dns.rdataclass.IN ds = node.get_rdataset(t, k, covers=dns.rdatatype.NONE, create=True) ds.ttl = ttl if type == "A" and klass == "IN": item = A(k, t, ip) ds.items.append(item) # update version for k, v in zone.nodes.iteritems(): for ds in v.rdatasets: if ds.rdtype == dns.rdatatype.SOA: for item in ds.items: item.serial += 1 zone.to_file(file, relativize=False) self.restart()
def zone_to_text(zone): after_tmp = tempfile.TemporaryFile(mode='w+t') zone.to_file(after_tmp, sorted=config.dnssec_order, relativize=config.relativize_zones) after_tmp.seek(0) after = after_tmp.read() after_tmp.close() return after
def modify_dns(new_IP): domain = "cap.com" zoneFile = "/etc/bind/zones/db.cap.com" zone = dns.zone.from_file(zoneFile, domain) change = "www" rdataset = zone.find_rdataset(change, rdtype='A') req_reload = False for rdata in rdataset: if rdata.address != new_IP: req_reload = True rdata.address = new_IP if req_reload: for (name, ttl, rdata) in zone.iterate_rdatas('SOA'): serial = rdata.serial + 1 rdata.serial = serial zone.to_file(zoneFile) proc = Popen(["rndc", "reload", "cap.com"], stdout = PIPE, stderr = PIPE) out,err = proc.communicate() if err: print err else: pass #print "DNS zone modification complete" else: pass
def addRecord(self, domain, host, ip, klass, type, ttl): host = "%s." % host records = [x for x in self.zones if x.domain == domain] if not records: raise RuntimeError("Invalid domain") record = records[0] file = record.file zone = dns.zone.from_file(file, os.path.basename(file), relativize=False) node = zone.get_node(host, create=True) if type == "A": t = dns.rdatatype.A if klass == "IN": k = dns.rdataclass.IN ds = node.get_rdataset(t, k, covers=dns.rdatatype.NONE, create=True) ds.ttl = ttl if type == "A" and klass == "IN": item = A(k, t, ip) ds.items.append(item) # update version for k, v in zone.nodes.iteritems(): for ds in v.rdatasets: if ds.rdtype == dns.rdatatype.SOA: for item in ds.items: item.serial += 1 zone.to_file(file, relativize=False) self.restart()
def run(self): zone = dns.zone.from_xfr(dns.query.xfr(**self.config["query"]), **self.config["zone"]) if self.save: if not os.isdir("./dns-zones"): os.mkdir("./dns-zones/") zone.to_file(f"./dns-zones/{self.name}.txt", sorted=True) else: print(colored(zone.to_text().decode("ascii"), dark=True))
def main(): """ Main function, typically invoked by the __name__ check. """ description = 'Create and verify ZONEMD digest in zone files.' parser = argparse.ArgumentParser(description=description) parser.add_argument('--check', '-c', action='store_true', help="check ZONEMD in zone file") parser.add_argument('--algorithm', '-a', help="set algorithm to use (defaults to sha384)", choices=(['sha384', 'sha512']), default='sha384') parser.add_argument('--generic', '-g', action='store_true', help="treat ZONEMD as an unknown type (RFC 3597)") parser.add_argument('--placeholder', '-p', action='store_true', help='output a placeholder digest') parser.add_argument('--origin', '-o', type=str, default=".", help="zone origin") parser.add_argument('filename', nargs='+') args = parser.parse_args() # pylint: disable=protected-access if args.generic: zonemd.ZONEMD_AS_GENERIC = True else: # Monkey-patch the dns.rdatatype module so we use the # presentation format. dns.rdatatype._by_value[zonemd.ZONEMD_RTYPE] = "ZONEMD" dns.rdatatype._by_text["ZONEMD"] = zonemd.ZONEMD_RTYPE dns.rdtypes.ANY.__all__.append("ZONEMD") mod_tuple = (dns.rdataclass.IN, zonemd.ZONEMD_RTYPE) dns.rdata._rdata_modules[mod_tuple] = zonemd exit_code = 0 for filename in args.filename: zone = dns.zone.from_file(filename, check_origin=False, relativize=False, origin=args.origin) if args.check: okay, err = zonemd.validate_zonemd(zone) if okay: print(f"{filename} has a valid digest") else: print(f"{filename} does NOT have a valid digest: {err}") exit_code = 1 else: zone_rr = zonemd.add_zonemd(zone, zonemd_algorithm=args.algorithm) if not args.placeholder: zone_rr = zonemd.update_zonemd(zone, zonemd_algorithm=args.algorithm) digest_hex = binascii.b2a_hex(zone_rr.digest).decode() zonemd_filename = filename + ".zonemd" with open(zonemd_filename, "w") as output_fp: zone.to_file(output_fp, relativize=False) print(f"Wrote ZONEMD digest {digest_hex} to {zonemd_filename}") sys.exit(exit_code)
def dnszone (account): zone_file = "/etc/bind/db.local" domain = "localhost" try: zone = dns.zone.from_file(zone_file, domain) for (name, ttl, rdata) in zone.iterate_rdatas(SOA): print rdata serial = rdata.serial new_serial = datetime.now().strftime("%Y%m%d%H%M%S") print "Changing SOA serial from %s to %s" % (serial, new_serial) rdata.serial = int(new_serial) rdata.mname = dns.name.Name(("ns1", "codeless-hosting", "co", "")) print "Adding record of type A:", account.domain NS_add = "@" target = dns.name.Name(("ns1", "codeless-hosting", "co", "")) print "Adding record of type NS:", NS_add rdataset = zone.find_rdataset(NS_add, rdtype=NS, create=True) rdata = dns.rdtypes.ANY.NS.NS(IN, NS, target) rdataset.add(rdata, ttl=86400) rdataset = zone.find_rdataset("www", rdtype=A, create=True) rdata = dns.rdtypes.IN.A.A(IN, A, address="192.168.1.30") rdataset.add(rdata, ttl=86400) new_zone_file = "/etc/bind/zones/db.%s" % account.domain zone.to_file(new_zone_file) except DNSException, e: print e
def delete(hostname=None, UUID=None): if mongo.db.users.find_one({'token': UUID}): zonefile = '/etc/bind/db.example.com' zone = dns.zone.from_file(zonefile, os.path.basename(zonefile)) zone.delete_rdataset(hostname, dns.rdatatype.A) # restart bind for changes to take effect subprocess.call(["sudo", "rndc", "reload"]) zone.to_file(zonefile) mongo.db.users.update({'username': session['username']}, {'$pull': { 'fqdns': hostname }}) return {"message": "A-record removed hostname {}".format(hostname)} else: return {"message": "not authorized"}
def write_bind_zone_file(self, ip_list: list) -> None: zone_origin = f"rev.{self.domain}" zone = dns.zone.Zone(origin=zone_origin) zone = self._add_bind_common(zone) for ip in ip_list: zone = self._add_to_zone( zone, f"{ip.exploded.replace(':', '-')}.rev.{self.domain}.", "AAAA", ip.exploded, ) zone.to_file(f"{self.config_folder}/{zone_origin}")
def update_domain(domain, zonefile, secret): ''' Updates the given domain with the new ACME secret. ''' zone = dns.zone.from_file(zonefile, domain) # updata soa serial for (_, _, rdata) in zone.iterate_rdatas(SOA): rdata.serial += 1 # update the acme challenge acme_record = zone.find_rdataset('_acme-challenge', rdtype=TXT) for rdata in acme_record: rdata.strings = [secret.encode("utf8")] zone.to_file(zonefile)
def updateHostIp(self, host, ip): map = self.map record = map.get(host) if not record: raise RuntimeError("Invalid host name") for r in record: file = r['file'] old_ip = r['ip'] zone = dns.zone.from_file(file, os.path.basename(file),relativize=False) for k, v in zone.iteritems(): for dataset in v.rdatasets: for item in dataset.items: if hasattr(item, 'address') and item.address == old_ip: item.address = ip zone.to_file(file) self.restart()
def generate(self, domains: Iterable[str], filename: str): ttl = 3600 origin = "rpz.local" def read_header(): with open(filename, "r") as f: for line in f: if not line.startswith("@"): break yield line try: # Read "header" only since it's expensive to parse everything. zone = dns.zone.from_text("\n".join(read_header()), origin=origin) except (dns.exception.DNSException, IOError): zone = dns.zone.Zone(origin) existing_soa_set = zone.get_rdataset("@", "SOA") zone.nodes.clear() soa_set = zone.find_rdataset("@", "SOA", create=True) if existing_soa_set is None: soa_set.ttl = 3600 soa_set.add( dns.rdata.from_text("IN", "SOA", "@ hostmaster 0 86400 7200 2592000 86400")) logging.info("creating zone from scratch") else: soa_set.update(existing_soa_set) # Increment serial. serial = soa_set[0].serial + 1 soa_set.add(soa_set[0].replace(serial=serial)) logging.info("parsed existing header, new serial is %d", serial) in_ns = zone.find_rdataset("@", "NS", create=True) in_ns.ttl = ttl in_ns.add(dns.rdata.from_text("IN", "NS", "LOCALHOST.")) in_cname_dot = dns.rdataset.from_text("IN", "CNAME", ttl, ".") for domain in domains: zone.find_node(domain, create=True).replace_rdataset(in_cname_dot) zone.to_file(filename, sorted=True) logging.info("block list has %d domains", len(zone.nodes) - 1)
def write_ptr_zone_file(self, ip_list: list) -> None: """ Function writes a BIND configuration file for the reverse DNS entry of the network """ zone_origin = self._retrive_zone_origin(self.network) zone = dns.zone.Zone(origin=zone_origin) zone = self._add_bind_common(zone) for ip in ip_list: zone = self._add_to_zone( zone, f"{ip.reverse_pointer}.", "PTR", f"{ip.exploded.replace(':', '-')}.rev.{self.domain}.", ) zone.to_file(f"{self.config_folder}/{zone_origin}")
def updateHostIp(self, host, ip): map = self.map record = map.get(host) if not record: raise RuntimeError("Invalid host name") for r in record: file = r['file'] old_ip = r['ip'] zone = dns.zone.from_file(file, os.path.basename(file), relativize=False) for k, v in zone.iteritems(): for dataset in v.rdatasets: for item in dataset.items: if hasattr(item, 'address') and item.address == old_ip: item.address = ip zone.to_file(file) self.restart()
def _apply(self, plan): ''' Arguments ========= plan: octodns.provider.plan.Plan ''' zone = dns.zone.Zone(plan.desired.name) soaset = dns.rdataset.Rdataset(dns.rdataclass.IN, dns.rdatatype.SOA) soaset.add( _create_rdata(dns.rdataclass.IN, dns.rdatatype.SOA, self.soa), self.soa_ttl) zone.replace_rdataset('@', soaset) for record in plan.desired.records: data = record.data name = record.name rdset = dns.rdataset.Rdataset( dns.rdataclass.IN, dns.rdatatype.from_text(record._type)) if 'value' in data: rdset.add(_create_rdata(dns.rdataclass.IN, dns.rdatatype.from_text(record._type), data['value']), ttl=int(data['ttl'])) elif 'values' in data: for value in data['values']: rdset.add(_create_rdata( dns.rdataclass.IN, dns.rdatatype.from_text(record._type), value), ttl=int(data['ttl'])) else: self.log.warning( "neither value nor values found in {}".format(name)) continue zone.replace_rdataset(name, rdset) zone.to_file(self.directory + '/' + plan.desired.name + self.file_extension)
def append(ip_adres=None, hostname=None, UUID=None): if mongo.db.users.find_one({'token': UUID}): zonefile = '/etc/bind/db.example.com' zone = dns.zone.from_file(zonefile, os.path.basename(zonefile)) rdataset = zone.find_rdataset(hostname, dns.rdatatype.A, create=True) rdata = dns.rdtypes.IN.A.A(dns.rdataclass.IN, dns.rdatatype.A, ip_adres) rdataset.add(rdata, 86400) zone.to_file(zonefile) subprocess.call(["sudo", "rndc", "reload"]) filter = {'username': session['username']} update = {"$push": {"fqdns": hostname}} mongo.db.users.update_one(filter, update) return { "message": "new A-record with ip {} and hostname {} inserted".format( ip_adres, hostname) } else: return {"message": "not authorized"}
def main(): parser = argparse.ArgumentParser(description="Extract zonefiles from named.conf.") parser.add_argument("named_conf", metavar="FILE", type=str, nargs=1, help="the named.conf to parse") parser.add_argument( "-w", "--write", metavar="DIR", type=str, help="Wwrite each extracted zonefile as its own file" " in DIR" ) parser.add_argument("-v", "--verbose", action="store_true", help="verbose output") args = parser.parse_args() if args.verbose: LOG.setLevel(logging.INFO) else: LOG.setLevel(logging.WARNING) try: x = Extractor(args.named_conf[0]) for zone in x.extract(): if args.write is not None: zone.to_file(args.write) else: zone.to_stdout() except IOError as e: LOG.error(e)
def deleteHost(self, host): host = host.rstrip('.') map = self.map record = map.get(host) if not record: raise RuntimeError("Invalid host name") for r in record: file = r['file'] old_ip = r['ip'] zone = dns.zone.from_file(file, os.path.basename(file),relativize=False) for k, v in zone.nodes.copy().iteritems(): if k.to_text() == "%s." % host: zone.delete_node(k) # update version for k, v in zone.nodes.iteritems(): for ds in v.rdatasets: if ds.rdtype == dns.rdatatype.SOA: for item in ds.items: item.serial += 1 zone.to_file(file, relativize=False) self.restart()
if options.output_format == "dns": zone = zeroconf_to_zone(target_zone=options.target_zone, target_ns=options.zone_xfr_from, zeroconf_results=results, locmap=eval(options.location_map), priomap=eval(options.priority_map), ttl=options.ttl) elif options.output_format == "json": zone = zeroconf_to_json(zeroconf_results=results) if not zone: sys.exit() if cgi_mode: print 'Content-Type: text/{format}' % options.output_format print if options.output_format == "dns": if options.output_rrset: zone.delete_node('@') zone.to_file(sys.stdout) elif options.output_format == "json": print zone except: if cgi_mode: print 'Content-Type: text/plain' print raise
def writeZone(ctxt, zone, fp): fp.write(';; -*- coding: utf-8{config} -*-\n'.format( config=(('; dnssync-config: ' + ctxt.config) if ctxt.config else ''))) fp.write('$ORIGIN {domain}\n'.format(domain=ctxt.domain)) zone.to_file(fp, relativize=False)
return dns.zone.from_text(zone_text, origin) def update_serial(zone): soa = zone.get_rdataset('@', dns.rdatatype.SOA)[0] soa.serial += 1 def usage(code=0): print('Usage: update-zonefile.py zonefile origin') exit(code) if len(sys.argv) != 3: usage(1) zonefile = sys.argv[1] origin = sys.argv[2] zone = load_zone(zonefile, origin) update_serial(zone) domains = parse_lists(origin) zone.to_file(zonefile) with Path(zonefile).open('a') as f: for d in (sorted(domains)): f.write(d + ' IN CNAME drop.sinkhole.\n') if config['wildcard_block']: f.write('*.' + d + ' IN CNAME drop.sinkhole.\n') print("Done")
def write_zone_to_file(zone_file, zone, absolute_names): zone.to_file(zone_file, sorted=True, relativize=(not absolute_names))
new_serial = serial + 1 print "Cambiando serial del SOA de %d a %d" % (serial, new_serial) rdata.serial = new_serial node_delete = "www2" print "Eliminando nodo", node_delete zone.delete_node(node_delete) A_change = "mail" new_IP = "192.168.2.100" print "Cambiando IPV4 del nodo", A_change, "al", new_IP rdataset = zone.find_rdataset(A_change, rdtype=A) for rdata in rdataset: rdata.address = new_IP rdataset = zone.find_rdataset("@", rdtype=NS) new_ttl = rdataset.ttl / 2 print "Cambiando el TTL de todos los NS a", new_ttl rdataset.ttl = new_ttl A_add = "www3" print "Añadir nuevo nodo www3:", A_add rdataset = zone.find_rdataset(A_add, rdtype=A, create=True) rdata = dns.rdtypes.IN.A.A(IN, A, address="192.168.10.30") rdataset.add(rdata, ttl=86400) new_zone_file = "new.%s" % domain zone.to_file(new_zone_file) except DNSException, e: print e.__class__, e
def cmd_export(args, r53): zone = _get_records(args, r53) print '$ORIGIN %s' % zone.origin.to_text() zone.to_file(sys.stdout, relativize=not args.full)
class commands: def __init__(self, simplicify): self.config = simplicify.SimplicifyConfig def ls_SRV(self, service_name): """ Note: This function retrieves all configured S Args: service_name: The symbolic name of the desired service, as defined in Assigned Numbers [STD 2] or locally. An underscore (_) is prepended to the service identifier to avoid collisions with DNS labels that occur in nature. Returns: returns: Array containing the program status code, http status code, humanly readable explanation, and payload """ # Define the response of a successful execution of the function http_status = 200 prog_status = 0 explanation = "Successfully listed all service records with the specified service name ({})".format( service_name) try: response = dns.resolver.query(service_name, 'SRV') except: explanation = "An unknown error occurred listing records for the specified service ({})".format( service_name) status = 500 return [1, status, explanation, ""] results_list = [] for rdata in response: results_list.append(str(rdata.target).rstrip('.')) payload = results_list returns = [prog_status, http_status, explanation, payload] return returns def ls_A(self, dns_name): """ Note: This function retrieves all configured S Args: service_name: The symbolic name of the desired service, as defined in Assigned Numbers [STD 2] or locally. An underscore (_) is prepended to the service identifier to avoid collisions with DNS labels that occur in nature. Returns: returns: Array containing the program status code, http status code, humanly readable explanation, and payload """ # Define the response of a successful execution of the function http_status = 200 prog_status = 0 explanation = "Successfully listed all service records with the specified DNS name ({})".format( dns_name) try: response = dns.resolver.query(dns_name, 'A') except: explanation = "An unknown error occurred listing records for the specified DNS name ({})".format( dns_name) status = 500 return [1, status, explanation, ""] results_list = [] for rdata in response: results_list.append(str(rdata)) payload = results_list returns = [prog_status, http_status, explanation, payload] return returns def create_A(self, record_name, ip_address): """ Note: This function creates an A record on a bind9 DNS server Args: record_name: FQDN for record Returns: returns: Array containing the program status code, http status code, humanly readable explanation, and payload """ # Define the response of a successful execution of the function http_status = 200 prog_status = 0 explanation = "Successfully created specified A record ({})".format( record_name) domain = "simplicify.com" print "Getting zone object for domain", domain zone_file = "/etc/bind/zones/db.%s" % domain try: zone = dns.zone.from_file(zone_file, domain) print "Zone origin:", zone.origin except DNSException, e: print e.__class__, e rdataset = zone.find_rdataset(record_name, rdtype=A, create=True) rdata = dns.rdtypes.IN.A.A(IN, A, address=ip_address) rdataset.add(rdata, ttl=86400) new_zone_file = "new.db.%s" % domain try: zone.to_file(new_zone_file) except: explanation = "An unknown error occurred adding the specified A record ({})".format( dns_name) status = 500 return [1, status, explanation, ""] payload = "" returns = { "prog_status": prog_status, "http_status": http_status, "explanation": explanation, "payload": payload } return returns
def generate_zone_file(origin): """Generates a zone file. Accepts the zone origin as string (no trailing dot). Returns the contents of a zone file that contains all the resource records associated with the domain with the provided origin. """ Domain = cache.get_model('powerdns_manager', 'Domain') Record = cache.get_model('powerdns_manager', 'Record') the_domain = Domain.objects.get(name__exact=origin) the_rrs = Record.objects.filter(domain=the_domain).order_by('-type') # Generate the zone file origin = Name((origin.rstrip('.') + '.').split('.')) # Create an empty dns.zone object. # We set check_origin=False because the zone contains no records. zone = dns.zone.from_text('', origin=origin, relativize=False, check_origin=False) rdclass = dns.rdataclass._by_text.get('IN') for rr in the_rrs: # Add trailing dot to rr.name record_name = rr.name.rstrip('.') + '.' if rr.type == 'SOA': # Add SOA Resource Record # SOA content: primary hostmaster serial refresh retry expire default_ttl bits = rr.content.split() # Primary nameserver of SOA record primary = bits[0].rstrip('.') + '.' mname = Name(primary.split('.')) # Responsible hostmaster from SOA record hostmaster = bits[1].rstrip('.') + '.' rname = Name(hostmaster.split('.')) rdtype = dns.rdatatype._by_text.get('SOA') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.SOA.SOA(rdclass, rdtype, mname = mname, rname = rname, serial = int(bits[2]), refresh = int(bits[3]), retry = int(bits[4]), expire = int(bits[5]), minimum = int(bits[6]) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'NS': # Add NS Resource Record rdtype = dns.rdatatype._by_text.get('NS') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.NS.NS(rdclass, rdtype, target = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'MX': # Add MX Resource Record rdtype = dns.rdatatype._by_text.get('MX') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.MX.MX(rdclass, rdtype, preference = int(rr.prio), exchange = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'TXT': # Add TXT Resource Record rdtype = dns.rdatatype._by_text.get('TXT') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.TXT.TXT(rdclass, rdtype, strings = rr.content.split(';') ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'CNAME': # Add CNAME Resource Record rdtype = dns.rdatatype._by_text.get('CNAME') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.CNAME.CNAME(rdclass, rdtype, target = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'A': # Add A Resource Record rdtype = dns.rdatatype._by_text.get('A') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.IN.A.A(rdclass, rdtype, address = rr.content ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'AAAA': # Add AAAA Resource Record rdtype = dns.rdatatype._by_text.get('AAAA') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.IN.AAAA.AAAA(rdclass, rdtype, address = rr.content ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'SPF': # Add SPF Resource Record rdtype = dns.rdatatype._by_text.get('SPF') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.SPF.SPF(rdclass, rdtype, strings = rr.content.split(';') ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'PTR': # Add PTR Resource Record rdtype = dns.rdatatype._by_text.get('PTR') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.PTR.PTR(rdclass, rdtype, target = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'SRV': # Add SRV Resource Record # weight port target weight, port, target = rr.content.split() rdtype = dns.rdatatype._by_text.get('SRV') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.IN.SRV.SRV(rdclass, rdtype, priority = int(rr.prio), weight = int(weight), port = int(port), target = Name((target.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) # Export text (from the source code of http://www.dnspython.org/docs/1.10.0/html/dns.zone.Zone-class.html#to_file) EOL = '\r\n' f = StringIO.StringIO() f.write('$ORIGIN %s%s' % (origin, EOL)) zone.to_file(f, sorted=True, relativize=False, nl=EOL) data = f.getvalue() f.close() return data
def cmd_export(args): zone = _get_records(args) zone.to_file(sys.stdout)
# Define the response of a successful execution of the function http_status = 200 prog_status = 0 explanation = "Successfully created specified SRV record (Service: {} Port: {} A Record: {})".format(service_name, service_port, A_record) domain = "simplicify.com" zone_file = "/etc/bind/zones/db.%s" % domain new_zone_file = "new.db.%s" % domain try: zone = dns.zone.from_file(zone_file, domain) except DNSException, e: print e.__class__, e n = dns.name.from_text(A_record) rdataset = zone.find_rdataset(service_name, rdtype='SRV', create=True) rdata = dns.rdtypes.IN.SRV.SRV(IN,SRV,0,0,service_port,target=n) rdataset.add(rdata, ttl=86400) print str(rdataset) print str(rdata) try: zone.to_file(new_zone_file) except: explanation = "An unknown error occurred adding the specified SRV record (Service: {} Port: {} A Record: {})".format(service_name, service_port, A_record) status = 500 return [ 1, status, explanation, "" ] payload = "" returns = [ prog_status, http_status, explanation, payload ] return returns
def main_process(self): """Main process editzone """ def clean_up(): if (tmp_file): os.unlink(tmp_file) tmp_file = '' # Get update session object error_str = '' try: update_session = DynDNSUpdate(settings['dns_server'], settings['dyndns_key_file'], settings['dyndns_key_name'], ) except (socket.error, DynDNSCantReadKeyError, IOError) as exc: error_str = str(exc) # Process above error... if (error_str): log_error("%s" % error_str) sys.exit(os.EX_NOHOST) # Do AXFR to obtain current zone data msg = None try: (zone, dnskey_flag, nesc3param_flag) \ = update_session.read_zone(self.zone_name) except NoSuchZoneOnServerError as exc: msg = str(exc) if msg: log_error(msg) sys.exit(os.EX_NOINPUT) # Only edit zone if not wrapping SOA serial number if (not settings['wrap_serial'] and not settings['update_serial'] and not settings['nsec3_seed'] and not settings['clear_nsec3'] and not settings['clear_dnskey']): # Write zone out to a temporary file (fd, tmp_file) = tempfile.mkstemp(prefix=settings['process_name'] + '-', suffix='.zone') os.close(fd) zone.to_file(tmp_file) # Edit zone data old_stat = os.stat(tmp_file) editor = self._get_editor() try: output = check_call([editor, tmp_file]) except CalledProcessError as exc: log_error("editor exited with '%s'." % exc.returncode) sys.exit(os.EX_SOFTWARE) new_stat = os.stat(tmp_file) if (not settings['force_update'] and old_stat[stat.ST_MTIME] == new_stat[stat.ST_MTIME] and old_stat[stat.ST_SIZE] == new_stat[stat.ST_SIZE] and old_stat[stat.ST_INO] == new_stat[stat.ST_INO]): log_info("File '%s' unchanged after editing - exiting." % tmp_file) clean_up() sys.exit(os.EX_OK) # Read in file and form zi structure zone = dns.zone.from_file(tmp_file, self.zone_name) # At the moment these values are just for the sake of it. zi = ZoneInstance(soa_refresh='5m', soa_retry='5m', soa_expire='7d', soa_minimum='600') for rdata in zone.iterate_rdatas(): zi.add_rr(dnspython_to_rr(rdata)) # Update Zone in DNS rcode, msg, soa_serial, *stuff = update_session.update_zone( self.zone_name, zi, force_soa_serial_update=not(settings['no_serial']), wrap_serial_next_time=settings['wrap_serial'], nsec3_seed=settings['nsec3_seed'], clear_nsec3=settings['clear_nsec3'], clear_dnskey=settings['clear_dnskey'] ) if rcode == RCODE_NOCHANGE: log_info(msg) sys.exit(os.EX_OK) # Delete temporary file clean_up() if rcode == RCODE_ERROR: log_warning(msg) sys.exit(os.EX_TEMPFAIL) elif rcode == RCODE_RESET: log_error(msg) sys.exit(os.EX_IOERR) elif rcode == RCODE_FATAL: log_error(msg) sys.exit(os.EX_IOERR) # Everything good - Lets GO! if (settings['verbose']): log_info(msg) else: log_debug(msg) sys.exit(os.EX_OK)
def generate_zone_file(origin): """Generates a zone file. Accepts the zone origin as string (no trailing dot). Returns the contents of a zone file that contains all the resource records associated with the domain with the provided origin. """ Domain = get_model('powerdns_manager', 'Domain') Record = get_model('powerdns_manager', 'Record') the_domain = Domain.objects.get(name__exact=origin) the_rrs = Record.objects.filter(domain=the_domain).order_by('-type') # Generate the zone file origin = Name((origin.rstrip('.') + '.').split('.')) # Create an empty dns.zone object. # We set check_origin=False because the zone contains no records. zone = dns.zone.from_text('', origin=origin, relativize=False, check_origin=False) rdclass = dns.rdataclass._by_text.get('IN') for rr in the_rrs: # Add trailing dot to rr.name record_name = rr.name.rstrip('.') + '.' if rr.type == 'SOA': # Add SOA Resource Record # SOA content: primary hostmaster serial refresh retry expire default_ttl bits = rr.content.split() # Primary nameserver of SOA record primary = bits[0].rstrip('.') + '.' mname = Name(primary.split('.')) # Responsible hostmaster from SOA record hostmaster = bits[1].rstrip('.') + '.' rname = Name(hostmaster.split('.')) rdtype = dns.rdatatype._by_text.get('SOA') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.SOA.SOA(rdclass, rdtype, mname = mname, rname = rname, serial = int(bits[2]), refresh = int(bits[3]), retry = int(bits[4]), expire = int(bits[5]), minimum = int(bits[6]) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'NS': # Add NS Resource Record rdtype = dns.rdatatype._by_text.get('NS') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.NS.NS(rdclass, rdtype, target = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'MX': # Add MX Resource Record rdtype = dns.rdatatype._by_text.get('MX') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.MX.MX(rdclass, rdtype, preference = int(rr.prio), exchange = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'TXT': # Add TXT Resource Record rdtype = dns.rdatatype._by_text.get('TXT') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.TXT.TXT(rdclass, rdtype, strings = [rr.content.strip('"')] ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'CNAME': # Add CNAME Resource Record rdtype = dns.rdatatype._by_text.get('CNAME') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.CNAME.CNAME(rdclass, rdtype, target = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'A': # Add A Resource Record rdtype = dns.rdatatype._by_text.get('A') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.IN.A.A(rdclass, rdtype, address = rr.content ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'AAAA': # Add AAAA Resource Record rdtype = dns.rdatatype._by_text.get('AAAA') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.IN.AAAA.AAAA(rdclass, rdtype, address = rr.content ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'SPF': # Add SPF Resource Record rdtype = dns.rdatatype._by_text.get('SPF') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.SPF.SPF(rdclass, rdtype, strings = [rr.content.strip('"')] ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'PTR': # Add PTR Resource Record rdtype = dns.rdatatype._by_text.get('PTR') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.ANY.PTR.PTR(rdclass, rdtype, target = Name((rr.content.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) elif rr.type == 'SRV': # Add SRV Resource Record # weight port target weight, port, target = rr.content.split() rdtype = dns.rdatatype._by_text.get('SRV') rdataset = zone.find_rdataset(record_name, rdtype=rdtype, create=True) rdata = dns.rdtypes.IN.SRV.SRV(rdclass, rdtype, priority = int(rr.prio), weight = int(weight), port = int(port), target = Name((target.rstrip('.') + '.').split('.')) ) rdataset.add(rdata, ttl=int(rr.ttl)) # Export text (from the source code of http://www.dnspython.org/docs/1.10.0/html/dns.zone.Zone-class.html#to_file) EOL = '\n' f = StringIO.StringIO() f.write('$ORIGIN %s%s' % (origin, EOL)) zone.to_file(f, sorted=True, relativize=False, nl=EOL) data = f.getvalue() f.close() return data
def _check_zones(zone_list, add_rrsets, delete_rrsets): """Apply changes to zones and run named-checkzone. This function always returns None. Its only effect is to raise an exception if the updates cause named-checkzone to fail. This function will check to ensure that deleted records existed previously, and added records did not exist. This duplicates the checks built into the DNS UPDATE message, but this is necessary because relying only on the DNS UPDATE constraints could mean that updates to one zone get processed but updates to another get rejected. We want to try as hard as possible to make this all-or-nothing. """ zones = {} # Acquire a copy of each zone. for zone in zone_list: axfr = dns.query.xfr(jinx_global_settings['DNS_NAMESERVER'], zone, relativize=False, port=int(jinx_global_settings['DNS_NAMESERVER_PORT'])) zones[zone] = dns.zone.from_xfr(axfr, relativize=False) # Apply the updates. for rrset in delete_rrsets: zone = zones[_get_zone(rrset.name, zone_list)] new = _rrset_to_rdataset(rrset) existing = zone.get_rdataset(rrset.name, rrset.rdtype) # Are we deleting or modifying? If an RRset with this name is in the # add group, then it's actually a modification. if rrset.name in [r.name for r in add_rrsets]: action = "modify" else: action = "delete" if existing is None: raise JinxInvalidStateError("You are attempting to %s %s, but this record does not exist in DNS." % (action, _format_rrset_name(rrset))) elif not _rdatasets_are_equal(new, existing): raise JinxInvalidStateError("You are attempting to %s %s, but its value in DNS has changed since you constructed your update." % (action, _format_rrset_name(rrset))) zone.delete_rdataset(rrset.name, rrset.rdtype) for rrset in add_rrsets: zone = zones[_get_zone(rrset.name, zone_list)] if zone.get_rdataset(rrset.name, rrset.rdtype) is not None: raise JinxInvalidStateError("You are attempting to add %s, but this record already exists in DNS." % _format_rrset_name(rrset)) rdataset = _rrset_to_rdataset(rrset) zone.replace_rdataset(rrset.name, rdataset) for name, zone in zones.iteritems(): zone_file = tempfile.NamedTemporaryFile() zone.to_file(zone_file, sorted=False, relativize=False) zone_file.flush() # Just flush, but don't close, the temp file, because Python temp files # are deleted once they're closed. try: checkzone = subprocess.Popen("/usr/sbin/named-checkzone -k fail -m fail -n fail -S ignore %s %s" % (name, zone_file.name), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) checkzone.wait() if checkzone.returncode != 0: raise JinxInvalidRequestError("zone %s failed zone check:\n%s" % (name, checkzone.stdout.read())) except OSError, exception: # Perhaps I should wrap this in a JinxAPIServerError, but really, # if I just let it go up, the middleware will do that for me. raise
parser.add_argument('zonefile', help='path to zone file') parser.add_argument('origin', help='zone origin') args = parser.parse_args() os.chdir(os.path.dirname(os.path.realpath(__file__))) if not config['cache'].is_dir(): config['cache'].mkdir(parents=True) zone = load_zone(args.zonefile, args.origin, args.raw_zone) update_serial(zone) domains = parse_lists(args.origin) tmpzonefile = Path(config['cache'], 'tempzone') zone.to_file(str(tmpzonefile)) with tmpzonefile.open('a') as f: for d in (sorted(domains)): if d in config['domain_whitelist']: continue append_domain_to_zonefile(f, d) if config['wildcard_block']: append_domain_to_zonefile(f, '*.' + d) if args.no_bind: save_zone(tmpzonefile, args.zonefile, args.origin, args.raw_zone) else: if check_zone(args.origin, tmpzonefile): save_zone(tmpzonefile, args.zonefile, args.origin, args.raw_zone) reload_zone(args.origin)
#!/usr/bin/python # bindnorm.py - "normalise" a bind zone file by expanding relative names. # Tue Sep 23 10:03:35 SAST 2008 import dns.zone import sys if len(sys.argv)<2: sys.stderr.write("Usage: %s [zone fqdn]\n" % sys.argv[0]) sys.stderr.write("Example: %s example.com < db.example.com > norm.db.example.com\n" % sys.argv[0]) sys.exit(1) zone = dns.zone.from_text(sys.stdin.read(), sys.argv[1], relativize=False, check_origin=False) zone.to_file(sys.stdout, relativize=False)