oui-offline 1.2.5-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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