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

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. 

8 

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 

14 

15# Check whether we need to use fallback code or not. 

16try: 

17 from socket import AF_LINK 

18except ImportError: 

19 AF_LINK = 48 

20 

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) 

29 

30#: The width (in bits) of this address type. 

31width = 48 

32 

33#: The AF_* constant value of this address type. 

34family = AF_LINK 

35 

36#: A friendly string name address type. 

37family_name = 'MAC' 

38 

39#: The version of this address type. 

40version = 48 

41 

42#: The maximum integer value that can be represented by this address type. 

43max_int = 2 ** width - 1 

44 

45#----------------------------------------------------------------------------- 

46# Dialect classes. 

47#----------------------------------------------------------------------------- 

48 

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 

53 

54 #: The number of words in this address type. 

55 num_words = width // word_size 

56 

57 #: The maximum integer value for an individual word in this address type. 

58 max_word = 2 ** word_size - 1 

59 

60 #: The separator character used between each word. 

61 word_sep = '-' 

62 

63 #: The format string to be used when converting words to string values. 

64 word_fmt = '%.2X' 

65 

66 #: The number base to be used when interpreting word values as integers. 

67 word_base = 16 

68 

69 

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 

77 

78 

79class mac_unix_expanded(mac_unix): 

80 """A UNIX-style MAC address dialect class with leading zeroes.""" 

81 word_fmt = '%.2x' 

82 

83 

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 

91 

92 

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 

100 

101 

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 

109 

110#: The default dialect to be used when not specified by the user. 

111DEFAULT_DIALECT = mac_eui48 

112 

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) + '$', 

119 

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) + '$', 

124 

125 # 6 bytes x 2 (PostgreSQL) 

126 '^' + '-'.join(['([0-9A-F]{5,6})'] * 2) + '$', 

127 '^' + ':'.join(['([0-9A-F]{5,6})'] * 2) + '$', 

128 

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] 

136 

137 

138def valid_str(addr): 

139 """ 

140 :param addr: An IEEE EUI-48 (MAC) address in string form. 

141 

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 

151 

152 return False 

153 

154 

155def str_to_int(addr): 

156 """ 

157 :param addr: An IEEE EUI-48 (MAC) address in string form. 

158 

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,)) 

179 

180 int_val = None 

181 

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,)) 

196 

197 return int_val 

198 

199 

200def int_to_str(int_val, dialect=None): 

201 """ 

202 :param int_val: An unsigned integer. 

203 

204 :param dialect: (optional) a Python class defining formatting options. 

205 

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 

211 

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) 

215 

216 return addr 

217 

218 

219def int_to_packed(int_val): 

220 """ 

221 :param int_val: the integer to be packed. 

222 

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) 

227 

228 

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. 

233 

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)) 

238 

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 

244 

245 return int_val 

246 

247 

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) 

252 

253 

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) 

258 

259 

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) 

264 

265 

266def valid_bits(bits, dialect=None): 

267 if dialect is None: 

268 dialect = DEFAULT_DIALECT 

269 return _valid_bits(bits, width, dialect.word_sep) 

270 

271 

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) 

276 

277 

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) 

283 

284 

285def valid_bin(bin_val, dialect=None): 

286 if dialect is None: 

287 dialect = DEFAULT_DIALECT 

288 return _valid_bin(bin_val, width) 

289 

290 

291def int_to_bin(int_val): 

292 return _int_to_bin(int_val, width) 

293 

294 

295def bin_to_int(bin_val): 

296 return _bin_to_int(bin_val, width)