No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dnshelper.py 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # This file is part of dnmgmt, a number resource management system
  2. # Licensed under GNU General Public License v3 or later
  3. # Written by Sebastian Lohff (seba@someserver.de)
  4. import dns.name
  5. import dns.message
  6. import dns.query
  7. import dns.resolver
  8. #from collections import defaultdict
  9. # FIXME: DNS timeouts
  10. def compareRecords(rrset, expected):
  11. result = {
  12. "nameMissing": [],
  13. "rrMissing": [],
  14. "rrExtra": [],
  15. }
  16. for domain, rrtype, content in expected:
  17. for rrrec in rrset:
  18. if domain == rrrec.name.to_text() and dns.rdatatype.from_text(rrtype) == rrrec.rdtype:
  19. for name in content:
  20. if name not in map(lambda _x: _x.to_text(), rrrec.items):
  21. # record missing
  22. result["rrMissing"].append((domain, rrtype, name))
  23. for item in rrrec.items:
  24. if item.to_text() not in content:
  25. # superfluous record
  26. result["rrExtra"].append((domain, rrtype, item.to_text()))
  27. break
  28. else:
  29. # domain + rr nicht in nameserver
  30. result["nameMissing"].append((domain, rrtype))
  31. success = not any(len(_x) > 0 for _x in result.values())
  32. return success, result
  33. def dnsQuery(domain, rrType, nameserverIp):
  34. dname = dns.name.from_text(domain)
  35. req = dns.message.make_query(dname, dns.rdatatype.from_text(rrType))
  36. resp = dns.query.udp(req, nameserverIp, timeout=2.0)
  37. if resp.rcode() != dns.rcode.NXDOMAIN:
  38. rrset = resp.answer + resp.authority + resp.additional
  39. return True, rrset
  40. else:
  41. return False, []
  42. def checkDomain(domain, tldNameserver, nameservers):
  43. result = []
  44. if nameservers.count() == 0:
  45. return [("err", "Domain %s has no nameservers attached to it, nothing to check" % domain)]
  46. # build record set
  47. nsRecords = [(domain, "NS", list(ns.name for ns in nameservers))]
  48. glueRecords = []
  49. for ns in nameservers:
  50. if ns.name.endswith("." + domain):
  51. if ns.glueIPv4 or ns.glueIPv6:
  52. if ns.glueIPv4:
  53. glueRecords.append((ns.name, "A", [ns.glueIPv4]))
  54. if ns.glueIPv6:
  55. glueRecords.append((ns.name, "AAAA", [ns.glueIPv6]))
  56. else:
  57. result.append(("err", "Nameserver %s is under domain %s, but has no glue entries." % (ns.name, domain)))
  58. # 1. TLD nameserver
  59. try:
  60. found, rrset = dnsQuery(domain, "ANY", tldNameserver)
  61. if found:
  62. success, errors = compareRecords(rrset, nsRecords + glueRecords)
  63. if success:
  64. result.append(("succ", "All records present in TLD nameserver"))
  65. else:
  66. result.append(("err", "Record mismatch between TLD nameserver and WHOIS database", errors))
  67. else:
  68. result.append(("err", "Domain %s not found in TLD nameserver" % (domain,)))
  69. except (dns.exception.Timeout, OSError):
  70. result.append(("err", "TLD nameserver is currently not reachable"))
  71. # find other records...
  72. # 2. your nameservers
  73. for ns in nameservers:
  74. addr = None
  75. if ns.glueIPv4:
  76. addr = ns.glueIPv4
  77. elif ns.glueIPv6:
  78. addr = ns.glueIPv6
  79. else:
  80. for rrType in ("A", "AAAA"):
  81. try:
  82. r = dns.resolver.Resolver()
  83. r.timeout = 2.0
  84. q = r.query(ns.name, rdtype=dns.rdatatype.from_text(rrType))
  85. addr = q.response.answer[0].items[0].address
  86. except (dns.exception.DNSException, OSError):
  87. pass
  88. if addr:
  89. err = False
  90. errDict = {"nameMissing": [], "rrMissing": [], "rrExtra": []}
  91. try:
  92. for rec in (nsRecords + glueRecords):
  93. found, rrset = dnsQuery(rec[0], rec[1], addr)
  94. #success, errors = compareRecords(rrset, nsRecords + glueRecords)
  95. success, errors = compareRecords(rrset, [rec])
  96. if not success:
  97. err = True
  98. for k in errors.keys():
  99. errDict[k].extend(errors[k])
  100. if not err:
  101. result.append(("succ", "Nameserver %s is configured correctly" % ns.name))
  102. else:
  103. result.append(("err", "Nameserver %s (via %s) recordset does not match the database" % (ns.name, addr), errDict))
  104. except (dns.exception.DNSException, OSError):
  105. result.append(("err", "Nameserver %s is not reachable (via %s)" % (ns.name, addr)))
  106. else:
  107. result.append(("err", "Can't resolv an ip address for nameserver %s" % ns.name))
  108. return result