Fix record duplication bug and general cleanup

Fixes #47
This commit is contained in:
Joshua Boniface 2019-08-01 13:11:45 -04:00
parent 8bdec03cf1
commit 710d2cf9c2
1 changed files with 63 additions and 23 deletions

View File

@ -333,6 +333,9 @@ class AXFRDaemonInstance(object):
for network, instance in self.dns_networks.items(): for network, instance in self.dns_networks.items():
zone_modified = False zone_modified = False
# Set up our SQL cursor
sql_curs = self.sql_conn.cursor()
# Set up our basic variables # Set up our basic variables
domain = network.domain domain = network.domain
if network.ip4_gateway != 'None': if network.ip4_gateway != 'None':
@ -371,34 +374,58 @@ class AXFRDaemonInstance(object):
# #
# Get the current zone from the database # Get the current zone from the database
# #
sql_curs = self.sql_conn.cursor() try:
sql_curs.execute( sql_curs.execute(
"SELECT id FROM domains WHERE name=%s", "SELECT id FROM domains WHERE name=%s",
(domain,) (domain,)
) )
domain_id = sql_curs.fetchone() domain_id = sql_curs.fetchone()
sql_curs.execute( sql_curs.execute(
"SELECT * FROM records WHERE domain_id=%s", "SELECT * FROM records WHERE domain_id=%s",
(domain_id,) (domain_id,)
) )
results = list(sql_curs.fetchall()) results = list(sql_curs.fetchall())
if self.config['debug']:
print('SQL query results: {}'.format(results))
except Exception as e:
self.logger.out('ERROR: Failed to obtain DNS records from database: {}'.format(e))
# Fix the formatting because it's useless for comparison # Fix the formatting because it's useless for comparison
# reference: ((10, 28, 'testnet01.i.bonilan.net', 'SOA', 'nsX.pvc.local root.pvc.local 1 10800 1800 86400 86400', 86400, 0, None, 0, None, 1), etc.) # reference: ((10, 28, 'testnet01.i.bonilan.net', 'SOA', 'nsX.pvc.local root.pvc.local 1 10800 1800 86400 86400', 86400, 0, None, 0, None, 1), etc.)
records_old = list() records_old = list()
records_old_ids = list() records_old_ids = list()
if not results:
if self.config['debug']:
print('No results found, skipping.')
continue
for record in results: for record in results:
# Skip the non-A # Skip the non-A
if record[3] != 'A' or record[3] != 'AAAA': r_id = record[0]
continue r_name = record[2]
r_ttl = record[5]
r_type = record[3]
r_data = record[4]
# Assemble a list element in the same format as the AXFR data # Assemble a list element in the same format as the AXFR data
entry = '{} {} IN {} {}'.format(record[2], record[5], record[3], record[4]) entry = '{} {} IN {} {}'.format(r_name, r_ttl, r_type, r_data)
if self.config['debug']:
print('Found record: {}'.format(entry))
# Skip non-A or AAAA records
if r_type != 'A' and r_type != 'AAAA':
if self.config['debug']:
print('Skipping record {}, not A or AAAA: "{}"'.format(entry, r_type))
continue
records_old.append(entry) records_old.append(entry)
records_old_ids.append(record[0]) records_old_ids.append(r_id)
records_new.sort() records_new.sort()
records_old.sort() records_old.sort()
if self.config['debug']:
print('New: {}'.format(records_new))
print('Old: {}'.format(records_old))
# Find the differences between the lists # Find the differences between the lists
# Basic check one: are they completely equal # Basic check one: are they completely equal
if records_new != records_old: if records_new != records_old:
@ -408,6 +435,10 @@ class AXFRDaemonInstance(object):
in_new_not_in_old = in_new - in_old in_new_not_in_old = in_new - in_old
in_old_not_in_new = in_old - in_new in_old_not_in_new = in_old - in_new
if self.config['debug']:
print('New but not old: {}'.format(in_new_not_in_old))
print('Old but not new: {}'.format(in_old_not_in_new))
# Go through the old list # Go through the old list
remove_records = list() # list of database IDs remove_records = list() # list of database IDs
for i in range(len(records_old)): for i in range(len(records_old)):
@ -430,7 +461,8 @@ class AXFRDaemonInstance(object):
if len(remove_records) > 0: if len(remove_records) > 0:
# Remove the invalid old records # Remove the invalid old records
for record_id in remove_records: for record_id in remove_records:
sql_curs = self.sql_conn.cursor() if self.config['debug']:
print('Removing record: {}'.format(record_id))
sql_curs.execute( sql_curs.execute(
"DELETE FROM records WHERE id=%s", "DELETE FROM records WHERE id=%s",
(record_id,) (record_id,)
@ -442,14 +474,15 @@ class AXFRDaemonInstance(object):
for record in in_new_not_in_old: for record in in_new_not_in_old:
# [NAME, TTL, 'IN', TYPE, DATA] # [NAME, TTL, 'IN', TYPE, DATA]
record = record.split() record = record.split()
rname = record[0] r_name = record[0]
rttl = record[1] r_ttl = record[1]
rtype = record[3] r_type = record[3]
rdata = record[4] r_data = record[4]
sql_curs = self.sql_conn.cursor() if self.config['debug']:
print('Add record: {}'.format(name))
sql_curs.execute( sql_curs.execute(
"INSERT INTO records (domain_id, name, ttl, type, prio, content) VALUES (%s, %s, %s, %s, %s, %s)", "INSERT INTO records (domain_id, name, ttl, type, prio, content) VALUES (%s, %s, %s, %s, %s, %s)",
(domain_id, rname, rttl, rtype, 0, rdata) (domain_id, r_name, r_ttl, r_type, 0, r_data)
) )
changed = True changed = True
@ -463,13 +496,20 @@ class AXFRDaemonInstance(object):
current_serial = int(soa_record[2]) current_serial = int(soa_record[2])
new_serial = current_serial + 1 new_serial = current_serial + 1
soa_record[2] = str(new_serial) soa_record[2] = str(new_serial)
if self.config['debug']:
print('Records changed; bumping SOA: {}'.format(new_serial))
sql_curs.execute( sql_curs.execute(
"UPDATE records SET content=%s WHERE domain_id=%s AND type='SOA'", "UPDATE records SET content=%s WHERE domain_id=%s AND type='SOA'",
(' '.join(soa_record), domain_id) (' '.join(soa_record), domain_id)
) )
# Commit all the previous changes # Commit all the previous changes
self.sql_conn.commit() if self.config['debug']:
print('Committing database changes and reloading PDNS')
try:
self.sql_conn.commit()
except Exception as e:
self.logger.out('ERROR: Failed to commit DNS aggregator changes: {}'.format(e), state='e')
# Reload the domain # Reload the domain
common.run_os_command( common.run_os_command(