fix vendor

This commit is contained in:
2023-09-07 12:06:13 +03:00
parent 4963339b34
commit 731ddbc133
130 changed files with 253704 additions and 0 deletions

749
vendor/netaddr/eui/__init__.py vendored Normal file
View File

@@ -0,0 +1,749 @@
#-----------------------------------------------------------------------------
# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
#
# Released under the BSD license. See the LICENSE file for details.
#-----------------------------------------------------------------------------
"""
Classes and functions for dealing with MAC addresses, EUI-48, EUI-64, OUI, IAB
identifiers.
"""
from netaddr.core import NotRegisteredError, AddrFormatError, DictDotLookup
from netaddr.strategy import eui48 as _eui48, eui64 as _eui64
from netaddr.strategy.eui48 import mac_eui48
from netaddr.strategy.eui64 import eui64_base
from netaddr.ip import IPAddress
from netaddr.compat import _importlib_resources, _is_int, _is_str
class BaseIdentifier(object):
"""Base class for all IEEE identifiers."""
__slots__ = ('_value', '__weakref__')
def __init__(self):
self._value = None
def __int__(self):
""":return: integer value of this identifier"""
return self._value
def __long__(self):
""":return: integer value of this identifier"""
return self._value
def __oct__(self):
""":return: octal string representation of this identifier."""
# Python 2.x only.
if self._value == 0:
return '0'
return '0%o' % self._value
def __hex__(self):
""":return: hexadecimal string representation of this identifier."""
# Python 2.x only.
return '0x%x' % self._value
def __index__(self):
"""
:return: return the integer value of this identifier when passed to
hex(), oct() or bin().
"""
# Python 3.x only.
return self._value
class OUI(BaseIdentifier):
"""
An individual IEEE OUI (Organisationally Unique Identifier).
For online details see - http://standards.ieee.org/regauth/oui/
"""
__slots__ = ('records',)
def __init__(self, oui):
"""
Constructor
:param oui: an OUI string ``XX-XX-XX`` or an unsigned integer. \
Also accepts and parses full MAC/EUI-48 address strings (but not \
MAC/EUI-48 integers)!
"""
super(OUI, self).__init__()
# Lazy loading of IEEE data structures.
from netaddr.eui import ieee
self.records = []
if isinstance(oui, str):
#TODO: Improve string parsing here.
#TODO: Accept full MAC/EUI-48 addressses as well as XX-XX-XX
#TODO: and just take /16 (see IAB for details)
self._value = int(oui.replace('-', ''), 16)
elif _is_int(oui):
if 0 <= oui <= 0xffffff:
self._value = oui
else:
raise ValueError('OUI int outside expected range: %r' % (oui,))
else:
raise TypeError('unexpected OUI format: %r' % (oui,))
# Discover offsets.
if self._value in ieee.OUI_INDEX:
fh = _importlib_resources.open_binary(__package__, 'oui.txt')
for (offset, size) in ieee.OUI_INDEX[self._value]:
fh.seek(offset)
data = fh.read(size).decode('UTF-8')
self._parse_data(data, offset, size)
fh.close()
else:
raise NotRegisteredError('OUI %r not registered!' % (oui,))
def __eq__(self, other):
if not isinstance(other, OUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return self._value == other._value
def __ne__(self, other):
if not isinstance(other, OUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return self._value != other._value
def __getstate__(self):
""":returns: Pickled state of an `OUI` object."""
return self._value, self.records
def __setstate__(self, state):
""":param state: data used to unpickle a pickled `OUI` object."""
self._value, self.records = state
def _parse_data(self, data, offset, size):
"""Returns a dict record from raw OUI record data"""
record = {
'idx': 0,
'oui': '',
'org': '',
'address': [],
'offset': offset,
'size': size,
}
for line in data.split("\n"):
line = line.strip()
if not line:
continue
if '(hex)' in line:
record['idx'] = self._value
record['org'] = line.split(None, 2)[2]
record['oui'] = str(self)
elif '(base 16)' in line:
continue
else:
record['address'].append(line)
self.records.append(record)
@property
def reg_count(self):
"""Number of registered organisations with this OUI"""
return len(self.records)
def registration(self, index=0):
"""
The IEEE registration details for this OUI.
:param index: the index of record (may contain multiple registrations)
(Default: 0 - first registration)
:return: Objectified Python data structure containing registration
details.
"""
return DictDotLookup(self.records[index])
def __str__(self):
""":return: string representation of this OUI"""
int_val = self._value
return "%02X-%02X-%02X" % (
(int_val >> 16) & 0xff,
(int_val >> 8) & 0xff,
int_val & 0xff)
def __repr__(self):
""":return: executable Python string to recreate equivalent object."""
return "OUI('%s')" % self
class IAB(BaseIdentifier):
IAB_EUI_VALUES = (0x0050c2, 0x40d855)
"""
An individual IEEE IAB (Individual Address Block) identifier.
For online details see - http://standards.ieee.org/regauth/oui/
"""
__slots__ = ('record',)
@classmethod
def split_iab_mac(cls, eui_int, strict=False):
"""
:param eui_int: a MAC IAB as an unsigned integer.
:param strict: If True, raises a ValueError if the last 12 bits of
IAB MAC/EUI-48 address are non-zero, ignores them otherwise.
(Default: False)
"""
if (eui_int >> 12) in cls.IAB_EUI_VALUES:
return eui_int, 0
user_mask = 2 ** 12 - 1
iab_mask = (2 ** 48 - 1) ^ user_mask
iab_bits = eui_int >> 12
user_bits = (eui_int | iab_mask) - iab_mask
if (iab_bits >> 12) in cls.IAB_EUI_VALUES:
if strict and user_bits != 0:
raise ValueError('%r is not a strict IAB!' % hex(user_bits))
else:
raise ValueError('%r is not an IAB address!' % hex(eui_int))
return iab_bits, user_bits
def __init__(self, iab, strict=False):
"""
Constructor
:param iab: an IAB string ``00-50-C2-XX-X0-00`` or an unsigned \
integer. This address looks like an EUI-48 but it should not \
have any non-zero bits in the last 3 bytes.
:param strict: If True, raises a ValueError if the last 12 bits \
of IAB MAC/EUI-48 address are non-zero, ignores them otherwise. \
(Default: False)
"""
super(IAB, self).__init__()
# Lazy loading of IEEE data structures.
from netaddr.eui import ieee
self.record = {
'idx': 0,
'iab': '',
'org': '',
'address': [],
'offset': 0,
'size': 0,
}
if isinstance(iab, str):
#TODO: Improve string parsing here.
#TODO: '00-50-C2' is actually invalid.
#TODO: Should be '00-50-C2-00-00-00' (i.e. a full MAC/EUI-48)
int_val = int(iab.replace('-', ''), 16)
iab_int, user_int = self.split_iab_mac(int_val, strict=strict)
self._value = iab_int
elif _is_int(iab):
iab_int, user_int = self.split_iab_mac(iab, strict=strict)
self._value = iab_int
else:
raise TypeError('unexpected IAB format: %r!' % (iab,))
# Discover offsets.
if self._value in ieee.IAB_INDEX:
fh = _importlib_resources.open_binary(__package__, 'iab.txt')
(offset, size) = ieee.IAB_INDEX[self._value][0]
self.record['offset'] = offset
self.record['size'] = size
fh.seek(offset)
data = fh.read(size).decode('UTF-8')
self._parse_data(data, offset, size)
fh.close()
else:
raise NotRegisteredError('IAB %r not unregistered!' % (iab,))
def __eq__(self, other):
if not isinstance(other, IAB):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return self._value == other._value
def __ne__(self, other):
if not isinstance(other, IAB):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return self._value != other._value
def __getstate__(self):
""":returns: Pickled state of an `IAB` object."""
return self._value, self.record
def __setstate__(self, state):
""":param state: data used to unpickle a pickled `IAB` object."""
self._value, self.record = state
def _parse_data(self, data, offset, size):
"""Returns a dict record from raw IAB record data"""
for line in data.split("\n"):
line = line.strip()
if not line:
continue
if '(hex)' in line:
self.record['idx'] = self._value
self.record['org'] = line.split(None, 2)[2]
self.record['iab'] = str(self)
elif '(base 16)' in line:
continue
else:
self.record['address'].append(line)
def registration(self):
"""The IEEE registration details for this IAB"""
return DictDotLookup(self.record)
def __str__(self):
""":return: string representation of this IAB"""
int_val = self._value << 4
return "%02X-%02X-%02X-%02X-%02X-00" % (
(int_val >> 32) & 0xff,
(int_val >> 24) & 0xff,
(int_val >> 16) & 0xff,
(int_val >> 8) & 0xff,
int_val & 0xff)
def __repr__(self):
""":return: executable Python string to recreate equivalent object."""
return "IAB('%s')" % self
class EUI(BaseIdentifier):
"""
An IEEE EUI (Extended Unique Identifier).
Both EUI-48 (used for layer 2 MAC addresses) and EUI-64 are supported.
Input parsing for EUI-48 addresses is flexible, supporting many MAC
variants.
"""
__slots__ = ('_module', '_dialect')
def __init__(self, addr, version=None, dialect=None):
"""
Constructor.
:param addr: an EUI-48 (MAC) or EUI-64 address in string format or \
an unsigned integer. May also be another EUI object (copy \
construction).
:param version: (optional) the explicit EUI address version, either \
48 or 64. Mainly used to distinguish EUI-48 and EUI-64 identifiers \
specified as integers which may be numerically equivalent.
:param dialect: (optional) the mac_* dialect to be used to configure \
the formatting of EUI-48 (MAC) addresses.
"""
super(EUI, self).__init__()
self._module = None
if isinstance(addr, EUI):
# Copy constructor.
if version is not None and version != addr._module.version:
raise ValueError('cannot switch EUI versions using '
'copy constructor!')
self._module = addr._module
self._value = addr._value
self.dialect = addr.dialect
return
if version is not None:
if version == 48:
self._module = _eui48
elif version == 64:
self._module = _eui64
else:
raise ValueError('unsupported EUI version %r' % version)
else:
# Choose a default version when addr is an integer and version is
# not specified.
if _is_int(addr):
if 0 <= addr <= 0xffffffffffff:
self._module = _eui48
elif 0xffffffffffff < addr <= 0xffffffffffffffff:
self._module = _eui64
self.value = addr
# Choose a dialect for MAC formatting.
self.dialect = dialect
def __getstate__(self):
""":returns: Pickled state of an `EUI` object."""
return self._value, self._module.version, self.dialect
def __setstate__(self, state):
"""
:param state: data used to unpickle a pickled `EUI` object.
"""
value, version, dialect = state
self._value = value
if version == 48:
self._module = _eui48
elif version == 64:
self._module = _eui64
else:
raise ValueError('unpickling failed for object state: %s' \
% (state,))
self.dialect = dialect
def _get_value(self):
return self._value
def _set_value(self, value):
if self._module is None:
# EUI version is implicit, detect it from value.
for module in (_eui48, _eui64):
try:
self._value = module.str_to_int(value)
self._module = module
break
except AddrFormatError:
try:
if 0 <= int(value) <= module.max_int:
self._value = int(value)
self._module = module
break
except ValueError:
pass
if self._module is None:
raise AddrFormatError('failed to detect EUI version: %r'
% (value,))
else:
# EUI version is explicit.
if _is_str(value):
try:
self._value = self._module.str_to_int(value)
except AddrFormatError:
raise AddrFormatError('address %r is not an EUIv%d'
% (value, self._module.version))
else:
if 0 <= int(value) <= self._module.max_int:
self._value = int(value)
else:
raise AddrFormatError('bad address format: %r' % (value,))
value = property(_get_value, _set_value, None,
'a positive integer representing the value of this EUI indentifier.')
def _get_dialect(self):
return self._dialect
def _validate_dialect(self, value):
if value is None:
if self._module is _eui64:
return eui64_base
else:
return mac_eui48
else:
if hasattr(value, 'word_size') and hasattr(value, 'word_fmt'):
return value
else:
raise TypeError('custom dialects should subclass mac_eui48!')
def _set_dialect(self, value):
self._dialect = self._validate_dialect(value)
dialect = property(_get_dialect, _set_dialect, None,
"a Python class providing support for the interpretation of "
"various MAC\n address formats.")
@property
def oui(self):
"""The OUI (Organisationally Unique Identifier) for this EUI."""
if self._module == _eui48:
return OUI(self.value >> 24)
elif self._module == _eui64:
return OUI(self.value >> 40)
@property
def ei(self):
"""The EI (Extension Identifier) for this EUI"""
if self._module == _eui48:
return '%02X-%02X-%02X' % tuple(self[3:6])
elif self._module == _eui64:
return '%02X-%02X-%02X-%02X-%02X' % tuple(self[3:8])
def is_iab(self):
""":return: True if this EUI is an IAB address, False otherwise"""
return (self._value >> 24) in IAB.IAB_EUI_VALUES
@property
def iab(self):
"""
If is_iab() is True, the IAB (Individual Address Block) is returned,
``None`` otherwise.
"""
if self.is_iab():
return IAB(self._value >> 12)
@property
def version(self):
"""The EUI version represented by this EUI object."""
return self._module.version
def __getitem__(self, idx):
"""
:return: The integer value of the word referenced by index (both \
positive and negative). Raises ``IndexError`` if index is out \
of bounds. Also supports Python list slices for accessing \
word groups.
"""
if _is_int(idx):
# Indexing, including negative indexing goodness.
num_words = self._dialect.num_words
if not (-num_words) <= idx <= (num_words - 1):
raise IndexError('index out range for address type!')
return self._module.int_to_words(self._value, self._dialect)[idx]
elif isinstance(idx, slice):
words = self._module.int_to_words(self._value, self._dialect)
return [words[i] for i in range(*idx.indices(len(words)))]
else:
raise TypeError('unsupported type %r!' % (idx,))
def __setitem__(self, idx, value):
"""Set the value of the word referenced by index in this address"""
if isinstance(idx, slice):
# TODO - settable slices.
raise NotImplementedError('settable slices are not supported!')
if not _is_int(idx):
raise TypeError('index not an integer!')
if not 0 <= idx <= (self._dialect.num_words - 1):
raise IndexError('index %d outside address type boundary!' % (idx,))
if not _is_int(value):
raise TypeError('value not an integer!')
if not 0 <= value <= self._dialect.max_word:
raise IndexError('value %d outside word size maximum of %d bits!'
% (value, self._dialect.word_size))
words = list(self._module.int_to_words(self._value, self._dialect))
words[idx] = value
self._value = self._module.words_to_int(words)
def __hash__(self):
""":return: hash of this EUI object suitable for dict keys, sets etc"""
return hash((self.version, self._value))
def __eq__(self, other):
"""
:return: ``True`` if this EUI object is numerically the same as other, \
``False`` otherwise.
"""
if not isinstance(other, EUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return (self.version, self._value) == (other.version, other._value)
def __ne__(self, other):
"""
:return: ``True`` if this EUI object is numerically the same as other, \
``False`` otherwise.
"""
if not isinstance(other, EUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return (self.version, self._value) != (other.version, other._value)
def __lt__(self, other):
"""
:return: ``True`` if this EUI object is numerically lower in value than \
other, ``False`` otherwise.
"""
if not isinstance(other, EUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return (self.version, self._value) < (other.version, other._value)
def __le__(self, other):
"""
:return: ``True`` if this EUI object is numerically lower or equal in \
value to other, ``False`` otherwise.
"""
if not isinstance(other, EUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return (self.version, self._value) <= (other.version, other._value)
def __gt__(self, other):
"""
:return: ``True`` if this EUI object is numerically greater in value \
than other, ``False`` otherwise.
"""
if not isinstance(other, EUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return (self.version, self._value) > (other.version, other._value)
def __ge__(self, other):
"""
:return: ``True`` if this EUI object is numerically greater or equal \
in value to other, ``False`` otherwise.
"""
if not isinstance(other, EUI):
try:
other = self.__class__(other)
except Exception:
return NotImplemented
return (self.version, self._value) >= (other.version, other._value)
def bits(self, word_sep=None):
"""
:param word_sep: (optional) the separator to insert between words. \
Default: None - use default separator for address type.
:return: human-readable binary digit string of this address.
"""
return self._module.int_to_bits(self._value, word_sep)
@property
def packed(self):
"""The value of this EUI address as a packed binary string."""
return self._module.int_to_packed(self._value)
@property
def words(self):
"""A list of unsigned integer octets found in this EUI address."""
return self._module.int_to_words(self._value)
@property
def bin(self):
"""
The value of this EUI adddress in standard Python binary
representational form (0bxxx). A back port of the format provided by
the builtin bin() function found in Python 2.6.x and higher.
"""
return self._module.int_to_bin(self._value)
def eui64(self):
"""
- If this object represents an EUI-48 it is converted to EUI-64 \
as per the standard.
- If this object is already an EUI-64, a new, numerically \
equivalent object is returned instead.
:return: The value of this EUI object as a new 64-bit EUI object.
"""
if self.version == 48:
# Convert 11:22:33:44:55:66 into 11:22:33:FF:FE:44:55:66.
first_three = self._value >> 24
last_three = self._value & 0xffffff
new_value = (first_three << 40) | 0xfffe000000 | last_three
else:
# is already a EUI64
new_value = self._value
return self.__class__(new_value, version=64)
def modified_eui64(self):
"""
- create a new EUI object with a modified EUI-64 as described in RFC 4291 section 2.5.1
:return: a new and modified 64-bit EUI object.
"""
# Modified EUI-64 format interface identifiers are formed by inverting
# the "u" bit (universal/local bit in IEEE EUI-64 terminology) when
# forming the interface identifier from IEEE EUI-64 identifiers. In
# the resulting Modified EUI-64 format, the "u" bit is set to one (1)
# to indicate universal scope, and it is set to zero (0) to indicate
# local scope.
eui64 = self.eui64()
eui64._value ^= 0x00000000000000000200000000000000
return eui64
def ipv6(self, prefix):
"""
.. note:: This poses security risks in certain scenarios. \
Please read RFC 4941 for details. Reference: RFCs 4291 and 4941.
:param prefix: ipv6 prefix
:return: new IPv6 `IPAddress` object based on this `EUI` \
using the technique described in RFC 4291.
"""
int_val = int(prefix) + int(self.modified_eui64())
return IPAddress(int_val, version=6)
def ipv6_link_local(self):
"""
.. note:: This poses security risks in certain scenarios. \
Please read RFC 4941 for details. Reference: RFCs 4291 and 4941.
:return: new link local IPv6 `IPAddress` object based on this `EUI` \
using the technique described in RFC 4291.
"""
return self.ipv6(0xfe800000000000000000000000000000)
@property
def info(self):
"""
A record dict containing IEEE registration details for this EUI
(MAC-48) if available, None otherwise.
"""
data = {'OUI': self.oui.registration()}
if self.is_iab():
data['IAB'] = self.iab.registration()
return DictDotLookup(data)
def format(self, dialect=None):
"""
Format the EUI into the representational format according to the given
dialect
:param dialect: the mac_* dialect defining the formatting of EUI-48 \
(MAC) addresses.
:return: EUI in representational format according to the given dialect
"""
validated_dialect = self._validate_dialect(dialect)
return self._module.int_to_str(self._value, validated_dialect)
def __str__(self):
""":return: EUI in representational format"""
return self._module.int_to_str(self._value, self._dialect)
def __repr__(self):
""":return: executable Python string to recreate equivalent object."""
return "EUI('%s')" % self

4575
vendor/netaddr/eui/iab.idx vendored Normal file

File diff suppressed because it is too large Load Diff

27381
vendor/netaddr/eui/iab.txt vendored Normal file

File diff suppressed because it is too large Load Diff

293
vendor/netaddr/eui/ieee.py vendored Normal file
View File

@@ -0,0 +1,293 @@
#!/usr/bin/env python
#-----------------------------------------------------------------------------
# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
#
# Released under the BSD license. See the LICENSE file for details.
#-----------------------------------------------------------------------------
#
# DISCLAIMER
#
# netaddr is not sponsored nor endorsed by the IEEE.
#
# Use of data from the IEEE (Institute of Electrical and Electronics
# Engineers) is subject to copyright. See the following URL for
# details :-
#
# - http://www.ieee.org/web/publications/rights/legal.html
#
# IEEE data files included with netaddr are not modified in any way but are
# parsed and made available to end users through an API. There is no
# guarantee that referenced files are not out of date.
#
# See README file and source code for URLs to latest copies of the relevant
# files.
#
#-----------------------------------------------------------------------------
"""
Provides access to public OUI and IAB registration data published by the IEEE.
More details can be found at the following URLs :-
- IEEE Home Page - http://www.ieee.org/
- Registration Authority Home Page - http://standards.ieee.org/regauth/
"""
import os.path as _path
import csv as _csv
from netaddr.compat import _bytes_type, _importlib_resources
from netaddr.core import Subscriber, Publisher
#: OUI index lookup dictionary.
OUI_INDEX = {}
#: IAB index lookup dictionary.
IAB_INDEX = {}
class FileIndexer(Subscriber):
"""
A concrete Subscriber that receives OUI record offset information that is
written to an index data file as a set of comma separated records.
"""
def __init__(self, index_file):
"""
Constructor.
:param index_file: a file-like object or name of index file where
index records will be written.
"""
if hasattr(index_file, 'readline') and hasattr(index_file, 'tell'):
self.fh = index_file
else:
self.fh = open(index_file, 'w')
self.writer = _csv.writer(self.fh, lineterminator="\n")
def update(self, data):
"""
Receives and writes index data to a CSV data file.
:param data: record containing offset record information.
"""
self.writer.writerow(data)
class OUIIndexParser(Publisher):
"""
A concrete Publisher that parses OUI (Organisationally Unique Identifier)
records from IEEE text-based registration files
It notifies registered Subscribers as each record is encountered, passing
on the record's position relative to the start of the file (offset) and
the size of the record (in bytes).
The file processed by this parser is available online from this URL :-
- http://standards.ieee.org/regauth/oui/oui.txt
This is a sample of the record structure expected::
00-CA-FE (hex) ACME CORPORATION
00CAFE (base 16) ACME CORPORATION
1 MAIN STREET
SPRINGFIELD
UNITED STATES
"""
def __init__(self, ieee_file):
"""
Constructor.
:param ieee_file: a file-like object or name of file containing OUI
records. When using a file-like object always open it in binary
mode otherwise offsets will probably misbehave.
"""
super(OUIIndexParser, self).__init__()
if hasattr(ieee_file, 'readline') and hasattr(ieee_file, 'tell'):
self.fh = ieee_file
else:
self.fh = open(ieee_file, 'rb')
def parse(self):
"""
Starts the parsing process which detects records and notifies
registered subscribers as it finds each OUI record.
"""
skip_header = True
record = None
size = 0
marker = _bytes_type('(hex)')
hyphen = _bytes_type('-')
empty_string = _bytes_type('')
while True:
line = self.fh.readline()
if not line:
break # EOF, we're done
if skip_header and marker in line:
skip_header = False
if skip_header:
# ignoring header section
continue
if marker in line:
# record start
if record is not None:
# a complete record.
record.append(size)
self.notify(record)
size = len(line)
offset = (self.fh.tell() - len(line))
oui = line.split()[0]
index = int(oui.replace(hyphen, empty_string), 16)
record = [index, offset]
else:
# within record
size += len(line)
# process final record on loop exit
record.append(size)
self.notify(record)
class IABIndexParser(Publisher):
"""
A concrete Publisher that parses IAB (Individual Address Block) records
from IEEE text-based registration files
It notifies registered Subscribers as each record is encountered, passing
on the record's position relative to the start of the file (offset) and
the size of the record (in bytes).
The file processed by this parser is available online from this URL :-
- http://standards.ieee.org/regauth/oui/iab.txt
This is a sample of the record structure expected::
00-50-C2 (hex) ACME CORPORATION
ABC000-ABCFFF (base 16) ACME CORPORATION
1 MAIN STREET
SPRINGFIELD
UNITED STATES
"""
def __init__(self, ieee_file):
"""
Constructor.
:param ieee_file: a file-like object or name of file containing IAB
records. When using a file-like object always open it in binary
mode otherwise offsets will probably misbehave.
"""
super(IABIndexParser, self).__init__()
if hasattr(ieee_file, 'readline') and hasattr(ieee_file, 'tell'):
self.fh = ieee_file
else:
self.fh = open(ieee_file, 'rb')
def parse(self):
"""
Starts the parsing process which detects records and notifies
registered subscribers as it finds each IAB record.
"""
skip_header = True
record = None
size = 0
hex_marker = _bytes_type('(hex)')
base16_marker = _bytes_type('(base 16)')
hyphen = _bytes_type('-')
empty_string = _bytes_type('')
while True:
line = self.fh.readline()
if not line:
break # EOF, we're done
if skip_header and hex_marker in line:
skip_header = False
if skip_header:
# ignoring header section
continue
if hex_marker in line:
# record start
if record is not None:
record.append(size)
self.notify(record)
offset = (self.fh.tell() - len(line))
iab_prefix = line.split()[0]
index = iab_prefix
record = [index, offset]
size = len(line)
elif base16_marker in line:
# within record
size += len(line)
prefix = record[0].replace(hyphen, empty_string)
suffix = line.split()[0]
suffix = suffix.split(hyphen)[0]
record[0] = (int(prefix + suffix, 16)) >> 12
else:
# within record
size += len(line)
# process final record on loop exit
record.append(size)
self.notify(record)
def create_index_from_registry(registry_fh, index_path, parser):
"""Generate an index files from the IEEE registry file."""
oui_parser = parser(registry_fh)
oui_parser.attach(FileIndexer(index_path))
oui_parser.parse()
def create_indices():
"""Create indices for OUI and IAB file based lookups"""
create_index_from_registry(
_path.join(_path.dirname(__file__), 'oui.txt'),
_path.join(_path.dirname(__file__), 'oui.idx'),
OUIIndexParser,
)
create_index_from_registry(
_path.join(_path.dirname(__file__), 'iab.txt'),
_path.join(_path.dirname(__file__), 'iab.idx'),
IABIndexParser,
)
def load_index(index, fp):
"""Load index from file into index data structure."""
try:
for row in _csv.reader([x.decode('UTF-8') for x in fp]):
(key, offset, size) = [int(_) for _ in row]
index.setdefault(key, [])
index[key].append((offset, size))
finally:
fp.close()
def load_indices():
"""Load OUI and IAB lookup indices into memory"""
load_index(OUI_INDEX, _importlib_resources.open_binary(__package__, 'oui.idx'))
load_index(IAB_INDEX, _importlib_resources.open_binary(__package__, 'iab.idx'))
if __name__ == '__main__':
# Generate indices when module is executed as a script.
create_indices()
else:
# On module load read indices in memory to enable lookups.
load_indices()

28112
vendor/netaddr/eui/oui.idx vendored Normal file

File diff suppressed because it is too large Load Diff

168378
vendor/netaddr/eui/oui.txt vendored Normal file

File diff suppressed because it is too large Load Diff