82 lines
4.6 KiB
Python
82 lines
4.6 KiB
Python
"""/dns: the primary name server of the router's domains."""
|
|
|
|
import vpnrouter
|
|
import vpnrouter_dns
|
|
from vpnrouter_status import run
|
|
|
|
from .common import section_change, unit_state
|
|
|
|
|
|
def dns(method, path, query, body):
|
|
"""Answer a /dns request with vpnrouter_dns: the HTTP status and the JSON document.
|
|
|
|
GET /dns {"settings", "installed", "running", "domains", "problem"}: the dns section of the
|
|
configuration, whether PowerDNS is installed and runs, the domains, each {"name", "sites",
|
|
"ttl", "secondaries", "manual", "records"} with its secondaries {"nameserver", "address"},
|
|
its manual records and the records the name server serves, and why the domains cannot be
|
|
read, null when they can
|
|
PUT /dns change any of the settings of the dns section
|
|
POST /dns/domains add a domain: {"name", "sites"?, "ttl"?}; sites gives the host names of the enabled sites
|
|
in it records; ttl is dns.ttl when null or absent; an existing name is 409
|
|
PUT /dns/domains/<domain>
|
|
change "sites" or "ttl" of the domain
|
|
DELETE /dns/domains/<domain>
|
|
remove the domain with its secondaries and manual records
|
|
POST /dns/domains/<domain>/secondaries
|
|
add a secondary name server of the domain, or change its address: {"nameserver", "address"}
|
|
DELETE /dns/domains/<domain>/secondaries/<nameserver>
|
|
remove the secondary name server
|
|
POST /dns/domains/<domain>/records
|
|
add a manual record: {"name", "type", "content", "ttl"?}; name is relative to the domain,
|
|
@ for the domain itself, or absolute with a final dot; ttl is the domain's without it
|
|
DELETE /dns/domains/<domain>/records
|
|
remove the manual records of name= and type=, with content= only that one
|
|
|
|
A change is applied by restarting vpn-router-setup without waiting for it.
|
|
"""
|
|
if body == 'invalid' or (body is not None and not isinstance(body, dict)):
|
|
return 400, {'error': 'the body must be a JSON object'}
|
|
body = body or {}
|
|
parts = path.strip('/').split('/')
|
|
route = (method, *parts[:2], *parts[3:4])
|
|
try:
|
|
cfg = vpnrouter.load_config()
|
|
if route == ('GET', 'dns'):
|
|
domains, problem = [], None
|
|
try:
|
|
domains = vpnrouter_dns.listing()
|
|
except vpnrouter_dns.DatabaseError as exc:
|
|
problem = str(exc)
|
|
return 200, {'settings': cfg['dns'], 'installed': vpnrouter_dns.PDNS_SERVER.exists(),
|
|
'running': unit_state(vpnrouter_dns.UNIT) == 'active', 'domains': domains,
|
|
'problem': problem}
|
|
if route == ('PUT', 'dns'):
|
|
changed = section_change('dns', body)
|
|
return changed if isinstance(changed, tuple) else (200, {'settings': changed})
|
|
if route == ('POST', 'dns', 'domains') and len(parts) == 2:
|
|
document, code = vpnrouter_dns.domain_add(body), 201
|
|
elif route == ('PUT', 'dns', 'domains') and len(parts) == 3:
|
|
document, code = vpnrouter_dns.domain_change(parts[2], body), 200
|
|
elif route == ('DELETE', 'dns', 'domains') and len(parts) == 3:
|
|
document, code = vpnrouter_dns.domain_remove(parts[2]), 200
|
|
elif route == ('POST', 'dns', 'domains', 'secondaries') and len(parts) == 4:
|
|
document, code = vpnrouter_dns.secondary_add(parts[2], body), 201
|
|
elif route == ('DELETE', 'dns', 'domains', 'secondaries') and len(parts) == 5:
|
|
document, code = vpnrouter_dns.secondary_remove(parts[2], parts[4]), 200
|
|
elif route == ('POST', 'dns', 'domains', 'records') and len(parts) == 4:
|
|
document, code = vpnrouter_dns.add(cfg, parts[2], body), 201
|
|
elif route == ('DELETE', 'dns', 'domains', 'records') and len(parts) == 4:
|
|
content = query.get('content', [None])[0]
|
|
document = vpnrouter_dns.remove(parts[2], query.get('name', [''])[0], query.get('type', [''])[0], content)
|
|
code = 200
|
|
else:
|
|
return 404, {'error': f'no route {method} {path}'}
|
|
except vpnrouter_dns.Failure as failure:
|
|
return {3: 404, 4: 409}.get(failure.status, 400), {'error': str(failure)}
|
|
except vpnrouter_dns.DatabaseError as exc:
|
|
return 500, {'error': str(exc)}
|
|
except SystemExit as exc:
|
|
return 500, {'error': str(exc.code)}
|
|
run('systemctl', 'restart', '--no-block', 'vpn-router-setup.service')
|
|
return code, document
|