Re-add pretty_ipv6_ptr. Bug fixes

This commit is contained in:
Khanh Ngo 2019-12-14 23:13:55 +07:00
parent 95fe2a8a85
commit 5ac58d5503
No known key found for this signature in database
GPG Key ID: A945965CD6351844
4 changed files with 75 additions and 97 deletions

View File

@ -1,5 +1,5 @@
import re
import traceback import traceback
import itertools
import dns.reversename import dns.reversename
import dns.inet import dns.inet
import dns.name import dns.name
@ -113,7 +113,14 @@ class Record(object):
def add(self, domain_name, rrset): def add(self, domain_name, rrset):
""" """
Add a record to a domain (a reverse domain name) Add a record to a domain (Used by auto_ptr and DynDNS)
Args:
domain_name(str): The zone name
rrset(dict): The record in PDNS rrset format
Returns:
(dict): A dict contains status code and message
""" """
# Validate record first # Validate record first
rrsets = self.get_rrsets(domain_name) rrsets = self.get_rrsets(domain_name)
@ -131,46 +138,6 @@ class Record(object):
headers = {} headers = {}
headers['X-API-Key'] = self.PDNS_API_KEY headers['X-API-Key'] = self.PDNS_API_KEY
# if self.NEW_SCHEMA:
# data = {
# "rrsets": [{
# "name":
# self.name.rstrip('.') + '.',
# "type":
# self.type,
# "changetype":
# "REPLACE",
# "ttl":
# self.ttl,
# "records": [{
# "content": self.data,
# "disabled": self.status,
# }],
# "comments":
# [self.comment_data] if self.comment_data else []
# }]
# }
# else:
# data = {
# "rrsets": [{
# "name":
# self.name,
# "type":
# self.type,
# "changetype":
# "REPLACE",
# "records": [{
# "content": self.data,
# "disabled": self.status,
# "name": self.name,
# "ttl": self.ttl,
# "type": self.type
# }],
# "comments":
# [self.comment_data] if self.comment_data else []
# }]
# }
try: try:
jdata = utils.fetch_json(urljoin( jdata = utils.fetch_json(urljoin(
self.PDNS_STATS_URL, self.API_EXTENDED_URL + self.PDNS_STATS_URL, self.API_EXTENDED_URL +
@ -184,8 +151,10 @@ class Record(object):
return {'status': 'ok', 'msg': 'Record was added successfully'} return {'status': 'ok', 'msg': 'Record was added successfully'}
except Exception as e: except Exception as e:
current_app.logger.error( current_app.logger.error(
"Cannot add record {0}/{1}/{2} to domain {3}. DETAIL: {4}". "Cannot add record to domain {}. Error: {}".format(
format(self.name, self.type, self.data, domain_name, e)) domain_name, e))
current_app.logger.debug("Submitted record rrset: \n{}".format(
utils.pretty_json(rrset)))
return { return {
'status': 'error', 'status': 'error',
'msg': 'msg':
@ -226,11 +195,26 @@ class Record(object):
rrsets = [] rrsets = []
for record in submitted_records: for record in submitted_records:
# Format the record name # Format the record name
record_name = "{}.{}.".format( #
record["record_name"], # If it is ipv6 reverse zone and PRETTY_IPV6_PTR is enabled,
domain_name) if record["record_name"] not in [ # We convert ipv6 address back to reverse record format
'@', '' # before submitting to PDNS API.
] else domain_name + '.' if self.PRETTY_IPV6_PTR and re.search(r'ip6\.arpa', domain_name):
if record['record_type'] == 'PTR' and ':' in record[
'record_name']:
record_name = dns.reversename.from_address(
record['record_name']).to_text()
# Else, it is forward zone, then record name should be
# in format "<name>.<domain>.". If it is root
# domain name (name == '@' or ''), the name should
# be in format "<domain>."
else:
record_name = "{}.{}.".format(
record["record_name"],
domain_name) if record["record_name"] not in [
'@', ''
] else domain_name + '.'
# Format the record content, it musts end # Format the record content, it musts end
# with a dot character if in following types # with a dot character if in following types
@ -249,7 +233,7 @@ class Record(object):
record_comments = [{ record_comments = [{
"content": record["record_comment"], "content": record["record_comment"],
"account": "" "account": ""
}] if record["record_comment"] else [] }] if record.get("record_comment") else []
# Add the formatted record to rrsets list # Add the formatted record to rrsets list
rrsets.append({ rrsets.append({
@ -267,7 +251,7 @@ class Record(object):
# Sort the list before using groupby # Sort the list before using groupby
rrsets = sorted(rrsets, key=lambda r: (r['name'], r['type'])) rrsets = sorted(rrsets, key=lambda r: (r['name'], r['type']))
groups = groupby(rrsets, key=lambda r: (r['name'], r['type'])) groups = groupby(rrsets, key=lambda r: (r['name'], r['type']))
for k, v in groups: for _k, v in groups:
group = list(v) group = list(v)
transformed_rrsets.append(self.merge_rrsets(group)) transformed_rrsets.append(self.merge_rrsets(group))
@ -336,38 +320,6 @@ class Record(object):
# Get the list of rrsets to be added and deleted # Get the list of rrsets to be added and deleted
new_rrsets, del_rrsets = self.compare(domain_name, submitted_records) new_rrsets, del_rrsets = self.compare(domain_name, submitted_records)
# records = []
# for r in deleted_records:
# r_name = r['name'].rstrip(
# '.') + '.' if self.NEW_SCHEMA else r['name']
# r_type = r['type']
# if self.PRETTY_IPV6_PTR: # only if activated
# if self.NEW_SCHEMA: # only if new schema
# if r_type == 'PTR': # only ptr
# if ':' in r['name']: # dirty ipv6 check
# r_name = dns.reversename.from_address(
# r['name']).to_text()
# record = {
# "name": r_name,
# "type": r_type,
# "changetype": "DELETE",
# "records": []
# }
# records.append(record)
# postdata_for_delete = {"rrsets": records}
# records = []
# for r in new_records:
# if self.NEW_SCHEMA:
# r_name = r['name'].rstrip('.') + '.'
# r_type = r['type']
# if self.PRETTY_IPV6_PTR: # only if activated
# if r_type == 'PTR': # only ptr
# if ':' in r['name']: # dirty ipv6 check
# r_name = r['name']
# Submit the changes to PDNS API # Submit the changes to PDNS API
try: try:
headers = {} headers = {}

View File

@ -3,7 +3,7 @@ import json
import traceback import traceback
from ast import literal_eval from ast import literal_eval
from distutils.version import StrictVersion from distutils.version import StrictVersion
from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, jsonify, abort from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, jsonify, abort, flash
from flask_login import login_required, current_user from flask_login import login_required, current_user
from ..decorators import operator_role_required, admin_role_required from ..decorators import operator_role_required, admin_role_required
@ -843,7 +843,7 @@ def create_template_from_zone():
for jr in jrecords: for jr in jrecords:
if jr['type'] in Setting().get_records_allow_to_edit(): if jr['type'] in Setting().get_records_allow_to_edit():
name = '@' if jr['name'] == domain_name else re.sub( name = '@' if jr['name'] == domain_name else re.sub(
'\.{}$'.format(domain_name), '', jr['name']) r'\.{}$'.format(domain_name), '', jr['name'])
for subrecord in jr['records']: for subrecord in jr['records']:
record = DomainTemplateRecord( record = DomainTemplateRecord(
name=name, name=name,
@ -858,7 +858,7 @@ def create_template_from_zone():
for jr in jrecords: for jr in jrecords:
if jr['type'] in Setting().get_records_allow_to_edit(): if jr['type'] in Setting().get_records_allow_to_edit():
name = '@' if jr['name'] == domain_name else re.sub( name = '@' if jr['name'] == domain_name else re.sub(
'\.{}$'.format(domain_name), '', jr['name']) r'\.{}$'.format(domain_name), '', jr['name'])
record = DomainTemplateRecord( record = DomainTemplateRecord(
name=name, name=name,
type=jr['type'], type=jr['type'],

View File

@ -1,6 +1,8 @@
import re import re
import json import json
import traceback import traceback
import dns.name
import dns.reversename
from distutils.version import StrictVersion from distutils.version import StrictVersion
from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, abort, jsonify from flask import Blueprint, render_template, make_response, url_for, current_app, request, redirect, abort, jsonify
from flask_login import login_required, current_user from flask_login import login_required, current_user
@ -63,15 +65,27 @@ def domain(domain_name):
if StrictVersion(Setting().get('pdns_version')) >= StrictVersion('4.0.0'): if StrictVersion(Setting().get('pdns_version')) >= StrictVersion('4.0.0'):
for r in rrsets: for r in rrsets:
if r['type'] in records_allow_to_edit: if r['type'] in records_allow_to_edit:
r_name = r['name'].rstrip('.')
# If it is reverse zone and pretty_ipv6_ptr setting
# is enabled, we reformat the name for ipv6 records.
if Setting().get('pretty_ipv6_ptr') and r[
'type'] == 'PTR' and 'ip6.arpa' in r_name:
r_name = dns.reversename.to_address(
dns.name.from_text(r_name))
# Create the list of records in format that
# PDA jinja2 template can understand.
index = 0 index = 0
for record in r['records']: for record in r['records']:
record_entry = RecordEntry( record_entry = RecordEntry(
name=r['name'].rstrip('.'), name=r_name,
type=r['type'], type=r['type'],
status='Disabled' if record['disabled'] else 'Active', status='Disabled' if record['disabled'] else 'Active',
ttl=r['ttl'], ttl=r['ttl'],
data=record['content'], data=record['content'],
comment=r['comments'][index]['content'] if r['comments'] else '', comment=r['comments'][index]['content']
if r['comments'] else '',
is_allowed_edit=True) is_allowed_edit=True)
index += 1 index += 1
records.append(record_entry) records.append(record_entry)
@ -79,7 +93,7 @@ def domain(domain_name):
# Unsupported version # Unsupported version
abort(500) abort(500)
if not re.search('ip6\.arpa|in-addr\.arpa$', domain_name): if not re.search(r'ip6\.arpa|in-addr\.arpa$', domain_name):
editable_records = forward_records_allow_to_edit editable_records = forward_records_allow_to_edit
else: else:
editable_records = reverse_records_allow_to_edit editable_records = reverse_records_allow_to_edit

View File

@ -1,4 +1,5 @@
import os import os
import re
import json import json
import traceback import traceback
import datetime import datetime
@ -423,7 +424,7 @@ def dyndns_update():
domain = None domain = None
domain_segments = hostname.split('.') domain_segments = hostname.split('.')
for index in range(len(domain_segments)): for _index in range(len(domain_segments)):
full_domain = '.'.join(domain_segments) full_domain = '.'.join(domain_segments)
potential_domain = Domain.query.filter( potential_domain = Domain.query.filter(
Domain.name == full_domain).first() Domain.name == full_domain).first()
@ -489,12 +490,23 @@ def dyndns_update():
DomainSetting.setting == 'create_via_dyndns').first() DomainSetting.setting == 'create_via_dyndns').first()
if (ondemand_creation is not None) and (strtobool( if (ondemand_creation is not None) and (strtobool(
ondemand_creation.value) == True): ondemand_creation.value) == True):
record = Record(name=hostname,
type=rtype, # Build the rrset
data=str(ip), rrset_data = [{
status=False, "changetype": "REPLACE",
ttl=3600) "name": hostname + '.',
result = record.add(domain.name) "ttl": 3600,
"type": rtype,
"records": [{
"content": str(ip),
"disabled": False
}],
"comments": []
}]
# Format the rrset
rrset = {"rrsets": rrset_data}
result = Record().add(domain.name, rrset)
if result['status'] == 'ok': if result['status'] == 'ok':
history = History( history = History(
msg= msg=
@ -679,7 +691,7 @@ def handle_account(account_name):
clean_name = ''.join(c for c in account_name.lower() clean_name = ''.join(c for c in account_name.lower()
if c in "abcdefghijklmnopqrstuvwxyz0123456789") if c in "abcdefghijklmnopqrstuvwxyz0123456789")
if len(clean_name) > Account.name.type.length: if len(clean_name) > Account.name.type.length:
logging.error( current_app.logger.error(
"Account name {0} too long. Truncated.".format(clean_name)) "Account name {0} too long. Truncated.".format(clean_name))
account = Account.query.filter_by(name=clean_name).first() account = Account.query.filter_by(name=clean_name).first()
if not account: if not account: