oui-offline 1.2.5-java

Sign up to get free protection for your applications and to get access to all the features.
data/db/oui.sqlite3 ADDED
Binary file
data/lib/oui.rb ADDED
@@ -0,0 +1,380 @@
1
+ autoload :FileUtils, 'fileutils'
2
+ autoload :JSON, 'json'
3
+ require 'monitor'
4
+ require 'open-uri'
5
+
6
+ require 'sequel'
7
+
8
+ # Organizationally Unique Identifier
9
+ module OUI
10
+ extend self
11
+
12
+ private
13
+
14
+ DEBUGGING_DEFAULT = false
15
+ TABLE = :ouis
16
+ # import data/oui.txt instead of fetching remotely
17
+ IMPORT_LOCAL_TXT_FILE_DEFAULT = false
18
+ # use in-memory instead of persistent file
19
+ IN_MEMORY_ONLY_DEFAULT = false
20
+ ROOT = File.expand_path(File.join('..', '..'), __FILE__)
21
+ LOCAL_DB_DEFAULT = File.join(ROOT, 'db', 'oui.sqlite3')
22
+ LOCAL_TXT_FILE = File.join(ROOT, 'data', 'oui.txt')
23
+ REMOTE_TXT_URI = 'http://standards.ieee.org/develop/regauth/oui/oui.txt'
24
+ LOCAL_MANUAL_FILE = File.join(ROOT, 'data', 'oui-manual.json')
25
+ FIRST_LINE_INDEX = 7
26
+ EXPECTED_DUPLICATES = [0x0001C8, 0x080030]
27
+ LINE_LENGTH = 22
28
+ HEX_BEGINNING_REGEX = /\A[[:space:]]{2}[[:xdigit:]]{2}-/
29
+ ERASE_LINE = "\b" * LINE_LENGTH
30
+ BLANK_LINE = ' ' * LINE_LENGTH
31
+
32
+ MISSING_COUNTRIES = [
33
+ 0x000052,
34
+ 0x002142,
35
+ 0x684CA8
36
+ ]
37
+
38
+ COUNTRY_OVERRIDES = {
39
+ 0x000052 => 'UNITED STATES',
40
+ 0x002142 => 'SERBIA',
41
+ 0x684CA8 => 'CHINA'
42
+ }
43
+
44
+ public
45
+
46
+ @@local_db = LOCAL_DB_DEFAULT
47
+
48
+ def local_db
49
+ @@local_db
50
+ end
51
+
52
+ def local_db=(v)
53
+ @@local_db = v || LOCAL_DB_DEFAULT
54
+ end
55
+
56
+
57
+ @@debugging = DEBUGGING_DEFAULT
58
+
59
+ def debugging
60
+ @@debugging
61
+ end
62
+
63
+ def debugging=(v)
64
+ @@debugging = (v.nil?) ? DEBUGGING_DEFAULT : v
65
+ end
66
+
67
+
68
+ @@import_local_txt_file = IMPORT_LOCAL_TXT_FILE_DEFAULT
69
+
70
+ def import_local_txt_file
71
+ @@import_local_txt_file
72
+ end
73
+
74
+ def import_local_txt_file=(v)
75
+ @@import_local_txt_file = (v.nil?) ? IMPORT_LOCAL_TXT_FILE_DEFAULT : v
76
+ end
77
+
78
+
79
+ @@in_memory_only = IN_MEMORY_ONLY_DEFAULT
80
+
81
+ def in_memory_only
82
+ @@in_memory_only
83
+ end
84
+
85
+ def in_memory_only=(v)
86
+ if v != @@in_memory_only
87
+ @@in_memory_only = (v.nil?) ? IN_MEMORY_ONLY_DEFAULT : v
88
+ close_db
89
+ end
90
+ end
91
+
92
+ # @param oui [String,Integer] hex or numeric OUI to find
93
+ # @return [Hash,nil]
94
+ def find(oui)
95
+ semaphore.synchronize do
96
+ update_db unless table? && table.count > 0
97
+ r = table.where(id: self.to_i(oui)).first
98
+ r.delete :create_table if r # not sure why this is here, but nuking it
99
+ r
100
+ end
101
+ end
102
+
103
+ # Converts an OUI string to an integer of equal value
104
+ # @param oui [String,Integer] MAC OUI in hexadecimal formats
105
+ # hhhh.hh, hh:hh:hh, hh-hh-hh or hhhhhh
106
+ # @return [Integer] numeric representation of oui
107
+ def to_i(oui)
108
+ return oui if oui.is_a? Integer
109
+ oui = oui.strip.gsub(/[:\- .]/, '')
110
+ if oui =~ /([[:xdigit:]]{6})/
111
+ $1.to_i(16)
112
+ end
113
+ end
114
+
115
+ # Convert an id to OUI
116
+ # @param oui [String,nil] string to place between pairs of hex digits, nil for none
117
+ # @return [String] hexadecimal format of id
118
+ def to_s(id, sep = '-')
119
+ return id if id.is_a? String
120
+ unless id >= 0x000000 && id <= 0xFFFFFF
121
+ raise ArgumentError, "#{id} is not a valid 24-bit OUI"
122
+ end
123
+ format('%06x', id).scan(/../).join(sep)
124
+ end
125
+
126
+ @@db = nil
127
+ # Release backend resources
128
+ def close_db
129
+ semaphore.synchronize do
130
+ debug 'Closing database'
131
+ if @@db
132
+ @@db.disconnect
133
+ @@db = nil
134
+ end
135
+ end
136
+ end
137
+
138
+ def clear_table
139
+ debug 'clear_table'
140
+ table.delete_sql
141
+ end
142
+
143
+ # Update database from fetched URL
144
+ # @param [Boolean] whether to connect to the network or not
145
+ # @return [Integer] number of unique records loaded
146
+ def update_db(local = nil, db_file = nil)
147
+ semaphore.synchronize do
148
+ debug "update_db(local = #{local}, db_file = #{db_file})"
149
+ close_db
150
+ old_import_local_txt_file = self.import_local_txt_file
151
+ self.import_local_txt_file = local
152
+ old_local_db = self.local_db
153
+ self.local_db = db_file
154
+ ## Sequel
155
+ debug '--- close db ---'
156
+ debug '--- close db ---'
157
+ debug '--- drop table ---'
158
+ drop_table
159
+ # debug '--- drop table ---'
160
+ # debug '--- create table ---'
161
+ create_table
162
+ # debug '--- create table ---'
163
+ db.transaction do
164
+ debug '--- clear table ---'
165
+ clear_table
166
+ debug '--- clear table ---'
167
+ debug '--- install manual ---'
168
+ install_manual
169
+ debug '--- install manual ---'
170
+ debug '--- install updates ---'
171
+ install_updates
172
+ debug '--- install updates ---'
173
+ end
174
+ debug '--- close db ---'
175
+ close_db
176
+ debug '--- close db ---'
177
+
178
+ self.local_db = old_local_db
179
+ self.import_local_txt_file = old_import_local_txt_file
180
+ ## AR
181
+ # self.transaction do
182
+ # self.delete_all
183
+ # self.install_manual
184
+ # self.install_updates
185
+ # end
186
+ debug "update_db(local = #{local}, db_file = #{db_file}) finish"
187
+ end
188
+ end
189
+
190
+ private
191
+
192
+ def connect_file_db(f)
193
+ FileUtils.mkdir_p(File.dirname(f))
194
+ if RUBY_PLATFORM == 'java'
195
+ u = 'jdbc:sqlite:'+f
196
+ else
197
+ u = 'sqlite:'+f
198
+ end
199
+ debug "Connecting to db file #{u}"
200
+ Sequel.connect(u)
201
+ end
202
+
203
+ def connect_db
204
+ if in_memory_only
205
+ debug 'Connecting to in-memory database'
206
+ if RUBY_PLATFORM == 'java'
207
+ Sequel.connect('jdbc:sqlite::memory:')
208
+ else
209
+ Sequel.sqlite # in-memory sqlite database
210
+ end
211
+ else
212
+ connect_file_db local_db
213
+ end
214
+ end
215
+
216
+ def db
217
+ @@db ||= connect_db
218
+ end
219
+
220
+ def table?
221
+ db.tables.include? TABLE
222
+ end
223
+
224
+ def table
225
+ db[TABLE]
226
+ end
227
+
228
+ def drop_table
229
+ debug 'drop_table'
230
+ db.drop_table(TABLE) if table?
231
+ end
232
+
233
+ def create_table
234
+ # debug 'create_table'
235
+ db.create_table TABLE do
236
+ primary_key :id
237
+ String :organization, null: false
238
+ String :address1
239
+ String :address2
240
+ String :address3
241
+ String :country
242
+ index :id
243
+ end
244
+ end
245
+
246
+ # @param lines [Array<String>]
247
+ # @return [Array<Array<String>>]
248
+ def parse_lines_into_groups(lines)
249
+ grps, curgrp = [], []
250
+ lines[FIRST_LINE_INDEX..-1].each do |line|
251
+ if !curgrp.empty? && line =~ HEX_BEGINNING_REGEX
252
+ grps << curgrp
253
+ curgrp = []
254
+ end
255
+ line.strip!
256
+ next if line.empty?
257
+ curgrp << line
258
+ end
259
+ grps << curgrp # add last group and return
260
+ end
261
+
262
+ # @param g [Array<String>]
263
+ def parse_org(g)
264
+ g[0].split("\t").last
265
+ end
266
+
267
+ # @param g [Array<String>]
268
+ def parse_id(g)
269
+ g[1].split(' ')[0].to_i(16)
270
+ end
271
+
272
+ def parse_address1(g)
273
+ g[2] if g.length >= 4
274
+ end
275
+
276
+ def parse_address2(g, id)
277
+ g[3] if g.length >= 5 || MISSING_COUNTRIES.include?(id)
278
+ end
279
+
280
+ def parse_address3(g)
281
+ g[4] if g.length == 6
282
+ end
283
+
284
+ # @param g [Array<String>]
285
+ # @param id [Integer]
286
+ def parse_country(g, id)
287
+ c = COUNTRY_OVERRIDES[id] || g[-1]
288
+ c if c !~ /\A\h/
289
+ end
290
+
291
+ # @param g [Array<String>]
292
+ def create_from_line_group(g)
293
+ n = g.length
294
+ raise ArgumentError, "Parse error lines: #{n}" unless (2..6).include? n
295
+ id = parse_id(g)
296
+ create_unless_present(id: id, organization: parse_org(g),
297
+ address1: parse_address1(g),
298
+ address2: parse_address2(g, id),
299
+ address3: parse_address3(g),
300
+ country: parse_country(g, id))
301
+ end
302
+
303
+ def fetch
304
+ uri = oui_uri
305
+ $stderr.puts "Fetching #{uri}"
306
+ open(uri).read
307
+ end
308
+
309
+ def install_manual
310
+ debug 'install_manual'
311
+ JSON.load(File.read(LOCAL_MANUAL_FILE)).each do |g|
312
+ # convert keys to symbols
313
+ g = g.map { |k, v| [k.to_sym, v] }
314
+ g = Hash[g]
315
+ # convert OUI octets to integers
316
+ g[:id] = self.to_i(g[:id])
317
+ create_unless_present(g)
318
+ end
319
+ rescue Errno::ENOENT
320
+ end
321
+
322
+ def install_updates
323
+ debug 'install_updates'
324
+ lines = fetch.split("\n").map { |x| x.sub(/\r$/, '') }
325
+ parse_lines_into_groups(lines).each_with_index do |group, idx|
326
+ create_from_line_group(group)
327
+ debug "#{ERASE_LINE}Created records #{idx}" if idx % 1000 == 0
328
+ end.count
329
+ debug "#{ERASE_LINE}#{BLANK_LINE}"
330
+ end
331
+
332
+ # Expected duplicates are 00-01-C8 (2x) and 08-00-30 (3x)
333
+ def expected_duplicate?(id)
334
+ EXPECTED_DUPLICATES.include? id
335
+ end
336
+
337
+ # Has a particular id been added yet?
338
+ def added
339
+ @@added ||= {}
340
+ end
341
+
342
+ def debug?
343
+ $DEBUG || debugging || ENV['DEBUG_OUI']
344
+ end
345
+
346
+ def debug(*args)
347
+ $stderr.puts(*args) if debug?
348
+ end
349
+
350
+ def debug_print(*args)
351
+ $stderr.print(*args) if debug?
352
+ end
353
+
354
+ def semaphore
355
+ @@semaphore ||= Monitor.new
356
+ end
357
+
358
+ def create_unless_present(opts)
359
+ id = opts[:id]
360
+ if added[id]
361
+ unless expected_duplicate? id
362
+ debug "OUI unexpected duplicate #{opts}"
363
+ end
364
+ else
365
+ table.insert(opts)
366
+ # self.create! opts
367
+ added[id] = true
368
+ end
369
+ end
370
+
371
+ def oui_uri
372
+ if import_local_txt_file
373
+ debug 'oui_uri = local'
374
+ LOCAL_TXT_FILE
375
+ else
376
+ debug 'oui_uri = remote'
377
+ REMOTE_TXT_URI
378
+ end
379
+ end
380
+ end
@@ -0,0 +1,40 @@
1
+ Gem::Specification::new do |s|
2
+ s.name = 'oui-offline'
3
+ s.version = '1.2.5'
4
+ s.summary = 'Organizationally Unique Idenitfiers (OUI)'
5
+ s.description = 'Organizationally Unique Idenitfiers (OUI) offline database'
6
+ s.license = 'MIT'
7
+
8
+ s.files =
9
+ ['Gemfile',
10
+ 'README.md',
11
+ 'bin/oui',
12
+ 'data/oui-manual.json',
13
+ 'db/oui.sqlite3',
14
+ 'lib/oui.rb',
15
+ 'oui-offline.gemspec',
16
+ ]
17
+ s.files << 'data/oui.txt' if File.exist?('data/oui.txt')
18
+
19
+ s.required_ruby_version = '>= 1.9.3'
20
+
21
+ s.require_path = 'lib'
22
+ s.executables << 'oui'
23
+
24
+ s.author = 'Barry Allard'
25
+ s.email = 'barry.allard@gmail.com'
26
+ s.homepage = 'https://github.com/steakknife/oui'
27
+ s.post_install_message = 'Oui!'
28
+
29
+ s.add_dependency 'sequel', '~> 4'
30
+ if RUBY_PLATFORM == 'java'
31
+ s.platform = 'java'
32
+ s.add_dependency 'jdbc-sqlite3'
33
+ else
34
+ s.platform = Gem::Platform::RUBY
35
+ s.add_dependency 'sqlite3', '~> 1'
36
+ end
37
+ s.add_development_dependency 'rake', '~> 10'
38
+ s.add_development_dependency 'minitest', '~> 5'
39
+ end
40
+ .tap {|gem| pk = File.expand_path(File.join('~/.keys', 'gem-private_key.pem')); gem.signing_key = pk if File.exist? pk; gem.cert_chain = ['gem-public_cert.pem']} # pressed firmly by waxseal
data.tar.gz.sig ADDED
@@ -0,0 +1,5 @@
1
+ 8=�%)�Gk�!���厶9�� ]`�,��N�Q+�ŠՉ��d` "=�Hc
2
+ �� ������Ҵ丶8]���[�-����h�c/��?��l�������
3
+ ��3�RB*��S��&0<iw�7�G<-�7w4�������&�*�����o�:\T�m#@���|n�'�fn��Z—?��P�4��ı�i�1�V����h(Z�X�n�� ��B<�L3�e�v�Ή�����2�Ja�F%<�̺��^�r�o�r��8c�#Z�����eP����W�,NB���[�6脅K�= ��!��֕ �ҸV�6n˯��#
4
+ s�_��r�)S�I���Z&��N����h9��ƌ �A�G�� ��a�4E i��1p-�6:������\�^�"4js?ƞ��mF���� -(��������B��s��?�B�|�r^�"
5
+ �C=:i��g��8��z1��[l� ���̥�~H�ҵP<���҇� z��
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oui-offline
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.5
5
+ platform: java
6
+ authors:
7
+ - Barry Allard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ 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
42
+ t/HWh1yhriCUe/y8+De8M87btOs=
43
+ -----END CERTIFICATE-----
44
+ date: 2015-01-27 00:00:00.000000000 Z
45
+ dependencies:
46
+ - !ruby/object:Gem::Dependency
47
+ requirement: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ~>
50
+ - !ruby/object:Gem::Version
51
+ version: '4'
52
+ name: sequel
53
+ prerelease: false
54
+ type: :runtime
55
+ version_requirements: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ version: '4'
60
+ - !ruby/object:Gem::Dependency
61
+ requirement: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ name: jdbc-sqlite3
67
+ prerelease: false
68
+ type: :runtime
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ - !ruby/object:Gem::Dependency
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ~>
78
+ - !ruby/object:Gem::Version
79
+ version: '10'
80
+ name: rake
81
+ prerelease: false
82
+ type: :development
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: '10'
88
+ - !ruby/object:Gem::Dependency
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '5'
94
+ name: minitest
95
+ prerelease: false
96
+ type: :development
97
+ version_requirements: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: '5'
102
+ description: Organizationally Unique Idenitfiers (OUI) offline database
103
+ email: barry.allard@gmail.com
104
+ executables:
105
+ - oui
106
+ extensions: []
107
+ extra_rdoc_files: []
108
+ files:
109
+ - Gemfile
110
+ - README.md
111
+ - bin/oui
112
+ - data/oui-manual.json
113
+ - db/oui.sqlite3
114
+ - lib/oui.rb
115
+ - oui-offline.gemspec
116
+ - data/oui.txt
117
+ homepage: https://github.com/steakknife/oui
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message: Oui!
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - '>='
128
+ - !ruby/object:Gem::Version
129
+ version: 1.9.3
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.1.9
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Organizationally Unique Idenitfiers (OUI)
141
+ test_files: []
metadata.gz.sig ADDED
Binary file