louis 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module Louis
2
+ VERSION = "1.0.0"
3
+ end
data/lib/louis.rb ADDED
@@ -0,0 +1,90 @@
1
+ require "louis/version"
2
+
3
+ module Louis
4
+ OUI_FILE = File.expand_path(File.join(File.dirname(__FILE__), '..', 'data',
5
+ 'mac_oui_manuf.txt'))
6
+
7
+ OUI_FORMAT_REGEX = /^(?<prefix>[0-9a-fA-F:\-]+)(\/(?<mask>(\d+)))?\s+(?<short_vendor>\S+)(\s+# (?<long_vendor>.+))?$/
8
+
9
+ # Calculate the bit mask for testing whether or not a mac_prefix matches.
10
+ # This returns an integer with the upper X bits set where X is the mask
11
+ # length.
12
+ #
13
+ # @param [String] prefix
14
+ # @param [String] mask
15
+ # @return [Fixnum]
16
+ def self.calculate_mask(prefix, mask)
17
+ mask_base = mask.nil? ? (clean_mac(prefix).length * 4) : mask.to_i
18
+ (2 ** 48 - 1) - (2 ** (48 - mask_base) - 1)
19
+ end
20
+
21
+ # Returns the hex representing a full or partial MAC address with the
22
+ # 'connecting' characters removed. Does nothing to ensure length.
23
+ #
24
+ # @param [String] mac
25
+ # @return [String]
26
+ def self.clean_mac(mac)
27
+ mac.gsub(/[:-]/, '')
28
+ end
29
+
30
+ # Search through the OUI lookup table and return all the entries in the
31
+ # lookup table that match the provided MAC.
32
+ #
33
+ # @param [String] mac
34
+ # @return [Array<Hash<String=>Object>>]
35
+ def self.find_matches(mac)
36
+ @lookup_table.select { |m| mac_matches_prefix?(mac, m['prefix'], m['mask']) }
37
+ end
38
+
39
+ # Loads the lookup table, parsing out the uncommented non-blank lines into
40
+ # objects we can compare MACs against to find their vendor.
41
+ def self.load_lookup_table
42
+ return if @lookup_table
43
+ @lookup_table = []
44
+
45
+ File.open(OUI_FILE).each_line do |line|
46
+ if (matches = OUI_FORMAT_REGEX.match(line))
47
+ result = Hash[matches.names.zip(matches.captures)]
48
+
49
+ @lookup_table.push({
50
+ 'mask' => calculate_mask(result['prefix'], result['mask']),
51
+ 'prefix' => mac_to_num(result['prefix']),
52
+ 'short_vendor' => result['short_vendor'],
53
+ 'long_vendor' => result['long_vendor']
54
+ })
55
+ end
56
+ end
57
+ end
58
+
59
+ # Returns the name of the vendor that has the most specific prefix
60
+ # available in the OUI table or failing any matches will return "Unknown".
61
+ #
62
+ # @param [String] mac
63
+ # @return [String]
64
+ def self.lookup(mac)
65
+ load_lookup_table
66
+
67
+ o = find_matches(mac).sort_by { |m| m['prefix'] }.first
68
+ o ||= {'long_vendor' => 'Unknown', 'short_vendor' => 'Unknown'}
69
+
70
+ o.select { |k,_| %w(long_vendor short_vendor).include?(k) }
71
+ end
72
+
73
+ # Checks to see whether or not the MAC address has the provided prefix.
74
+ #
75
+ # @param [String] mac
76
+ # @param [Fixnum] prefix
77
+ # @param [Fixnum] mask
78
+ # @return [Boolean]
79
+ def self.mac_matches_prefix?(mac, prefix, mask)
80
+ (mac_to_num(mac) & mask) == prefix
81
+ end
82
+
83
+ # Converts a hexidecimal version of a full or partial (prefix) MAC address
84
+ # into it's integer representation.
85
+ #
86
+ # @param [String] mac
87
+ def self.mac_to_num(mac)
88
+ clean_mac(mac).ljust(12, '0').to_i(16)
89
+ end
90
+ end
data/louis.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+
6
+ require 'louis/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "louis"
10
+ spec.version = Louis::VERSION
11
+ spec.authors = ["Sam Stelfox"]
12
+ spec.email = ["sstelfox@bedroomprogrammers.net"]
13
+ spec.summary = %q{Library for looking up the the vendor associated with a MAC address.}
14
+ spec.description = %q{There is a public registry maintained by the IANA that is required to be used by all vendors operating in certains spaces. Ethernet, Bluetooth, and Wireless device manufacturers are all assigned unique prefixes. This database is available publicly online and can be used to identify the manufacturer of these devices. This library provides an easy mechanism to perform these lookups.}
15
+ spec.homepage = ""
16
+ spec.license = "AGPLv3"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.7"
24
+ spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rdoc"
27
+ spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "simplecov"
29
+ spec.add_development_dependency "yard"
30
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Louis do
4
+ it 'has a version number' do
5
+ expect(Louis::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ base_path = File.expand_path(File.join(File.basename(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(base_path) unless $LOAD_PATH.include?(base_path)
3
+
4
+ require 'rspec'
5
+ require 'simplecov'
6
+
7
+ SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
8
+ SimpleCov.add_filter "/spec/"
9
+ SimpleCov.add_filter do |source_file|
10
+ source_file.lines.count < 3
11
+ end
12
+
13
+ SimpleCov.start
14
+
15
+ require 'louis'
16
+
17
+ RSpec.configure do |config|
18
+ config.expect_with :rspec do |expectations|
19
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
20
+ end
21
+
22
+ config.mock_with :rspec do |mocks|
23
+ mocks.verify_partial_doubles = true
24
+ mocks.verify_doubled_constant_names = true
25
+ end
26
+
27
+ config.filter_run :focus
28
+ config.run_all_when_everything_filtered = true
29
+ config.disable_monkey_patching!
30
+ config.warnings = true
31
+
32
+ if config.files_to_run.one?
33
+ config.default_formatter = 'doc'
34
+ end
35
+
36
+ config.profile_examples = 3
37
+ config.order = :random
38
+
39
+ Kernel.srand(config.seed)
40
+ end
metadata ADDED
@@ -0,0 +1,163 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: louis
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Sam Stelfox
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rdoc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: yard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: There is a public registry maintained by the IANA that is required to
112
+ be used by all vendors operating in certains spaces. Ethernet, Bluetooth, and Wireless
113
+ device manufacturers are all assigned unique prefixes. This database is available
114
+ publicly online and can be used to identify the manufacturer of these devices. This
115
+ library provides an easy mechanism to perform these lookups.
116
+ email:
117
+ - sstelfox@bedroomprogrammers.net
118
+ executables: []
119
+ extensions: []
120
+ extra_rdoc_files: []
121
+ files:
122
+ - ".gitignore"
123
+ - ".rspec"
124
+ - ".travis.yml"
125
+ - ".yardopts"
126
+ - Gemfile
127
+ - LICENSE.txt
128
+ - README.md
129
+ - Rakefile
130
+ - data/mac_oui_manuf.txt
131
+ - lib/louis.rb
132
+ - lib/louis/version.rb
133
+ - louis.gemspec
134
+ - spec/louis_spec.rb
135
+ - spec/spec_helper.rb
136
+ homepage: ''
137
+ licenses:
138
+ - AGPLv3
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.4.3
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: Library for looking up the the vendor associated with a MAC address.
160
+ test_files:
161
+ - spec/louis_spec.rb
162
+ - spec/spec_helper.rb
163
+ has_rdoc: