PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/netaddr/strategy/ipv6.py

https://github.com/sargun/netaddr
Python | 266 lines | 215 code | 21 blank | 30 comment | 8 complexity | 6cf0bfb071e57e41fbc136532ec39d7d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2008-2014, David P. D. Moss. All rights reserved.
  3. #
  4. # Released under the BSD license. See the LICENSE file for details.
  5. #-----------------------------------------------------------------------------
  6. """
  7. IPv6 address logic.
  8. """
  9. import struct as _struct
  10. OPT_IMPORTS = False
  11. # Check whether we need to use fallback code or not.
  12. try:
  13. import socket as _socket
  14. # These might all generate exceptions on different platforms.
  15. if not _socket.has_ipv6:
  16. raise Exception('IPv6 disabled')
  17. _socket.inet_pton
  18. _socket.AF_INET6
  19. from _socket import inet_pton as _inet_pton, \
  20. inet_ntop as _inet_ntop, \
  21. AF_INET6
  22. OPT_IMPORTS = True
  23. except Exception:
  24. from netaddr.fbsocket import inet_pton as _inet_pton, \
  25. inet_ntop as _inet_ntop, \
  26. AF_INET6
  27. from netaddr.core import AddrFormatError
  28. from netaddr.strategy import \
  29. valid_words as _valid_words, \
  30. int_to_words as _int_to_words, \
  31. words_to_int as _words_to_int, \
  32. valid_bits as _valid_bits, \
  33. bits_to_int as _bits_to_int, \
  34. int_to_bits as _int_to_bits, \
  35. valid_bin as _valid_bin, \
  36. int_to_bin as _int_to_bin, \
  37. bin_to_int as _bin_to_int
  38. #: The width (in bits) of this address type.
  39. width = 128
  40. #: The individual word size (in bits) of this address type.
  41. word_size = 16
  42. #: The separator character used between each word.
  43. word_sep = ':'
  44. #: The AF_* constant value of this address type.
  45. family = AF_INET6
  46. #: A friendly string name address type.
  47. family_name = 'IPv6'
  48. #: The version of this address type.
  49. version = 6
  50. #: The number base to be used when interpreting word values as integers.
  51. word_base = 16
  52. #: The maximum integer value that can be represented by this address type.
  53. max_int = 2 ** width - 1
  54. #: The number of words in this address type.
  55. num_words = width // word_size
  56. #: The maximum integer value for an individual word in this address type.
  57. max_word = 2 ** word_size - 1
  58. #: A dictionary mapping IPv6 CIDR prefixes to the equivalent netmasks.
  59. prefix_to_netmask = dict(
  60. [(i, max_int ^ (2 ** (width - i) - 1)) for i in range(0, width+1)])
  61. #: A dictionary mapping IPv6 netmasks to their equivalent CIDR prefixes.
  62. netmask_to_prefix = dict(
  63. [(max_int ^ (2 ** (width - i) - 1), i) for i in range(0, width+1)])
  64. #: A dictionary mapping IPv6 CIDR prefixes to the equivalent hostmasks.
  65. prefix_to_hostmask = dict(
  66. [(i, (2 ** (width - i) - 1)) for i in range(0, width+1)])
  67. #: A dictionary mapping IPv6 hostmasks to their equivalent CIDR prefixes.
  68. hostmask_to_prefix = dict(
  69. [((2 ** (width - i) - 1), i) for i in range(0, width+1)])
  70. #-----------------------------------------------------------------------------
  71. # Dialect classes.
  72. #-----------------------------------------------------------------------------
  73. class ipv6_compact(object):
  74. """An IPv6 dialect class - compact form."""
  75. #: The format string used to converting words into string values.
  76. word_fmt = '%x'
  77. #: Boolean flag indicating if IPv6 compaction algorithm should be used.
  78. compact = True
  79. class ipv6_full(ipv6_compact):
  80. """An IPv6 dialect class - 'all zeroes' form."""
  81. #: Boolean flag indicating if IPv6 compaction algorithm should be used.
  82. compact = False
  83. class ipv6_verbose(ipv6_compact):
  84. """An IPv6 dialect class - extra wide 'all zeroes' form."""
  85. #: The format string used to converting words into string values.
  86. word_fmt = '%.4x'
  87. #: Boolean flag indicating if IPv6 compaction algorithm should be used.
  88. compact = False
  89. #-----------------------------------------------------------------------------
  90. def valid_str(addr, flags=0):
  91. """
  92. :param addr: An IPv6 address in presentation (string) format.
  93. :param flags: decides which rules are applied to the interpretation of the
  94. addr value. Future use - currently has no effect.
  95. :return: ``True`` if IPv6 address is valid, ``False`` otherwise.
  96. """
  97. if addr == '':
  98. raise AddrFormatError('Empty strings are not supported!')
  99. try:
  100. _inet_pton(AF_INET6, addr)
  101. except:
  102. return False
  103. return True
  104. #-----------------------------------------------------------------------------
  105. def str_to_int(addr, flags=0):
  106. """
  107. :param addr: An IPv6 address in string form.
  108. :param flags: decides which rules are applied to the interpretation of the
  109. addr value. Future use - currently has no effect.
  110. :return: The equivalent unsigned integer for a given IPv6 address.
  111. """
  112. try:
  113. packed_int = _inet_pton(AF_INET6, addr)
  114. return packed_to_int(packed_int)
  115. except Exception:
  116. raise AddrFormatError('%r is not a valid IPv6 address string!' % addr)
  117. #-----------------------------------------------------------------------------
  118. def int_to_str(int_val, dialect=None):
  119. """
  120. :param int_val: An unsigned integer.
  121. :param dialect: (optional) a Python class defining formatting options.
  122. :return: The IPv6 presentation (string) format address equivalent to the
  123. unsigned integer provided.
  124. """
  125. if dialect is None:
  126. dialect = ipv6_compact
  127. addr = None
  128. try:
  129. packed_int = int_to_packed(int_val)
  130. if dialect.compact:
  131. # Default return value.
  132. addr = _inet_ntop(AF_INET6, packed_int)
  133. else:
  134. # Custom return value.
  135. words = list(_struct.unpack('>8H', packed_int))
  136. tokens = [dialect.word_fmt % word for word in words]
  137. addr = word_sep.join(tokens)
  138. except Exception:
  139. raise ValueError('%r is not a valid 128-bit unsigned integer!' \
  140. % int_val)
  141. return addr
  142. #-----------------------------------------------------------------------------
  143. def int_to_arpa(int_val):
  144. """
  145. :param int_val: An unsigned integer.
  146. :return: The reverse DNS lookup for an IPv6 address in network byte
  147. order integer form.
  148. """
  149. addr = int_to_str(int_val, ipv6_verbose)
  150. tokens = list(addr.replace(':', ''))
  151. tokens.reverse()
  152. # We won't support ip6.int here - see RFC 3152 for details.
  153. tokens = tokens + ['ip6', 'arpa', '']
  154. return '.'.join(tokens)
  155. #-----------------------------------------------------------------------------
  156. def int_to_packed(int_val):
  157. """
  158. :param int_val: the integer to be packed.
  159. :return: a packed string that is equivalent to value represented by an
  160. unsigned integer.
  161. """
  162. words = int_to_words(int_val, 4, 32)
  163. return _struct.pack('>4I', *words)
  164. #-----------------------------------------------------------------------------
  165. def packed_to_int(packed_int):
  166. """
  167. :param packed_int: a packed string containing an unsigned integer.
  168. It is assumed that string is packed in network byte order.
  169. :return: An unsigned integer equivalent to value of network address
  170. represented by packed binary string.
  171. """
  172. words = list(_struct.unpack('>4I', packed_int))
  173. int_val = 0
  174. for i, num in enumerate(reversed(words)):
  175. word = num
  176. word = word << 32 * i
  177. int_val = int_val | word
  178. return int_val
  179. #-----------------------------------------------------------------------------
  180. def valid_words(words):
  181. return _valid_words(words, word_size, num_words)
  182. #-----------------------------------------------------------------------------
  183. def int_to_words(int_val, num_words=None, word_size=None):
  184. if num_words is None:
  185. num_words = globals()['num_words']
  186. if word_size is None:
  187. word_size = globals()['word_size']
  188. return _int_to_words(int_val, word_size, num_words)
  189. #-----------------------------------------------------------------------------
  190. def words_to_int(words):
  191. return _words_to_int(words, word_size, num_words)
  192. #-----------------------------------------------------------------------------
  193. def valid_bits(bits):
  194. return _valid_bits(bits, width, word_sep)
  195. #-----------------------------------------------------------------------------
  196. def bits_to_int(bits):
  197. return _bits_to_int(bits, width, word_sep)
  198. #-----------------------------------------------------------------------------
  199. def int_to_bits(int_val, word_sep=None):
  200. if word_sep is None:
  201. word_sep = globals()['word_sep']
  202. return _int_to_bits(int_val, word_size, num_words, word_sep)
  203. #-----------------------------------------------------------------------------
  204. def valid_bin(bin_val):
  205. return _valid_bin(bin_val, width)
  206. #-----------------------------------------------------------------------------
  207. def int_to_bin(int_val):
  208. return _int_to_bin(int_val, width)
  209. #-----------------------------------------------------------------------------
  210. def bin_to_int(bin_val):
  211. return _bin_to_int(bin_val, width)