mirror of
https://github.com/cwinfo/powerdns-admin.git
synced 2024-11-08 14:40:27 +00:00
Merge pull request #156 from petersipos/feature/automatic-reverse-domain-creation
Feature/automatic reverse domain creation
This commit is contained in:
commit
b6ed658cbd
125
app/models.py
125
app/models.py
@ -7,8 +7,11 @@ import urlparse
|
||||
import itertools
|
||||
import traceback
|
||||
import pyotp
|
||||
import re
|
||||
import dns.reversename
|
||||
|
||||
from datetime import datetime
|
||||
from distutils.util import strtobool
|
||||
from distutils.version import StrictVersion
|
||||
from flask_login import AnonymousUserMixin
|
||||
|
||||
@ -31,7 +34,6 @@ else:
|
||||
if 'PRETTY_IPV6_PTR' in app.config.keys():
|
||||
import dns.inet
|
||||
import dns.name
|
||||
import dns.reversename
|
||||
PRETTY_IPV6_PTR = app.config['PRETTY_IPV6_PTR']
|
||||
else:
|
||||
PRETTY_IPV6_PTR = False
|
||||
@ -450,7 +452,7 @@ class Domain(db.Model):
|
||||
db.session.commit()
|
||||
return True
|
||||
except Exception, e:
|
||||
logging.error('Can not create settting %s for domain %s. %s' % (setting, self.name, str(e)))
|
||||
logging.error('Can not create setting %s for domain %s. %s' % (setting, self.name, str(e)))
|
||||
return False
|
||||
|
||||
def get_domains(self):
|
||||
@ -481,8 +483,11 @@ class Domain(db.Model):
|
||||
"""
|
||||
Return domain id
|
||||
"""
|
||||
domain = Domain.query.filter(Domain.name==name).first()
|
||||
return domain.id
|
||||
try:
|
||||
domain = Domain.query.filter(Domain.name==name).first()
|
||||
return domain.id
|
||||
except:
|
||||
return None
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
@ -507,6 +512,10 @@ class Domain(db.Model):
|
||||
if domain_user:
|
||||
domain_user.delete()
|
||||
db.session.commit()
|
||||
domain_setting = DomainSetting.query.filter(DomainSetting.domain_id==domain.id)
|
||||
if domain_setting:
|
||||
domain_setting.delete()
|
||||
db.session.commit()
|
||||
|
||||
# then remove domain
|
||||
Domain.query.filter(Domain.name == d).delete()
|
||||
@ -600,6 +609,60 @@ class Domain(db.Model):
|
||||
logging.debug(str(e))
|
||||
return {'status': 'error', 'msg': 'Cannot add this domain.'}
|
||||
|
||||
def create_reverse_domain(self, domain_name, domain_reverse_name):
|
||||
"""
|
||||
Check the existing reverse lookup domain,
|
||||
if not exists create a new one automatically
|
||||
"""
|
||||
domain_obj = Domain.query.filter(Domain.name == domain_name).first()
|
||||
domain_auto_ptr = DomainSetting.query.filter(DomainSetting.domain == domain_obj).filter(DomainSetting.setting == 'auto_ptr').first()
|
||||
domain_auto_ptr = strtobool(domain_auto_ptr.value) if domain_auto_ptr else False
|
||||
system_auto_ptr = Setting.query.filter(Setting.name == 'auto_ptr').first()
|
||||
system_auto_ptr = strtobool(system_auto_ptr.value)
|
||||
self.name = domain_name
|
||||
domain_id = self.get_id_by_name(domain_reverse_name)
|
||||
if None == domain_id and \
|
||||
(
|
||||
system_auto_ptr or \
|
||||
domain_auto_ptr
|
||||
):
|
||||
result = self.add(domain_reverse_name, 'Master', 'INCEPTION-INCREMENT', '', '')
|
||||
self.update()
|
||||
if result['status'] == 'ok':
|
||||
history = History(msg='Add reverse lookup domain %s' % domain_reverse_name, detail=str({'domain_type': 'Master', 'domain_master_ips': ''}), created_by='System')
|
||||
history.add()
|
||||
else:
|
||||
return {'status': 'error', 'msg': 'Adding reverse lookup domain failed'}
|
||||
domain_user_ids = self.get_user()
|
||||
domain_users = []
|
||||
u = User()
|
||||
for uid in domain_user_ids:
|
||||
u.id = uid
|
||||
tmp = u.get_user_info_by_id()
|
||||
domain_users.append(tmp.username)
|
||||
if 0 != len(domain_users):
|
||||
self.name = domain_reverse_name
|
||||
self.grant_privielges(domain_users)
|
||||
return {'status': 'ok', 'msg': 'New reverse lookup domain created with granted privilages'}
|
||||
return {'status': 'ok', 'msg': 'New reverse lookup domain created without users'}
|
||||
return {'status': 'ok', 'msg': 'Reverse lookup domain already exists'}
|
||||
|
||||
def get_reverse_domain_name(self, reverse_host_address):
|
||||
c = 1
|
||||
if re.search('ip6.arpa', reverse_host_address):
|
||||
for i in range(1,32,1):
|
||||
address = re.search('((([a-f0-9]\.){'+ str(i) +'})(?P<ipname>.+6.arpa)\.?)', reverse_host_address)
|
||||
if None != self.get_id_by_name(address.group('ipname')):
|
||||
c = i
|
||||
break
|
||||
return re.search('((([a-f0-9]\.){'+ str(c) +'})(?P<ipname>.+6.arpa)\.?)', reverse_host_address).group('ipname')
|
||||
else:
|
||||
for i in range(1,4,1):
|
||||
address = re.search('((([0-9]+\.){'+ str(i) +'})(?P<ipname>.+r.arpa)\.?)', reverse_host_address)
|
||||
if None != self.get_id_by_name(address.group('ipname')):
|
||||
c = i
|
||||
break
|
||||
return re.search('((([0-9]+\.){'+ str(c) +'})(?P<ipname>.+r.arpa)\.?)', reverse_host_address).group('ipname')
|
||||
|
||||
def delete(self, domain_name):
|
||||
"""
|
||||
@ -769,7 +832,7 @@ class Record(object):
|
||||
if NEW_SCHEMA:
|
||||
data = {"rrsets": [
|
||||
{
|
||||
"name": self.name + '.',
|
||||
"name": self.name.rstrip('.') + '.',
|
||||
"type": self.type,
|
||||
"changetype": "REPLACE",
|
||||
"ttl": self.ttl,
|
||||
@ -861,7 +924,7 @@ class Record(object):
|
||||
|
||||
records = []
|
||||
for r in deleted_records:
|
||||
r_name = r['name'] + '.' if NEW_SCHEMA else r['name']
|
||||
r_name = r['name'].rstrip('.') + '.' if NEW_SCHEMA else r['name']
|
||||
r_type = r['type']
|
||||
if PRETTY_IPV6_PTR: # only if activated
|
||||
if NEW_SCHEMA: # only if new schema
|
||||
@ -883,7 +946,7 @@ class Record(object):
|
||||
records = []
|
||||
for r in new_records:
|
||||
if NEW_SCHEMA:
|
||||
r_name = r['name'] + '.'
|
||||
r_name = r['name'].rstrip('.') + '.'
|
||||
r_type = r['type']
|
||||
if PRETTY_IPV6_PTR: # only if activated
|
||||
if r_type == 'PTR': # only ptr
|
||||
@ -988,12 +1051,54 @@ class Record(object):
|
||||
logging.debug(jdata2['error'])
|
||||
return {'status': 'error', 'msg': jdata2['error']}
|
||||
else:
|
||||
self.auto_ptr(domain, new_records, deleted_records)
|
||||
logging.info('Record was applied successfully.')
|
||||
return {'status': 'ok', 'msg': 'Record was applied successfully'}
|
||||
except Exception, e:
|
||||
logging.error("Cannot apply record changes to domain %s. DETAIL: %s" % (str(e), domain))
|
||||
return {'status': 'error', 'msg': 'There was something wrong, please contact administrator'}
|
||||
|
||||
def auto_ptr(self, domain, new_records, deleted_records):
|
||||
"""
|
||||
Add auto-ptr records
|
||||
"""
|
||||
domain_obj = Domain.query.filter(Domain.name == domain).first()
|
||||
domain_auto_ptr = DomainSetting.query.filter(DomainSetting.domain == domain_obj).filter(DomainSetting.setting == 'auto_ptr').first()
|
||||
domain_auto_ptr = strtobool(domain_auto_ptr.value) if domain_auto_ptr else False
|
||||
|
||||
system_auto_ptr = Setting.query.filter(Setting.name == 'auto_ptr').first()
|
||||
system_auto_ptr = strtobool(system_auto_ptr.value)
|
||||
|
||||
if system_auto_ptr or domain_auto_ptr:
|
||||
try:
|
||||
d = Domain()
|
||||
for r in new_records:
|
||||
if r['type'] in ['A', 'AAAA']:
|
||||
r_name = r['name'] + '.'
|
||||
r_content = r['content']
|
||||
reverse_host_address = dns.reversename.from_address(r_content).to_text()
|
||||
domain_reverse_name = d.get_reverse_domain_name(reverse_host_address)
|
||||
d.create_reverse_domain(domain, domain_reverse_name)
|
||||
self.name = dns.reversename.from_address(r_content).to_text().rstrip('.')
|
||||
self.type = 'PTR'
|
||||
self.status = r['disabled']
|
||||
self.ttl = r['ttl']
|
||||
self.data = r_name
|
||||
self.add(domain_reverse_name)
|
||||
for r in deleted_records:
|
||||
if r['type'] in ['A', 'AAAA']:
|
||||
r_name = r['name'] + '.'
|
||||
r_content = r['content']
|
||||
reverse_host_address = dns.reversename.from_address(r_content).to_text()
|
||||
domain_reverse_name = d.get_reverse_domain_name(reverse_host_address)
|
||||
self.name = reverse_host_address
|
||||
self.type = 'PTR'
|
||||
self.data = r_content
|
||||
self.delete(domain_reverse_name)
|
||||
return {'status': 'ok', 'msg': 'Auto-PTR record was updated successfully'}
|
||||
except Exception as e:
|
||||
logging.error("Cannot update auto-ptr record changes to domain %s. DETAIL: %s" % (str(e), domain))
|
||||
return {'status': 'error', 'msg': 'Auto-PTR creation failed. There was something wrong, please contact administrator.'}
|
||||
|
||||
def delete(self, domain):
|
||||
"""
|
||||
@ -1003,14 +1108,10 @@ class Record(object):
|
||||
headers['X-API-Key'] = PDNS_API_KEY
|
||||
data = {"rrsets": [
|
||||
{
|
||||
"name": self.name,
|
||||
"name": self.name.rstrip('.') + '.',
|
||||
"type": self.type,
|
||||
"changetype": "DELETE",
|
||||
"records": [
|
||||
{
|
||||
"name": self.name,
|
||||
"type": self.type
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
@ -168,7 +168,7 @@
|
||||
{{ domain.type }}
|
||||
</td>
|
||||
<td>
|
||||
{{ domain.serial }}
|
||||
{% if domain.serial == 0 %}{{ domain.notified_serial }}{% else %}{{domain.serial}}{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if domain.master == '[]'%}N/A {% else %}{{ domain.master|display_master_name }}{% endif %}
|
||||
|
@ -223,7 +223,8 @@
|
||||
$("#tbl_records").DataTable().search('').columns().search('').draw();
|
||||
|
||||
// add new row
|
||||
var nRow = jQuery('#tbl_records').dataTable().fnAddData(['', 'A', 'Active', 3600, '', '', '', '0']);
|
||||
var default_type = records_allow_edit[0]
|
||||
var nRow = jQuery('#tbl_records').dataTable().fnAddData(['', default_type, 'Active', 3600, '', '', '', '0']);
|
||||
editRow($("#tbl_records").DataTable(), nRow);
|
||||
document.getElementById("edit-row-focus").focus();
|
||||
nEditing = nRow;
|
||||
@ -268,16 +269,16 @@
|
||||
var modal = $("#modal_custom_record");
|
||||
if (record_data.val() == "") {
|
||||
var form = " <label for=\"mx_priority\">MX Priority</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_priority\" id=\"mx_priority\" placeholder=\"10\"> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_priority\" id=\"mx_priority\" placeholder=\"eg. 10\"> \
|
||||
<label for=\"mx_server\">MX Server</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_server\" id=\"mx_server\" placeholder=\"postfix.example.com\"> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_server\" id=\"mx_server\" placeholder=\"eg. postfix.example.com\"> \
|
||||
";
|
||||
} else {
|
||||
var parts = record_data.val().split(" ");
|
||||
var form = " <label for=\"mx_priority\">MX Priority</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_priority\" id=\"mx_priority\" placeholder=\"10\" value=\"" + parts[0] + "\"> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_priority\" id=\"mx_priority\" placeholder=\"eg. 10\" value=\"" + parts[0] + "\"> \
|
||||
<label for=\"mx_server\">MX Server</label> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_server\" id=\"mx_server\" placeholder=\"postfix.example.com\" value=\"" + parts[1] + "\"> \
|
||||
<input type=\"text\" class=\"form-control\" name=\"mx_server\" id=\"mx_server\" placeholder=\"eg. postfix.example.com\" value=\"" + parts[1] + "\"> \
|
||||
";
|
||||
}
|
||||
modal.find('.modal-body p').html(form);
|
||||
|
@ -55,6 +55,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title">Auto PTR creation</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p><input type="checkbox" id="{{ domain.name }}" class="auto_ptr_toggle"
|
||||
{% for setting in domain.settings %}{% if setting.setting=='auto_ptr' and setting.value=='True' %}checked{% endif %}{% endfor %} {% if auto_ptr_setting %}disabled="True"{% endif %}>
|
||||
Allow automatic reverse pointer creation on record updates?{% if
|
||||
auto_ptr_setting %}</br><code>Auto-ptr is enabled globally on the PDA system!</code>{% endif %}</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box">
|
||||
@ -94,6 +110,10 @@ $('.dyndns_on_demand_toggle').iCheck({
|
||||
checkboxClass : 'icheckbox_square-blue',
|
||||
increaseArea : '20%' // optional
|
||||
});
|
||||
$('.auto_ptr_toggle').iCheck({
|
||||
checkboxClass : 'icheckbox_square-blue',
|
||||
increaseArea : '20%' // optional
|
||||
});
|
||||
|
||||
$("#domain_multi_user").multiSelect();
|
||||
|
||||
@ -110,6 +130,18 @@ $('.dyndns_on_demand_toggle').on('ifToggled', function(event) {
|
||||
};
|
||||
applyChanges(postdata, $SCRIPT_ROOT + '/domain/' + domain + '/managesetting', true);
|
||||
});
|
||||
$('.auto_ptr_toggle').on('ifToggled', function(event) {
|
||||
var is_checked = $(this).prop('checked');
|
||||
var domain = $(this).prop('id');
|
||||
postdata = {
|
||||
'action' : 'set_setting',
|
||||
'data' : {
|
||||
'setting' : 'auto_ptr',
|
||||
'value' : is_checked
|
||||
}
|
||||
};
|
||||
applyChanges(postdata, $SCRIPT_ROOT + '/domain/' + domain + '/managesetting', true);
|
||||
});
|
||||
|
||||
// handle deletion of domain
|
||||
$(document.body).on('click', '.delete_domain', function() {
|
||||
|
13
app/views.py
13
app/views.py
@ -2,6 +2,7 @@ import base64
|
||||
import json
|
||||
import os
|
||||
import traceback
|
||||
import re
|
||||
from distutils.util import strtobool
|
||||
from distutils.version import StrictVersion
|
||||
from functools import wraps
|
||||
@ -58,6 +59,11 @@ def inject_default_domain_table_size_setting():
|
||||
default_domain_table_size_setting = Setting.query.filter(Setting.name == 'default_domain_table_size').first()
|
||||
return dict(default_domain_table_size_setting=default_domain_table_size_setting.value)
|
||||
|
||||
@app.context_processor
|
||||
def inject_auto_ptr_setting():
|
||||
auto_ptr_setting = Setting.query.filter(Setting.name == 'auto_ptr').first()
|
||||
return dict(auto_ptr_setting=strtobool(auto_ptr_setting.value))
|
||||
|
||||
# START USER AUTHENTICATION HANDLER
|
||||
@app.before_request
|
||||
def before_request():
|
||||
@ -312,8 +318,11 @@ def domain(domain_name):
|
||||
if jr['type'] in app.config['RECORDS_ALLOW_EDIT']:
|
||||
record = Record(name=jr['name'], type=jr['type'], status='Disabled' if jr['disabled'] else 'Active', ttl=jr['ttl'], data=jr['content'])
|
||||
records.append(record)
|
||||
|
||||
return render_template('domain.html', domain=domain, records=records, editable_records=app.config['RECORDS_ALLOW_EDIT'])
|
||||
if not re.search('ip6\.arpa|in-addr\.arpa$', domain_name):
|
||||
editable_records = app.config['RECORDS_ALLOW_EDIT']
|
||||
else:
|
||||
editable_records = ['PTR']
|
||||
return render_template('domain.html', domain=domain, records=records, editable_records=editable_records)
|
||||
else:
|
||||
return redirect(url_for('error', code=404))
|
||||
|
||||
|
@ -77,7 +77,8 @@ def init_records():
|
||||
Setting('record_helper', 'True'),
|
||||
Setting('login_ldap_first', 'True'),
|
||||
Setting('default_record_table_size', '15'),
|
||||
Setting('default_domain_table_size', '10')
|
||||
Setting('default_domain_table_size', '10'),
|
||||
Setting('auto_ptr','False')
|
||||
])
|
||||
|
||||
db_commit = db.session.commit()
|
||||
|
Loading…
Reference in New Issue
Block a user