pdns.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import json
  2. import requests
  3. from django.core.exceptions import SuspiciousOperation
  4. from api import settings as api_settings
  5. from desecapi.exceptions import PDNSException
  6. NSLORD = object()
  7. NSMASTER = object()
  8. settings = {
  9. NSLORD: {
  10. 'base_url': api_settings.NSLORD_PDNS_API,
  11. 'headers': {
  12. 'Accept': 'application/json',
  13. 'User-Agent': 'desecapi',
  14. 'X-API-Key': api_settings.NSLORD_PDNS_API_TOKEN,
  15. }
  16. },
  17. NSMASTER: {
  18. 'base_url': api_settings.NSMASTER_PDNS_API,
  19. 'headers': {
  20. 'Accept': 'application/json',
  21. 'User-Agent': 'desecapi',
  22. 'X-API-Key': api_settings.NSMASTER_PDNS_API_TOKEN,
  23. }
  24. }
  25. }
  26. def _pdns_request(method, *, server, path, body=None, acceptable_range=range(200, 300)):
  27. data = json.dumps(body) if body else None
  28. if data is not None and len(data) > api_settings.PDNS_MAX_BODY_SIZE:
  29. raise PDNSException(detail='Payload too large', status=413)
  30. r = requests.request(method, settings[server]['base_url'] + path, data=data, headers=settings[server]['headers'])
  31. if r.status_code not in acceptable_range:
  32. raise PDNSException(r)
  33. return r
  34. def _pdns_post(server, path, body):
  35. return _pdns_request('post', server=server, path=path, body=body)
  36. def _pdns_patch(server, path, body):
  37. return _pdns_request('patch', server=server, path=path, body=body)
  38. def _pdns_get(server, path):
  39. return _pdns_request('get', server=server, path=path, acceptable_range=range(200, 400)) # FIXME range
  40. def _pdns_put(server, path):
  41. return _pdns_request('put', server=server, path=path, acceptable_range=range(200, 500)) # FIXME range
  42. def _pdns_delete(server, path):
  43. return _pdns_request('delete', server=server, path=path)
  44. def pdns_id(name):
  45. # / is allowed by pdns, but we don't want it
  46. if '/' in name or '?' in name:
  47. raise SuspiciousOperation('Invalid hostname ' + name)
  48. # See also pdns code, apiZoneNameToId() in ws-api.cc
  49. name = name.translate(str.maketrans({'/': '=2F', '_': '=5F'}))
  50. return name.rstrip('.') + '.'
  51. def get_keys(domain):
  52. """
  53. Retrieves a dict representation of the DNSSEC key information
  54. """
  55. r = _pdns_get(NSLORD, '/zones/%s/cryptokeys' % pdns_id(domain.name))
  56. return [{k: key[k] for k in ('dnskey', 'ds', 'flags', 'keytype')}
  57. for key in r.json()
  58. if key['active'] and key['keytype'] in ['csk', 'ksk']]
  59. def get_zone(domain):
  60. """
  61. Retrieves a dict representation of the zone from pdns
  62. """
  63. r = _pdns_get(NSLORD, '/zones/' + pdns_id(domain.name))
  64. return r.json()
  65. def get_rrset_datas(domain):
  66. """
  67. Retrieves a dict representation of the RRsets in a given zone
  68. """
  69. return [{'domain': domain,
  70. 'subname': rrset['name'][:-(len(domain.name) + 2)],
  71. 'type': rrset['type'],
  72. 'records': [record['content'] for record in rrset['records']],
  73. 'ttl': rrset['ttl']}
  74. for rrset in get_zone(domain)['rrsets']]