#!/usr/bin/python # Copyright (c) 2009 Andy Barclay (Unixpeople) # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Sun Jan 17 15:00:52 UTC 2016 import cgi, os, re, sys import cgitb cgitb.enable() import StringIO import dns.resolver import dns.zone import dns.query import dns.update import dns.tsigkeyring from types import ListType def htmlHeader(title): print "Content-type: text/html\n" print "
Return to Main Page' print "" # end htmlFooter def gettype(id): m = re.match('^(.*):(.*):(.*)',id) return(m.group(1)) # end gettype def getdname(id): m = re.match('^(.*):(.*):(.*)',id) return(m.group(2)) # end getdname def getrdata(id): m = re.match('^(.*):(.*):(.*)',id) return(m.group(3)) # end getrdata def getTsigKey(zoneName): # zones in the file do not have "." at the end, so strip # the dot zoneName=zoneName.rstrip(".") # read all the zones from the file f=open(zonefile,'r') tsigkeyname=None for line in f: zlist=line.split() if (zlist[0]==zoneName): tsigkeyname=zlist[1] tsigkey=zlist[2] f.close() if (tsigkeyname == None): return(None) else: return(dns.tsigkeyring.from_text({tsigkeyname : tsigkey})) def getNameserver(zoneName): # zones in the file do not have "." at the end, so strip # the dot zoneName=zoneName.rstrip(".") # read all the zones from the file f=open(zonefile,'r') nameserver=None for line in f: zlist=line.split() if (zlist[0]==zoneName): # nameserver will always be the last in line nameserver=zlist[len(zlist)-1] f.close() if (nameserver == None): return(None) else: return(nameserver) def reverseIP(ip): m = re.match('(.*)\.(.*)\.(.*)\.(.*)',ip) return(m.group(4) + "." + m.group(3) + "." + m.group(2) + "." + m.group(1)) # end reverseip # returns the rest of the domain name passed - everything after first . def rest(ip): m = re.match('([^\.]*)\.(.*)',ip) return(m.group(2)) # end rest ################ main starts here ################## zonefile="/home/abarclay/config/zones.txt" #nameserver='192.168.37.12' #nameserver='107.21.97.57' try: TEST=os.environ["TEST"] except: TEST="false" if (TEST == "true"): # test basic functions print gettype("PTR:22:barclay.unixpeople.internal") print getdname("PTR:22:barclay.unixpeople.internal") print getrdata("PTR:22:barclay.unixpeople.internal") # test update # prepare the dns update myring = getTsigKey("unixpeople.com") nameserver = getNameserver("unixpeople.com") update = dns.update.Update("unixpeople.com", keyring=myring) # this succeeds, but doesn't work #update.delete("159.37.168.192.in-addr.arpa", "PTR", "alex.unixpeople.internal") # this succeeds, but doesn't work #update.delete("159.37.168.192.in-addr.arpa", "PTR", "alex.unixpeople.internal.") # this succeeds, but doesn't work #update.delete("159.37.168.192.in-addr.arpa.", "PTR", "alex.unixpeople.internal") # this one WORKS! # seems like both the dname and the rdata have to be fqdn #update.delete("162.37.168.192.in-addr.arpa.", "PTR", "kristen.unixpeople.internal.") # when we do two of them, it works too... #update.delete("172.37.168.192.in-addr.arpa.", "PTR", "DIRECTV-HR21-C30954D1.unixpeople.internal.") #update.delete("176.37.168.192.in-addr.arpa.", "PTR", "cessna.unixpeople.internal.") update.add("timeclock.unixpeople.com.", 86400, "CNAME", "annie.unixpeople.com.") #update.replace(rrname, myttl, mytype, myrrdata) response = dns.query.tcp(update, nameserver , timeout=10000) if (response.rcode()==0): print '
Success!
' else: print 'Failed!
' print 'rcode is
' print response.rcode() print response.to_text(response.rcode()) sys.exit(1) formVariables = cgi.FieldStorage() cgiScript="/cgi-bin/protected/dnstool.py" rrtypes=['ANY','A','CNAME','MX','NS','PTR','TXT', 'SOA'] # in future, lets add the name server to the zones.txt file try: myAction = formVariables["action"].value except: myAction = None if (myAction == 'Add a Resource Record'): htmlHeader("Add a Resource Record") # get zone to operate on try: myzone=formVariables["zone"].value except: print "You didn't select a zone to which you want to Add'
htmlFooter()
elif (myAction == "Edit Selected Resource Record"):
try:
myzone=formVariables["zone"].value
nameserver = getNameserver(myzone)
formtype=dns.rdatatype.from_text(formVariables["rrtype"].value)
except:
print "You didn't select a zone and rrtype to view
"
print "Go back and select a zone first"
htmlFooter()
sys.exit(0)
htmlHeader(myAction + ": " + myzone + " from server: " + nameserver)
print "not implemented"
htmlFooter()
elif (myAction == "Delete Selected Resource Records"):
htmlHeader("DNS Maintenance Tool")
try:
myzone=formVariables["zone"].value
nameserver = getNameserver(myzone)
except:
print "zones.txt file does not appear to contain a nameserver for zone: " + myzone + "
"
htmlFooter()
sys.exit(0)
# prepare the dns update
keyring = getTsigKey(myzone)
update = dns.update.Update(myzone, keyring=keyring)
# fully qualify the zonename
myzone=myzone + "."
# "selected" could be a list or a variable
try:
# assume it's a list...
for id in formVariables["selected"]:
print "about to delete " + id.value + " from " + myzone + '
'
myrrtype=gettype(id.value)
print "
myrrtype:" + myrrtype + ""
mydname=getdname(id.value)
mydname=mydname + "." + myzone
print "
mydame:" + mydname + ""
myrdata=getrdata(id.value)
print "
myrdata:" + myrdata + ""
print "
calling delete with " + mydname + " " + myrrtype + " " + myrdata
update.delete(mydname, myrrtype, myrdata)
except KeyError:
print "You didn't select any records to delete
"
print "Go back and select one or more records first"
htmlFooter()
sys.exit(0)
except:
# if selected was not a list, then we'll end up here...
id=formVariables["selected"]
print "about to delete " + id.value + " from " + myzone
myrrtype=gettype(id.value)
print "
myrrtype:" + myrrtype + ""
mydname=getdname(id.value)
mydname=mydname + "." + myzone
print "
mydame:" + mydname + ""
myrdata=getrdata(id.value)
print "
myrdata:" + myrdata + ""
print "
calling delete with " + mydname + " " + myrrtype + " " + myrdata
update.delete(mydname, myrrtype, myrdata)
response = dns.query.tcp(update, nameserver , timeout=10)
if (response.rcode()==0):
print '
Success!' else: print '
Failed!'
htmlFooter()
elif (myAction == 'Add Record'):
htmlHeader("DNS Maintenance Tool")
try:
myzone=formVariables["zone"].value
nameserver = getNameserver(myzone)
except:
print "zones.txt file does not appear to contain a nameserver for zone: " + myzone + "
"
htmlFooter()
sys.exit(0)
# prepare the dns update
keyring = getTsigKey(myzone)
update = dns.update.Update(myzone, keyring=keyring)
# the type will always be set
mytype=formVariables["rrtype"].value
myclass=formVariables["class"].value
myttl=formVariables["ttl"].value
# based on type, names of vars might be different
if (mytype == 'MX'):
try:
myrrdata=str(formVariables["preference"].value) + " " + formVariables["mailserver"].value
except:
print 'looks like you did not specify a preference and mail server'
print 'go back and specify them'
htmlFooter()
sys.exit(0)
# otherwise, its a common name
else:
try:
rrname=formVariables["rrname"].value
except:
rrname=""
try:
myrrdata=formVariables["rrdata"].value
except:
print "You didn't type in anything for the rdata
"
print "Go back and type something in"
htmlFooter()
sys.exit(0)
# see if it's fully qualified
fq=re.compile(".*\.$")
if ((mytype == 'PTR') and (not (fq.match(myrrdata)))):
myrrdata = myrrdata + "."
print "about to add " + rrname + " " + myttl + " " + myclass + " " + mytype + " " + myrrdata + " to " + myzone + '
'
# changed from update.replace
update.add(rrname, myttl, mytype, myrrdata)
response = dns.query.tcp(update, nameserver , timeout=10)
if (response.rcode()==0):
print '
Success!' else: print '
Failed!' # if the record type is an A record and addptr is true, then add # the ptr record too try: addptr=formVariables["addptr"].value except: addptr="0" if ((mytype == 'A') and (addptr=='1')): print '
Adding PTR too!'
tmpname=rrname
rrname=reverseIP(myrrdata) + ".in-addr.arpa."
originalzone=myzone
myzone=rrname
myrrdata=tmpname
# if myrrdata not fully qualified, add original myzone
fq=re.compile(".*\.$")
if (not (fq.match(myrrdata))):
myrrdata = myrrdata + "." + originalzone + "."
mytype="PTR"
keyring=None
while ((keyring==None) and (myzone != "")):
print "looking for zone " + myzone + '
'
myzone=rest(myzone)
keyring = getTsigKey(myzone)
if (myzone != ""):
update = dns.update.Update(myzone, keyring=keyring)
update.replace(rrname, myttl, mytype, myrrdata)
print "about to add " + rrname + " " + myttl + " " + myclass + " " + mytype + " " + myrrdata + " to " + myzone + '
'
response = dns.query.tcp(update, nameserver , timeout=10)
else:
print "unable to add PTR - can't find zone"
htmlFooter()
else:
htmlHeader("DNS Maintenance Tool")
print "unknown action"
htmlFooter()