inet.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
  2. # Copyright (C) 2003-2017 Nominum, Inc.
  3. #
  4. # Permission to use, copy, modify, and distribute this software and its
  5. # documentation for any purpose with or without fee is hereby granted,
  6. # provided that the above copyright notice and this permission notice
  7. # appear in all copies.
  8. #
  9. # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
  10. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
  12. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  15. # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. """Generic Internet address helper functions."""
  17. import socket
  18. import dns.ipv4
  19. import dns.ipv6
  20. # We assume that AF_INET and AF_INET6 are always defined. We keep
  21. # these here for the benefit of any old code (unlikely though that
  22. # is!).
  23. AF_INET = socket.AF_INET
  24. AF_INET6 = socket.AF_INET6
  25. def inet_pton(family, text):
  26. """Convert the textual form of a network address into its binary form.
  27. *family* is an ``int``, the address family.
  28. *text* is a ``str``, the textual address.
  29. Raises ``NotImplementedError`` if the address family specified is not
  30. implemented.
  31. Returns a ``bytes``.
  32. """
  33. if family == AF_INET:
  34. return dns.ipv4.inet_aton(text)
  35. elif family == AF_INET6:
  36. return dns.ipv6.inet_aton(text, True)
  37. else:
  38. raise NotImplementedError
  39. def inet_ntop(family, address):
  40. """Convert the binary form of a network address into its textual form.
  41. *family* is an ``int``, the address family.
  42. *address* is a ``bytes``, the network address in binary form.
  43. Raises ``NotImplementedError`` if the address family specified is not
  44. implemented.
  45. Returns a ``str``.
  46. """
  47. if family == AF_INET:
  48. return dns.ipv4.inet_ntoa(address)
  49. elif family == AF_INET6:
  50. return dns.ipv6.inet_ntoa(address)
  51. else:
  52. raise NotImplementedError
  53. def af_for_address(text):
  54. """Determine the address family of a textual-form network address.
  55. *text*, a ``str``, the textual address.
  56. Raises ``ValueError`` if the address family cannot be determined
  57. from the input.
  58. Returns an ``int``.
  59. """
  60. try:
  61. dns.ipv4.inet_aton(text)
  62. return AF_INET
  63. except Exception:
  64. try:
  65. dns.ipv6.inet_aton(text, True)
  66. return AF_INET6
  67. except Exception:
  68. raise ValueError
  69. def is_multicast(text):
  70. """Is the textual-form network address a multicast address?
  71. *text*, a ``str``, the textual address.
  72. Raises ``ValueError`` if the address family cannot be determined
  73. from the input.
  74. Returns a ``bool``.
  75. """
  76. try:
  77. first = dns.ipv4.inet_aton(text)[0]
  78. return first >= 224 and first <= 239
  79. except Exception:
  80. try:
  81. first = dns.ipv6.inet_aton(text, True)[0]
  82. return first == 255
  83. except Exception:
  84. raise ValueError
  85. def is_address(text):
  86. """Is the specified string an IPv4 or IPv6 address?
  87. *text*, a ``str``, the textual address.
  88. Returns a ``bool``.
  89. """
  90. try:
  91. dns.ipv4.inet_aton(text)
  92. return True
  93. except Exception:
  94. try:
  95. dns.ipv6.inet_aton(text, True)
  96. return True
  97. except Exception:
  98. return False
  99. def low_level_address_tuple(high_tuple, af=None):
  100. """Given a "high-level" address tuple, i.e.
  101. an (address, port) return the appropriate "low-level" address tuple
  102. suitable for use in socket calls.
  103. If an *af* other than ``None`` is provided, it is assumed the
  104. address in the high-level tuple is valid and has that af. If af
  105. is ``None``, then af_for_address will be called.
  106. """
  107. address, port = high_tuple
  108. if af is None:
  109. af = af_for_address(address)
  110. if af == AF_INET:
  111. return (address, port)
  112. elif af == AF_INET6:
  113. i = address.find('%')
  114. if i < 0:
  115. # no scope, shortcut!
  116. return (address, port, 0, 0)
  117. # try to avoid getaddrinfo()
  118. addrpart = address[:i]
  119. scope = address[i + 1:]
  120. if scope.isdigit():
  121. return (addrpart, port, 0, int(scope))
  122. try:
  123. return (addrpart, port, 0, socket.if_nametoindex(scope))
  124. except AttributeError: # pragma: no cover (we can't really test this)
  125. ai_flags = socket.AI_NUMERICHOST
  126. ((*_, tup), *_) = socket.getaddrinfo(address, port, flags=ai_flags)
  127. return tup
  128. else:
  129. raise NotImplementedError(f'unknown address family {af}')