End-to-end working version of adding forward/reverse A record from forward zone form.
This commit is contained in:
parent
77da4b8f82
commit
00f8036991
|
@ -2,10 +2,18 @@ from django import forms
|
||||||
|
|
||||||
from bcommon.models import BindServer, Key
|
from bcommon.models import BindServer, Key
|
||||||
|
|
||||||
|
RECORD_TYPE_CHOICES = (("A", "A"), ("AAAA", "AAAA"))
|
||||||
|
TTL_CHOICES = ((300, "5 minutes"),
|
||||||
|
(1800, "30 minutes"),
|
||||||
|
(3600, "1 hour"),
|
||||||
|
(43200, "12 hours"),
|
||||||
|
(86400, "1 day"))
|
||||||
|
|
||||||
class FormAddRecord(forms.Form):
|
class FormAddRecord(forms.Form):
|
||||||
dns_hostname = forms.CharField(max_length=100)
|
dns_server = forms.CharField(max_length=100, label="Hostname of DNS Server", widget=forms.TextInput(attrs={'readonly':'readonly'}))
|
||||||
rr_domain = forms.CharField(max_length=100)
|
name = forms.CharField(max_length=100, label="Record Name (FQDN)")
|
||||||
rr_name = forms.CharField(max_length=256)
|
record_type = forms.ChoiceField(choices=RECORD_TYPE_CHOICES, label="Record Type")
|
||||||
rr_type = forms.ChoiceField(choices=(("A", "A"), ("MX", "MX"), ("CNAME", "CNAME"), ("AAAA", "AAAA")))
|
ttl = forms.ChoiceField(choices=TTL_CHOICES, label="TTL", initial=86400)
|
||||||
rr_data = forms.CharField(max_length=256)
|
create_reverse = forms.BooleanField(label="Create Reverse Record (PTR)?", required=False)
|
||||||
tsig_key = forms.ModelChoiceField(queryset=Key.objects.all(), empty_label=None)
|
data = forms.CharField(max_length=256, label="Record Data (IP/Hostname)")
|
||||||
|
key_name = forms.ModelChoiceField(queryset=Key.objects.all(), empty_label=None, label="TSIG Key")
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import urllib2
|
from bcommon.keyutils import create_keyring
|
||||||
from BeautifulSoup import BeautifulStoneSoup as BS
|
|
||||||
import re
|
|
||||||
|
|
||||||
from bcommon.models import Key, BindServer
|
import re
|
||||||
import dns.query
|
import dns.query
|
||||||
|
import dns.reversename
|
||||||
|
import dns.update
|
||||||
|
|
||||||
def list_zone_records(dns_hostname, zone_name):
|
def list_zone_records(dns_hostname, zone_name):
|
||||||
""" Take a DNS zone, and list all the records it contains. """
|
"""Take a DNS server and a zone name,
|
||||||
|
and return an array of its records."""
|
||||||
# Need to move most of this logic into a helper method.
|
# Need to move most of this logic into a helper method.
|
||||||
try:
|
try:
|
||||||
zone = dns.zone.from_xfr(dns.query.xfr(dns_hostname, zone_name))
|
zone = dns.zone.from_xfr(dns.query.xfr(dns_hostname, zone_name))
|
||||||
|
@ -31,16 +32,48 @@ def list_zone_records(dns_hostname, zone_name):
|
||||||
'rr_data' : split_record.split(" ")[4]})
|
'rr_data' : split_record.split(" ")[4]})
|
||||||
return record_array
|
return record_array
|
||||||
|
|
||||||
def add_record(clean_data):
|
def add_forward_record(form_data, zone_keyring):
|
||||||
key_name = Key.objects.get(name=(clean_data['tsig_key'])).name
|
"""Take in data from FormAddRecord and a keyring object,
|
||||||
key_data = Key.objects.get(name=(clean_data['tsig_key'])).data
|
return a response from the DNS server about adding the record."""
|
||||||
key_algorithm = Key.objects.get(name=(clean_data['tsig_key'])).algorithm
|
|
||||||
keyring = dns.tsigkeyring.from_text({ key_name : key_data })
|
|
||||||
dns_update = dns.update.Update(clean_data['rr_domain'], keyring = keyring, keyalgorithm=key_algorithm)
|
|
||||||
dns_update.replace(str(clean_data['rr_name']), 86400, str(clean_data['rr_type']), str(clean_data['rr_data']))
|
|
||||||
try:
|
|
||||||
response = dns.query.tcp(dns_update, clean_data['dns_hostname'])
|
|
||||||
except dns.tsig.PeerBadKey:
|
|
||||||
return {'errors' : "There was a problem adding your record due to a TSIG key issue. Please resolve that first." }
|
|
||||||
|
|
||||||
return {'response' : response }
|
re_form_data = re.search(r"(\w+).(.*)", form_data["name"])
|
||||||
|
hostname = re_form_data.group(1)
|
||||||
|
domain = re_form_data.group(2)
|
||||||
|
|
||||||
|
dns_update = dns.update.Update(domain, keyring = zone_keyring)
|
||||||
|
dns_update.replace(hostname, int(form_data["ttl"]), str(form_data["record_type"]), str(form_data["data"]))
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = dns.query.tcp(dns_update, form_data["dns_server"])
|
||||||
|
except dns.tsig.BadPeerKey:
|
||||||
|
response = "There was a problem adding your forward record due to a TSIG key issue."
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def add_reverse_record(form_data, zone_keyring):
|
||||||
|
|
||||||
|
reverse_ip_fqdn = str(dns.reversename.from_address(form_data["data"]))
|
||||||
|
reverse_ip = re.search(r"([0-9]+).(.*).$", reverse_ip_fqdn).group(1)
|
||||||
|
reverse_domain = re.search(r"([0-9]+).(.*).$", reverse_ip_fqdn).group(2)
|
||||||
|
|
||||||
|
dns_update = dns.update.Update(reverse_domain, keyring = zone_keyring)
|
||||||
|
dns_update.replace(reverse_ip, int(form_data["ttl"]), "PTR", str(form_data["name"]) + ".")
|
||||||
|
|
||||||
|
response = dns.query.tcp(dns_update, form_data["dns_server"])
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def add_record(form_data, key_dict):
|
||||||
|
"""Add a DNS record with data from a FormAddRecord object.
|
||||||
|
If a reverse PTR record is requested, this will be added too."""
|
||||||
|
|
||||||
|
keyring = create_keyring(key_dict)
|
||||||
|
response = {}
|
||||||
|
forward_response = add_forward_record(form_data, keyring)
|
||||||
|
response["forward_response"] = forward_response
|
||||||
|
|
||||||
|
if form_data["create_reverse"]:
|
||||||
|
reverse_response = add_reverse_record(form_data, keyring)
|
||||||
|
response["reverse_response"] = reverse_response
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import dns.tsigkeyring
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def create_keyring(key_dict):
|
||||||
|
"""Accept a TSIG keyfile and a key name to retrieve.
|
||||||
|
Return a keyring object with the key name and TSIG secret."""
|
||||||
|
|
||||||
|
keyring = dns.tsigkeyring.from_text({
|
||||||
|
key_dict.name : key_dict.data
|
||||||
|
})
|
||||||
|
|
||||||
|
return keyring
|
|
@ -3,17 +3,11 @@
|
||||||
from bcommon.models import BindServer, Key
|
from bcommon.models import BindServer, Key
|
||||||
from django.template import Context
|
from django.template import Context
|
||||||
from django.shortcuts import render_to_response, redirect
|
from django.shortcuts import render_to_response, redirect
|
||||||
from bcommon.helpers import list_server_zones, list_zone_records, add_record
|
from bcommon.helpers import list_zone_records, add_record #, delete_record
|
||||||
|
|
||||||
from bcommon.forms import FormAddRecord
|
from bcommon.forms import FormAddRecord
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
|
|
||||||
|
|
||||||
import dns.update
|
|
||||||
import dns.tsigkeyring
|
|
||||||
|
|
||||||
import socket
|
|
||||||
|
|
||||||
def home_index(request):
|
def home_index(request):
|
||||||
return render_to_response('index.htm')
|
return render_to_response('index.htm')
|
||||||
|
|
||||||
|
@ -55,37 +49,40 @@ def view_zone_records(request, dns_hostname, zone_name):
|
||||||
'rr_domain' : zone_name},
|
'rr_domain' : zone_name},
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
def view_add_record(request, dns_hostname, zone_name):
|
def view_add_record(request, dns_server, zone):
|
||||||
""" View to provide form to add a DNS record. """
|
""" View to provide form to add a DNS record. """
|
||||||
form = FormAddRecord(initial={ 'dns_hostname' : dns_hostname,
|
form = FormAddRecord(initial={ 'dns_server' : dns_server,
|
||||||
'rr_domain' : zone_name })
|
'zone' : zone })
|
||||||
return render_to_response('bcommon/add_record_form.htm',
|
return render_to_response('bcommon/add_record_form.htm',
|
||||||
{ 'form' : form },
|
{ 'form' : form },
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
def add_record_result(request):
|
def view_add_record_result(request):
|
||||||
""" Process the input given to add a DNS record. """
|
""" Process the input given to add a DNS record. """
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
# Return home. You shouldn't be accessing the result
|
# Return home. You shouldn't be accessing this url via a GET.
|
||||||
# via a GET.
|
|
||||||
return redirect('/')
|
return redirect('/')
|
||||||
|
|
||||||
# We got a POST to add the result.
|
|
||||||
form = FormAddRecord(request.POST)
|
form = FormAddRecord(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
cd = form.cleaned_data
|
cd = form.cleaned_data
|
||||||
response = add_record(cd)
|
|
||||||
|
|
||||||
if 'errors' in response:
|
|
||||||
return render_to_response('bcommon/add_record_result.htm',
|
|
||||||
{ 'errors' : response['errors'] },
|
|
||||||
context_instance=RequestContext(request))
|
|
||||||
else:
|
else:
|
||||||
return render_to_response('bcommon/add_record_result.htm',
|
form = FormAddRecord(request.POST)
|
||||||
{ 'response' : response['response'] },
|
return render_to_response('bcommon/add_record_form.htm',
|
||||||
|
{ 'form' : form },
|
||||||
context_instance=RequestContext(request))
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
def view_delete_record(request):
|
|
||||||
|
key_dict = Key.objects.get(name=cd["key_name"])
|
||||||
|
add_record_response = add_record(cd, key_dict)
|
||||||
|
|
||||||
|
return render_to_response('bcommon/add_record_result.htm',
|
||||||
|
{ 'response' : add_record_response },
|
||||||
|
context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
|
||||||
|
### WORK ON BELOW
|
||||||
|
def confirm_delete_record(request):
|
||||||
if request.method == "GET":
|
if request.method == "GET":
|
||||||
# Return home. You shouldn't trying to directly acces
|
# Return home. You shouldn't trying to directly acces
|
||||||
# the url for deleting records.
|
# the url for deleting records.
|
||||||
|
@ -95,20 +92,33 @@ def view_delete_record(request):
|
||||||
rr_domain = request.POST['rr_domain']
|
rr_domain = request.POST['rr_domain']
|
||||||
rr_array = request.POST.getlist('rr_array')
|
rr_array = request.POST.getlist('rr_array')
|
||||||
|
|
||||||
if request.POST['delete_step'] == "initial":
|
## TODO(jforman): We need to handle the case where the POST data
|
||||||
""" We need to confirm they really want to delete the items. """
|
## is somehow bad.
|
||||||
return render_to_response('bcommon/delete_record_initial.htm',
|
return render_to_response('bcommon/delete_record_initial.htm',
|
||||||
{ 'rr_server' : rr_server,
|
{ 'rr_server' : rr_server,
|
||||||
'rr_domain' : rr_domain,
|
'rr_domain' : rr_domain,
|
||||||
'rr_array' : rr_array },
|
'rr_array' : rr_array,
|
||||||
context_instance=RequestContext(request))
|
'tsig_keys' : Key.objects.all() },
|
||||||
|
context_instance=RequestContext(request))
|
||||||
if request.POST['delete_step'] == "finalize":
|
|
||||||
# TODO: Instrument
|
|
||||||
""" Time to actually delete the records requested """
|
|
||||||
pass
|
|
||||||
|
|
||||||
# If we hit a case where we don't know what's going on.
|
# If we hit a case where we don't know what's going on.
|
||||||
return render_to_response('bcommon/index.htm',
|
# return render_to_response('bcommon/index.htm',
|
||||||
{ 'errors' : "We hit an unhandled exception in deleting your requested records." },
|
# { 'errors' : "We hit an unhandled exception in deleting your requested records." },
|
||||||
context_instance=RequestContext(request))
|
# context_instance=RequestContext(request))
|
||||||
|
|
||||||
|
def delete_result(request):
|
||||||
|
if request.method == "GET":
|
||||||
|
# Return home. You shouldn't trying to directly acces
|
||||||
|
# the url for deleting records.
|
||||||
|
return redirect('/')
|
||||||
|
|
||||||
|
to_delete_array = {}
|
||||||
|
to_delete_array['rr_server'] = request.POST['rr_server']
|
||||||
|
to_delete_array['rr_domain'] = request.POST['rr_domain']
|
||||||
|
to_delete_array['rr_array'] = eval(request.POST.getlist('rr_array')[0])
|
||||||
|
for current in to_delete_array['rr_array']:
|
||||||
|
print "current: %s" % current
|
||||||
|
|
||||||
|
to_delete_array['key_name'] = request.POST['key_name']
|
||||||
|
to_delete_array['key_data'] = Key.objects.get(name=(to_delete_array['key_name'])).data
|
||||||
|
delete_result = delete_record(to_delete_array)
|
||||||
|
|
|
@ -6,10 +6,19 @@
|
||||||
{% endblock pageheader %}
|
{% endblock pageheader %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% if not errors %}
|
{% if response.forward_response %}
|
||||||
Result:
|
Forward Record Creation Output
|
||||||
<pre>
|
<pre>
|
||||||
{{ response }}
|
{{ response.forward_response }}
|
||||||
</pre>
|
</pre>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{% if response.reverse_response %}
|
||||||
|
Reverse Record Creation Output
|
||||||
|
<pre>
|
||||||
|
{{ response.reverse_response }}
|
||||||
|
</pre>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
|
|
|
@ -2,18 +2,23 @@
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
||||||
<form action="/delete_record/" method="POST">{% csrf_token %}
|
<form action="/delete_record/result/" method="POST">{% csrf_token %}
|
||||||
<input type="hidden" name="rr_server" value="{{ rr_server }}">
|
<input type="hidden" name="rr_server" value="{{ rr_server }}">
|
||||||
<input type="hidden" name="rr_domain" value="{{ rr_domain }}">
|
<input type="hidden" name="rr_domain" value="{{ rr_domain }}">
|
||||||
<input type="hidden" name="rr_array" value="{{ rr_array }}">
|
<input type="hidden" name="rr_array" value="{{ rr_array }}">
|
||||||
<input type="hidden" name="delete_step" value="finalize">
|
<!-- <input type="hidden" name="delete_step" value="finalize"> -->
|
||||||
Do you really want to delete the following records?
|
Do you really want to delete the following records?
|
||||||
<ul>
|
<ul>
|
||||||
<li>Server: {{ rr_server }}</li>
|
<li>Server: {{ rr_server }}</li>
|
||||||
<li>Domain: {{ rr_domain }}</li>
|
<li>Domain: {{ rr_domain }}</li>
|
||||||
<li>Records: {{ rr_array }}</li>
|
<li>Records: {% for current_rr in rr_array %} {{ current_rr}} {% endfor %}</li>
|
||||||
|
<li>Key: <select name="key_name">
|
||||||
|
{% for current_key in tsig_keys %}
|
||||||
|
<option value="{{current_key}}">{{current_key}}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select> </li>
|
||||||
</ul>
|
</ul>
|
||||||
<input type="submit" value="Yes, I really want to really them."/>
|
<input type="submit" value="Yes, I really want to delete them."/>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% if not errors %}
|
{% if not errors %}
|
||||||
DNS Server Zone List:
|
DNS Server Zone List for {{ dns_hostname }}:
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{% for current_zone in zone_array %}
|
{% for current_zone in zone_array %}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
<form action="/delete_record/" method="post">{% csrf_token %}
|
<form action="/delete_record/" method="post">{% csrf_token %}
|
||||||
<input type="hidden" name="rr_server" value="{{ rr_server }}">
|
<input type="hidden" name="rr_server" value="{{ rr_server }}">
|
||||||
<input type="hidden" name="rr_domain" value="{{ rr_domain }}">
|
<input type="hidden" name="rr_domain" value="{{ rr_domain }}">
|
||||||
<input type="hidden" name="delete_step" value="initial">
|
|
||||||
{% for current_record in record_array %}
|
{% for current_record in record_array %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><input type="checkbox" name="rr_array" value="{{ current_record.rr_name }}"></td>
|
<td><input type="checkbox" name="rr_array" value="{{ current_record.rr_name }}"></td>
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
|
|
||||||
<ul>
|
<a href="/info/">Server List</a>
|
||||||
<li><a href="/info/">Server List</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% endblock body %}
|
{% endblock body %}
|
||||||
|
|
|
@ -9,11 +9,15 @@ urlpatterns = patterns('',
|
||||||
(r'^admin/', include(admin.site.urls)),
|
(r'^admin/', include(admin.site.urls)),
|
||||||
(r'^$', 'bcommon.views.home_index'),
|
(r'^$', 'bcommon.views.home_index'),
|
||||||
(r'^info/$', 'bcommon.views.list_servers'),
|
(r'^info/$', 'bcommon.views.list_servers'),
|
||||||
|
|
||||||
(r'^info/(?P<dns_hostname>[a-zA-Z0-9.-]+)/$', 'bcommon.views.view_server_zones'),
|
(r'^info/(?P<dns_hostname>[a-zA-Z0-9.-]+)/$', 'bcommon.views.view_server_zones'),
|
||||||
(r'^info/(?P<dns_hostname>[a-zA-Z0-9.-]+)/(?P<zone_name>[a-zA-Z0-9.-]+)/$', 'bcommon.views.view_zone_records'),
|
(r'^info/(?P<dns_hostname>[a-zA-Z0-9.-]+)/(?P<zone_name>[a-zA-Z0-9.-]+)/$', 'bcommon.views.view_zone_records'),
|
||||||
(r'^add_record/(?P<dns_hostname>[a-zA-Z0-9.-]+)/(?P<zone_name>[a-zA-Z0-9.-]+)/$', 'bcommon.views.view_add_record'),
|
|
||||||
(r'^add_record/result/$', 'bcommon.views.add_record_result'),
|
(r'^add_record/(?P<dns_server>[a-zA-Z0-9.-]+)/(?P<zone>[a-zA-Z0-9.-]+)/$', 'bcommon.views.view_add_record'),
|
||||||
(r'^delete_record/$', 'bcommon.views.view_delete_record'),
|
(r'^add_record/result/$', 'bcommon.views.view_add_record_result'),
|
||||||
|
|
||||||
|
# (r'^delete_record/$', 'bcommon.views.view_delete_record'),
|
||||||
|
# (r'^delete_record/result/$', 'bcommon.views.view_delete_result'),
|
||||||
)
|
)
|
||||||
|
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
|
|
Loading…
Reference in New Issue