Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/netaddr/strategy/eui48.py: 48%
135 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:45 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:45 +0000
1#-----------------------------------------------------------------------------
2# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
3#
4# Released under the BSD license. See the LICENSE file for details.
5#-----------------------------------------------------------------------------
6"""
7IEEE 48-bit EUI (MAC address) logic.
9Supports numerous MAC string formats including Cisco's triple hextet as well
10as bare MACs containing no delimiters.
11"""
12import struct as _struct
13import re as _re
15# Check whether we need to use fallback code or not.
16try:
17 from socket import AF_LINK
18except ImportError:
19 AF_LINK = 48
21from netaddr.core import AddrFormatError
22from netaddr.compat import _is_str
23from netaddr.strategy import (
24 valid_words as _valid_words, int_to_words as _int_to_words,
25 words_to_int as _words_to_int, valid_bits as _valid_bits,
26 bits_to_int as _bits_to_int, int_to_bits as _int_to_bits,
27 valid_bin as _valid_bin, int_to_bin as _int_to_bin,
28 bin_to_int as _bin_to_int)
30#: The width (in bits) of this address type.
31width = 48
33#: The AF_* constant value of this address type.
34family = AF_LINK
36#: A friendly string name address type.
37family_name = 'MAC'
39#: The version of this address type.
40version = 48
42#: The maximum integer value that can be represented by this address type.
43max_int = 2 ** width - 1
45#-----------------------------------------------------------------------------
46# Dialect classes.
47#-----------------------------------------------------------------------------
49class mac_eui48(object):
50 """A standard IEEE EUI-48 dialect class."""
51 #: The individual word size (in bits) of this address type.
52 word_size = 8
54 #: The number of words in this address type.
55 num_words = width // word_size
57 #: The maximum integer value for an individual word in this address type.
58 max_word = 2 ** word_size - 1
60 #: The separator character used between each word.
61 word_sep = '-'
63 #: The format string to be used when converting words to string values.
64 word_fmt = '%.2X'
66 #: The number base to be used when interpreting word values as integers.
67 word_base = 16
70class mac_unix(mac_eui48):
71 """A UNIX-style MAC address dialect class."""
72 word_size = 8
73 num_words = width // word_size
74 word_sep = ':'
75 word_fmt = '%x'
76 word_base = 16
79class mac_unix_expanded(mac_unix):
80 """A UNIX-style MAC address dialect class with leading zeroes."""
81 word_fmt = '%.2x'
84class mac_cisco(mac_eui48):
85 """A Cisco 'triple hextet' MAC address dialect class."""
86 word_size = 16
87 num_words = width // word_size
88 word_sep = '.'
89 word_fmt = '%.4x'
90 word_base = 16
93class mac_bare(mac_eui48):
94 """A bare (no delimiters) MAC address dialect class."""
95 word_size = 48
96 num_words = width // word_size
97 word_sep = ''
98 word_fmt = '%.12X'
99 word_base = 16
102class mac_pgsql(mac_eui48):
103 """A PostgreSQL style (2 x 24-bit words) MAC address dialect class."""
104 word_size = 24
105 num_words = width // word_size
106 word_sep = ':'
107 word_fmt = '%.6x'
108 word_base = 16
110#: The default dialect to be used when not specified by the user.
111DEFAULT_DIALECT = mac_eui48
113#-----------------------------------------------------------------------------
114#: Regular expressions to match all supported MAC address formats.
115RE_MAC_FORMATS = (
116 # 2 bytes x 6 (UNIX, Windows, EUI-48)
117 '^' + ':'.join(['([0-9A-F]{1,2})'] * 6) + '$',
118 '^' + '-'.join(['([0-9A-F]{1,2})'] * 6) + '$',
120 # 4 bytes x 3 (Cisco)
121 '^' + ':'.join(['([0-9A-F]{1,4})'] * 3) + '$',
122 '^' + '-'.join(['([0-9A-F]{1,4})'] * 3) + '$',
123 '^' + r'\.'.join(['([0-9A-F]{1,4})'] * 3) + '$',
125 # 6 bytes x 2 (PostgreSQL)
126 '^' + '-'.join(['([0-9A-F]{5,6})'] * 2) + '$',
127 '^' + ':'.join(['([0-9A-F]{5,6})'] * 2) + '$',
129 # 12 bytes (bare, no delimiters)
130 '^(' + ''.join(['[0-9A-F]'] * 12) + ')$',
131 '^(' + ''.join(['[0-9A-F]'] * 11) + ')$',
132)
133# For efficiency, each string regexp converted in place to its compiled
134# counterpart.
135RE_MAC_FORMATS = [_re.compile(_, _re.IGNORECASE) for _ in RE_MAC_FORMATS]
138def valid_str(addr):
139 """
140 :param addr: An IEEE EUI-48 (MAC) address in string form.
142 :return: ``True`` if MAC address string is valid, ``False`` otherwise.
143 """
144 for regexp in RE_MAC_FORMATS:
145 try:
146 match_result = regexp.findall(addr)
147 if len(match_result) != 0:
148 return True
149 except TypeError:
150 pass
152 return False
155def str_to_int(addr):
156 """
157 :param addr: An IEEE EUI-48 (MAC) address in string form.
159 :return: An unsigned integer that is equivalent to value represented
160 by EUI-48/MAC string address formatted according to the dialect
161 settings.
162 """
163 words = []
164 if _is_str(addr):
165 found_match = False
166 for regexp in RE_MAC_FORMATS:
167 match_result = regexp.findall(addr)
168 if len(match_result) != 0:
169 found_match = True
170 if isinstance(match_result[0], tuple):
171 words = match_result[0]
172 else:
173 words = (match_result[0],)
174 break
175 if not found_match:
176 raise AddrFormatError('%r is not a supported MAC format!' % (addr,))
177 else:
178 raise TypeError('%r is not str() or unicode()!' % (addr,))
180 int_val = None
182 if len(words) == 6:
183 # 2 bytes x 6 (UNIX, Windows, EUI-48)
184 int_val = int(''.join(['%.2x' % int(w, 16) for w in words]), 16)
185 elif len(words) == 3:
186 # 4 bytes x 3 (Cisco)
187 int_val = int(''.join(['%.4x' % int(w, 16) for w in words]), 16)
188 elif len(words) == 2:
189 # 6 bytes x 2 (PostgreSQL)
190 int_val = int(''.join(['%.6x' % int(w, 16) for w in words]), 16)
191 elif len(words) == 1:
192 # 12 bytes (bare, no delimiters)
193 int_val = int('%012x' % int(words[0], 16), 16)
194 else:
195 raise AddrFormatError('unexpected word count in MAC address %r!' % (addr,))
197 return int_val
200def int_to_str(int_val, dialect=None):
201 """
202 :param int_val: An unsigned integer.
204 :param dialect: (optional) a Python class defining formatting options.
206 :return: An IEEE EUI-48 (MAC) address string that is equivalent to
207 unsigned integer formatted according to the dialect settings.
208 """
209 if dialect is None:
210 dialect = mac_eui48
212 words = int_to_words(int_val, dialect)
213 tokens = [dialect.word_fmt % i for i in words]
214 addr = dialect.word_sep.join(tokens)
216 return addr
219def int_to_packed(int_val):
220 """
221 :param int_val: the integer to be packed.
223 :return: a packed string that is equivalent to value represented by an
224 unsigned integer.
225 """
226 return _struct.pack(">HI", int_val >> 32, int_val & 0xffffffff)
229def packed_to_int(packed_int):
230 """
231 :param packed_int: a packed string containing an unsigned integer.
232 It is assumed that string is packed in network byte order.
234 :return: An unsigned integer equivalent to value of network address
235 represented by packed binary string.
236 """
237 words = list(_struct.unpack('>6B', packed_int))
239 int_val = 0
240 for i, num in enumerate(reversed(words)):
241 word = num
242 word = word << 8 * i
243 int_val = int_val | word
245 return int_val
248def valid_words(words, dialect=None):
249 if dialect is None:
250 dialect = DEFAULT_DIALECT
251 return _valid_words(words, dialect.word_size, dialect.num_words)
254def int_to_words(int_val, dialect=None):
255 if dialect is None:
256 dialect = DEFAULT_DIALECT
257 return _int_to_words(int_val, dialect.word_size, dialect.num_words)
260def words_to_int(words, dialect=None):
261 if dialect is None:
262 dialect = DEFAULT_DIALECT
263 return _words_to_int(words, dialect.word_size, dialect.num_words)
266def valid_bits(bits, dialect=None):
267 if dialect is None:
268 dialect = DEFAULT_DIALECT
269 return _valid_bits(bits, width, dialect.word_sep)
272def bits_to_int(bits, dialect=None):
273 if dialect is None:
274 dialect = DEFAULT_DIALECT
275 return _bits_to_int(bits, width, dialect.word_sep)
278def int_to_bits(int_val, dialect=None):
279 if dialect is None:
280 dialect = DEFAULT_DIALECT
281 return _int_to_bits(
282 int_val, dialect.word_size, dialect.num_words, dialect.word_sep)
285def valid_bin(bin_val, dialect=None):
286 if dialect is None:
287 dialect = DEFAULT_DIALECT
288 return _valid_bin(bin_val, width)
291def int_to_bin(int_val):
292 return _int_to_bin(int_val, width)
295def bin_to_int(bin_val):
296 return _bin_to_int(bin_val, width)