e164.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. # Copyright (C) 2006, 2007, 2009, 2011 Nominum, Inc.
  2. #
  3. # Permission to use, copy, modify, and distribute this software and its
  4. # documentation for any purpose with or without fee is hereby granted,
  5. # provided that the above copyright notice and this permission notice
  6. # appear in all copies.
  7. #
  8. # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
  9. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
  11. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  14. # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. """DNS E.164 helpers
  16. @var public_enum_domain: The DNS public ENUM domain, e164.arpa.
  17. @type public_enum_domain: dns.name.Name object
  18. """
  19. import dns.exception
  20. import dns.name
  21. import dns.resolver
  22. from ._compat import string_types
  23. public_enum_domain = dns.name.from_text('e164.arpa.')
  24. def from_e164(text, origin=public_enum_domain):
  25. """Convert an E.164 number in textual form into a Name object whose
  26. value is the ENUM domain name for that number.
  27. @param text: an E.164 number in textual form.
  28. @type text: str
  29. @param origin: The domain in which the number should be constructed.
  30. The default is e164.arpa.
  31. @type origin: dns.name.Name object or None
  32. @rtype: dns.name.Name object
  33. """
  34. parts = [d for d in text if d.isdigit()]
  35. parts.reverse()
  36. return dns.name.from_text('.'.join(parts), origin=origin)
  37. def to_e164(name, origin=public_enum_domain, want_plus_prefix=True):
  38. """Convert an ENUM domain name into an E.164 number.
  39. @param name: the ENUM domain name.
  40. @type name: dns.name.Name object.
  41. @param origin: A domain containing the ENUM domain name. The
  42. name is relativized to this domain before being converted to text.
  43. @type origin: dns.name.Name object or None
  44. @param want_plus_prefix: if True, add a '+' to the beginning of the
  45. returned number.
  46. @rtype: str
  47. """
  48. if origin is not None:
  49. name = name.relativize(origin)
  50. dlabels = [d for d in name.labels if d.isdigit() and len(d) == 1]
  51. if len(dlabels) != len(name.labels):
  52. raise dns.exception.SyntaxError('non-digit labels in ENUM domain name')
  53. dlabels.reverse()
  54. text = b''.join(dlabels)
  55. if want_plus_prefix:
  56. text = b'+' + text
  57. return text
  58. def query(number, domains, resolver=None):
  59. """Look for NAPTR RRs for the specified number in the specified domains.
  60. e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.'])
  61. """
  62. if resolver is None:
  63. resolver = dns.resolver.get_default_resolver()
  64. e_nx = dns.resolver.NXDOMAIN()
  65. for domain in domains:
  66. if isinstance(domain, string_types):
  67. domain = dns.name.from_text(domain)
  68. qname = dns.e164.from_e164(number, domain)
  69. try:
  70. return resolver.query(qname, 'NAPTR')
  71. except dns.resolver.NXDOMAIN as e:
  72. e_nx += e
  73. raise e_nx