Module: Louis

Defined in:
lib/louis.rb,
lib/louis/const.rb,
lib/louis/helpers.rb,
lib/louis/version.rb

Defined Under Namespace

Modules: Helpers

Constant Summary collapse

IGNORED_BITS_MASK =

This masks out both the ‘universal/local’ bit as well as the ‘unicast/multicast’ bit which is the first and second least significant bit of the first byte in a vendor prefix.

0xfcffffffffff
LOCALLY_ADMINISTERED_BIT =

Flag to indicate that this address is generated versus one assigned by a manufacturer.

0x020000000000
LOOKUP_TABLE =

Loads the lookup table, parsing out the uncommented non-blank lines into objects we can compare MACs against to find their vendor.

JSON.parse(File.read(Louis::PARSED_DATA_FILE))
MULTICAST_BIT =

Bit flag indicating that the address is directed at more than one recipient.

0x010000000000
ORIGINAL_OUI_FILE =
File.expand_path(File.join(File.dirname(__FILE__), \
'..', '..', 'data', 'mac_oui_manuf.txt')).freeze
PARSED_DATA_FILE =
File.expand_path(File.join(File.dirname(__FILE__), \
'..', '..', 'data', 'processed_data.json')).freeze
OUI_FORMAT_REGEX =
/^(?<prefix>[0-9a-fA-F:\-.]+)(\/(?<mask>(\d+)))?\s+(?<short_vendor>\S+)(\s+(?<long_vendor>.+))?$/.freeze
VERSION =
'2.3.7'

Class Method Summary collapse

Class Method Details

.lookup(mac) ⇒ String

Returns the name of the vendor that has the most specific prefix available in the OUI table or failing any matches will return “Unknown”.

Parameters:

  • mac (String)

Returns:

  • (String)


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/louis.rb', line 37

def self.lookup(mac)
  numeric_mac = Louis::Helpers.mac_to_num(mac)
  masked_mac = numeric_mac & IGNORED_BITS_MASK

  address_flags = []
  address_flags << (numeric_mac & MULTICAST_BIT > 0 ? :multicast : :unicast)
  address_flags << (numeric_mac & LOCALLY_ADMINISTERED_BIT > 0 ? :locally_generated : :manufacturer_generated)

  if (vendor = search_table(masked_mac))
    return {
      'flags' => address_flags,
      'long_vendor' => vendor['l'],
      'short_vendor' => vendor['s'],
    }.compact
  end

  # Try again, but this time don't ignore any bits (Looking at you
  # Google... with your 'da' prefix...)
  if (vendor = search_table(numeric_mac))
    return {
      'flags' => address_flags,
      'long_vendor' => vendor['l'],
      'short_vendor' => vendor['s'],
    }.compact
  end

  {'flags' => address_flags, 'long_vendor' => 'Unknown', 'short_vendor' => 'Unknown'}
end

.mask_keysvoid

Collect the recorded mask and order it appropriately from most specific to least.

Parameters:

  • (Array<Fixnum>)


28
29
30
# File 'lib/louis.rb', line 28

def self.mask_keys
  @mask_keys ||= LOOKUP_TABLE.keys.map(&:to_i).sort.reverse
end

.search_table(encoded_mac) ⇒ void



66
67
68
69
70
71
72
73
74
# File 'lib/louis.rb', line 66

def self.search_table(encoded_mac)
  mask_keys.each do |mask|
    table = LOOKUP_TABLE[mask.to_s]
    prefix = (encoded_mac & Louis::Helpers.calculate_mask(nil, mask)).to_s
    return table[prefix] if table.include?(prefix)
  end

  nil
end