forked from dmyerscough/BIND-RESTful
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbind-api.py
More file actions
executable file
·154 lines (113 loc) · 4.52 KB
/
bind-api.py
File metadata and controls
executable file
·154 lines (113 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#!/usr/bin/env python
import ConfigParser
import dns.tsigkeyring
import dns.resolver
import dns.update
import dns.query
import dns.zone
from dns.rdatatype import *
from flask import Flask, jsonify, request
app = Flask(__name__)
def parse_config(config):
"""
Parse the user config and retreieve the nameserver, username and
password required to perform dynamic DNS updates
"""
options = {}
parser = ConfigParser.ConfigParser()
parser.read(config)
options['nameserver'] = parser.get('nameserver', 'server')
options['username'] = parser.get('auth', 'username')
options['password'] = parser.get('auth', 'password')
options['zones'] = [i + '.' for i in parser.get('zones', 'valid').split(",")]
return options
@app.route('/dns/zone/<string:zone_name>', methods=['GET'])
def get_zone(zone_name):
"""
Query a DNS zone file and get every record and return it in JSON
format
"""
config = parse_config('config.ini')
record_types = ['A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SOA']
valid_zones = config['zones']
records = {}
if not zone_name.endswith('.'):
zone_name = zone_name + '.'
if zone_name not in valid_zones:
return jsonify({'error': 'zone file not permitted'})
try:
zone = dns.zone.from_xfr(dns.query.xfr(config['nameserver'], zone_name))
except dns.exception.FormError:
return jsonify({'fail': zone_name})
for (name, ttl, rdata) in zone.iterate_rdatas():
if rdata.rdtype != SOA:
if records.get(str(name), 0):
records[str(name)] = records[str(name)] + [{'Answer': str(rdata), 'RecordType': rdata.rdtype, 'TTL': ttl}]
else:
records[str(name)] = [{'Answer': str(rdata), 'RecordType': rdata.rdtype, 'TTL': ttl}]
return jsonify({zone_name: records})
@app.route('/dns/record/<string:domain>', methods=['GET'])
def get_record(domain):
"""
Allow users to request the records for a particualr record
"""
config = parse_config('config.ini')
record_types = ['A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SOA']
valid_zones = config['zones']
record = {}
valid = [True for i in valid_zones if domain.endswith(i)]
"""
Only allow the valid zones to be queried, this should stop
TLD outside of your nameserver from being queried
"""
if valid:
for record_type in record_types:
try:
answers = dns.resolver.query(domain, record_type)
except dns.resolver.NoAnswer:
continue
record.update({record_type: [str(i) for i in answers.rrset]})
return jsonify({domain: record})
else:
return jsonify({'error': 'zone not permitted'})
@app.route('/dns/record/<string:domain>/<int:ttl>/<string:record_type>/<string:response>', methods=['PUT', 'POST', 'DELETE'])
def dns_mgmt(domain, ttl, record_type, response):
"""
Allow users to update existing records
"""
config = parse_config('config.ini')
record_types = ['A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT', 'SOA']
valid_zones = config['zones']
zone = ''
zone = '.'.join(dns.name.from_text(domain).labels[1:])
if record_type not in record_types:
return jsonify({'error': 'not a valid record type'})
if zone not in valid_zones:
return jsonify({'error': 'not a valid zone'})
"""
If the user is only updating make sure the record exists before
attempting to perform a dynamic update. This will
"""
if request.method == 'PUT' or request.method == 'DELETE':
resolver = dns.resolver.Resolver()
resolver.nameservers = [config['nameserver']]
try:
answer = resolver.query(domain, record_type)
except dns.resolver.NXDOMAIN:
return jsonify({'error': 'domain does not exist'})
tsig = dns.tsigkeyring.from_text({config['username']: config['password']})
action = dns.update.Update(zone, keyring=tsig)
if request.method == 'DELETE':
action.delete(dns.name.from_text(domain).labels[0])
elif request.method == 'PUT' or request.method == 'POST':
action.replace(dns.name.from_text(domain).labels[0], ttl, str(record_type), str(response))
try:
response = dns.query.tcp(action, config['nameserver'])
except:
return jsonify({'error': 'DNS transaction failed'})
if response.rcode() == 0:
return jsonify({domain: 'DNS request successful'})
else:
return jsonify({domain: 'DNS request failed'})
if __name__ == '__main__':
app.run(debug=True)