iana-data 1.1.3
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.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +39 -0
- data/LICENSE +22 -0
- data/README.md +42 -0
- data/Rakefile +56 -0
- data/example-data/lsr.txt +5538 -0
- data/examples/ethertypes.rb +51 -0
- data/examples/ports.rb +35 -0
- data/examples/protocols.rb +36 -0
- data/examples/tlds.rb +20 -0
- data/iana.gemspec +35 -0
- data/iana.tmproj +49 -0
- data/lib/iana/ethertype.rb +99 -0
- data/lib/iana/lsr.rb +145 -0
- data/lib/iana/port.rb +80 -0
- data/lib/iana/protocol.rb +71 -0
- data/lib/iana/tld.rb +29 -0
- data/lib/iana/version.rb +3 -0
- data/lib/iana.rb +24 -0
- metadata +145 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# examples/ethertypes.rb
|
|
6
|
+
|
|
7
|
+
require 'pathname'
|
|
8
|
+
dir = Pathname.new(File.expand_path(__FILE__)).realpath
|
|
9
|
+
require File.join(File.dirname(dir.to_s), '../lib/iana')
|
|
10
|
+
|
|
11
|
+
SCRIPT = File.basename(__FILE__)
|
|
12
|
+
|
|
13
|
+
def known_ethertype?(ethertype)
|
|
14
|
+
|
|
15
|
+
IANA_ETHERTYPES.include?(ethertype)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if ARGV.length == 1
|
|
19
|
+
begin
|
|
20
|
+
IANA_ETHERTYPES, IANA_ETHERTYPES_UPDATED = IANA::EtherType::load(ARGV[0])
|
|
21
|
+
rescue
|
|
22
|
+
puts "#{SCRIPT}: #{$!}"
|
|
23
|
+
exit 1
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
puts "Usage: #{SCRIPT} <ethernet-numbers>"
|
|
27
|
+
exit 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
puts "updated #{IANA_ETHERTYPES_UPDATED} => #{IANA_ETHERTYPES.size} entries"
|
|
31
|
+
puts
|
|
32
|
+
IANA_ETHERTYPES.each do |t|
|
|
33
|
+
print "#{t.begin}"
|
|
34
|
+
print "-#{t.end}" if t.end != t.begin
|
|
35
|
+
puts " => #{t.description}"
|
|
36
|
+
end
|
|
37
|
+
puts
|
|
38
|
+
|
|
39
|
+
# known in :begin => true
|
|
40
|
+
puts "86dd is known? => #{IANA::EtherType.known?("86dd")}"
|
|
41
|
+
|
|
42
|
+
# known in :end => true
|
|
43
|
+
puts "8a97 is known? => #{IANA::EtherType.known?("8a97")}"
|
|
44
|
+
|
|
45
|
+
# known between :begin and :end => true
|
|
46
|
+
puts "8709 is known? => #{IANA::EtherType.known?("8709")}"
|
|
47
|
+
|
|
48
|
+
# unknown => false
|
|
49
|
+
puts "fefe is known? => #{IANA::EtherType.known?("fefe")}"
|
|
50
|
+
|
|
51
|
+
exit 0
|
data/examples/ports.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# examples/ports.rb
|
|
6
|
+
|
|
7
|
+
require 'pathname'
|
|
8
|
+
dir = Pathname.new(File.expand_path(__FILE__)).realpath
|
|
9
|
+
require File.join(File.dirname(dir.to_s), '../lib/iana')
|
|
10
|
+
|
|
11
|
+
SCRIPT = File.basename(__FILE__)
|
|
12
|
+
|
|
13
|
+
if ARGV.length == 1
|
|
14
|
+
begin
|
|
15
|
+
IANA_PORT, IANA_PORT_UPDATED = IANA::Port::load(ARGV[0])
|
|
16
|
+
rescue
|
|
17
|
+
puts "#{SCRIPT}: #{$!}"
|
|
18
|
+
exit 1
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
puts "Usage: #{SCRIPT} <port-numbers>"
|
|
22
|
+
exit 1
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
puts "#{IANA_PORT_UPDATED} => #{IANA_PORT.size} entries"
|
|
26
|
+
|
|
27
|
+
# lookup port 22
|
|
28
|
+
port = 22
|
|
29
|
+
result = IANA_PORT[port]
|
|
30
|
+
puts "#{result.size} matches for port #{port}:"
|
|
31
|
+
result.each do |p|
|
|
32
|
+
puts "=> #{p.keyword} #{port}/#{p.protocol} \"#{p.description}\""
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
exit 0
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# examples/protocols.rb
|
|
6
|
+
|
|
7
|
+
require 'pathname'
|
|
8
|
+
dir = Pathname.new(File.expand_path(__FILE__)).realpath
|
|
9
|
+
require File.join(File.dirname(dir.to_s), '../lib/iana')
|
|
10
|
+
|
|
11
|
+
SCRIPT = File.basename(__FILE__)
|
|
12
|
+
|
|
13
|
+
if ARGV.length == 1
|
|
14
|
+
begin
|
|
15
|
+
IANA_PROTO, IANA_PROTO_UPDATED = IANA::Protocol::load(ARGV[0])
|
|
16
|
+
rescue
|
|
17
|
+
puts "#{SCRIPT}: #{$!}"
|
|
18
|
+
exit 1
|
|
19
|
+
end
|
|
20
|
+
else
|
|
21
|
+
puts "Usage: #{SCRIPT} <protocol-numbers>"
|
|
22
|
+
exit 1
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
puts "#{IANA_PROTO_UPDATED} => #{IANA_PROTO.size} entries"
|
|
26
|
+
|
|
27
|
+
# lookup protocol 22
|
|
28
|
+
result = IANA_PROTO[22]
|
|
29
|
+
print "protocol 22 => #{result.name} \"#{result.description}\""
|
|
30
|
+
if !result.references.nil? && !result.references.empty? then
|
|
31
|
+
puts " #{result.references}"
|
|
32
|
+
else
|
|
33
|
+
puts
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
exit 0
|
data/examples/tlds.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# examples/tlds.rb
|
|
6
|
+
require 'iana'
|
|
7
|
+
|
|
8
|
+
# is com a TLD?
|
|
9
|
+
puts "com is a TLD? => #{IANA::TLD.tld?('com')}"
|
|
10
|
+
|
|
11
|
+
# how about to?
|
|
12
|
+
puts "to is a TLD? => #{IANA::TLD.tld?('to')}"
|
|
13
|
+
|
|
14
|
+
# grizzlebat is probably not a TLD
|
|
15
|
+
puts "grizzlebat is a TLD? => #{IANA::TLD.tld?('grizzlebat')}"
|
|
16
|
+
|
|
17
|
+
# how about yn?
|
|
18
|
+
puts "yn is a TLD? => #{IANA::TLD.tld?('yn')}"
|
|
19
|
+
|
|
20
|
+
exit 0
|
data/iana.gemspec
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'iana/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "iana-data"
|
|
8
|
+
spec.version = Iana::VERSION
|
|
9
|
+
spec.authors = ["Runar Ingebrigtsen", "Ramsey Dow"]
|
|
10
|
+
spec.email = %w{runar@rin.no, yesmar@gmail.com}
|
|
11
|
+
|
|
12
|
+
spec.summary = %q{Look up official IANA data, replacement for iana gem}
|
|
13
|
+
spec.homepage = "http://github.com/ringe/iana"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
|
17
|
+
# delete this section to allow pushing this gem to any host.
|
|
18
|
+
if spec.respond_to?(:metadata)
|
|
19
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
|
20
|
+
else
|
|
21
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
25
|
+
spec.bindir = "exe"
|
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
27
|
+
spec.require_paths = ["lib"]
|
|
28
|
+
|
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
|
30
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
31
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
32
|
+
spec.add_development_dependency 'yard', '~> 0.8', '>= 0.8.7'
|
|
33
|
+
|
|
34
|
+
spec.add_dependency "open-uri-cached", "= 0.0.5"
|
|
35
|
+
end
|
data/iana.tmproj
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>documents</key>
|
|
6
|
+
<array>
|
|
7
|
+
<dict>
|
|
8
|
+
<key>filename</key>
|
|
9
|
+
<string>README</string>
|
|
10
|
+
</dict>
|
|
11
|
+
<dict>
|
|
12
|
+
<key>filename</key>
|
|
13
|
+
<string>LICENSE</string>
|
|
14
|
+
</dict>
|
|
15
|
+
<dict>
|
|
16
|
+
<key>filename</key>
|
|
17
|
+
<string>Rakefile</string>
|
|
18
|
+
</dict>
|
|
19
|
+
<dict>
|
|
20
|
+
<key>expanded</key>
|
|
21
|
+
<true/>
|
|
22
|
+
<key>name</key>
|
|
23
|
+
<string>lib</string>
|
|
24
|
+
<key>regexFolderFilter</key>
|
|
25
|
+
<string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
|
|
26
|
+
<key>sourceDirectory</key>
|
|
27
|
+
<string>lib</string>
|
|
28
|
+
</dict>
|
|
29
|
+
<dict>
|
|
30
|
+
<key>expanded</key>
|
|
31
|
+
<true/>
|
|
32
|
+
<key>name</key>
|
|
33
|
+
<string>examples</string>
|
|
34
|
+
<key>regexFolderFilter</key>
|
|
35
|
+
<string>!.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$</string>
|
|
36
|
+
<key>sourceDirectory</key>
|
|
37
|
+
<string>examples</string>
|
|
38
|
+
</dict>
|
|
39
|
+
</array>
|
|
40
|
+
<key>fileHierarchyDrawerWidth</key>
|
|
41
|
+
<integer>200</integer>
|
|
42
|
+
<key>metaData</key>
|
|
43
|
+
<dict/>
|
|
44
|
+
<key>showFileHierarchyDrawer</key>
|
|
45
|
+
<true/>
|
|
46
|
+
<key>windowFrame</key>
|
|
47
|
+
<string>{{638, 167}, {728, 637}}</string>
|
|
48
|
+
</dict>
|
|
49
|
+
</plist>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# lib/iana/ethertype.rb
|
|
6
|
+
|
|
7
|
+
module IANA
|
|
8
|
+
module EtherType
|
|
9
|
+
EtherType = Struct.new('ETHERTYPE', :begin, :end, :description)
|
|
10
|
+
|
|
11
|
+
# I hate doing it this way, but the inconsistency of IANA data files...
|
|
12
|
+
LAST_ENTRY = '^ 65535 FFFF - - Reserved \[RFC1701\]$'
|
|
13
|
+
|
|
14
|
+
# load IANA Ether types list from flat file:
|
|
15
|
+
# http://www.iana.org/assignments/ethernet-numbers
|
|
16
|
+
def self.load(pathname)
|
|
17
|
+
raise ArgumentError, 'nil pathname' if pathname.nil?
|
|
18
|
+
raise ArgumentError, 'invalid pathname class' if pathname.class != String
|
|
19
|
+
raise ArgumentError, 'empty pathname' if pathname.empty?
|
|
20
|
+
|
|
21
|
+
# TODO: better error checking for files with incorrect content
|
|
22
|
+
|
|
23
|
+
ethertypes = []
|
|
24
|
+
updated = nil
|
|
25
|
+
|
|
26
|
+
begin
|
|
27
|
+
f = File.new(pathname, 'r')
|
|
28
|
+
while (line = f.gets)
|
|
29
|
+
line.chomp!
|
|
30
|
+
|
|
31
|
+
# extract update stamp
|
|
32
|
+
if line =~ /^\(last updated (\d{4}-\d{2}-\d{2})\)\s*$/
|
|
33
|
+
updated = $1
|
|
34
|
+
next
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# skip lines that don't have [XXX] or (XXX) at the end
|
|
38
|
+
next if line !~ /\[\w*\]$/ && line !~ /\([\w\s]*\)$/
|
|
39
|
+
|
|
40
|
+
# now skip all lines that don't begin with a space
|
|
41
|
+
next if line !~ /^[\t\ ]*/
|
|
42
|
+
|
|
43
|
+
# skip over decimal Ethertype
|
|
44
|
+
pos = 0
|
|
45
|
+
if line =~ /^\t\ /
|
|
46
|
+
pos = 2
|
|
47
|
+
else
|
|
48
|
+
pos = 9
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# clean up ridiculous IANA formatting
|
|
52
|
+
line.gsub!(/^\t/, '8') # TODO: investigate this weirdness
|
|
53
|
+
line.gsub!(/\t -/, ' -')
|
|
54
|
+
line.gsub!(/\t\t\t /, ' ')
|
|
55
|
+
line.gsub!(/\t/, ' ')
|
|
56
|
+
|
|
57
|
+
tmp = line[pos..-1]
|
|
58
|
+
|
|
59
|
+
ethertype = tmp[0..9].strip!
|
|
60
|
+
low, high = ethertype.split('-')
|
|
61
|
+
high = low if high.nil?
|
|
62
|
+
|
|
63
|
+
description, *junk = tmp[25..-1].split('[')
|
|
64
|
+
description.strip!
|
|
65
|
+
|
|
66
|
+
et = EtherType.new(low, high, description)
|
|
67
|
+
ethertypes << et
|
|
68
|
+
|
|
69
|
+
# short-circuit as soon as we've hit the end of the list
|
|
70
|
+
break if line =~ /#{LAST_ENTRY}/
|
|
71
|
+
end
|
|
72
|
+
ensure
|
|
73
|
+
f.close if !f.nil?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
return ethertypes, updated
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# is specified Ether type known
|
|
80
|
+
def self.known?(ethertype)
|
|
81
|
+
raise ArgumentError, 'nil ethertype' if ethertype.nil?
|
|
82
|
+
raise ArgumentError, 'invalid ethertype class' if \
|
|
83
|
+
ethertype.class != String
|
|
84
|
+
raise ArgumentError, 'empty ethertype' if ethertype.empty?
|
|
85
|
+
|
|
86
|
+
IANA_ETHERTYPES.each do |t|
|
|
87
|
+
return true if ethertype.upcase == t.begin
|
|
88
|
+
if t.end != t.begin
|
|
89
|
+
return true if ethertype.upcase >= t.begin && \
|
|
90
|
+
ethertype.upcase <= t.end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
false
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/iana/lsr.rb
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# NOTE
|
|
4
|
+
# RFC 4646 described below has been obseleted by RFC5646. Tests still run OK
|
|
5
|
+
# but I have no idea (yet) what this new RFC has changed in terms of the LSR
|
|
6
|
+
# file format or langugae tags generally.
|
|
7
|
+
# See http://tools.ietf.org/html/rfc5646 (particularly section 8).
|
|
8
|
+
# 2011-04-18
|
|
9
|
+
module IANA
|
|
10
|
+
# Get the Language Subtag Registry data from the IANA site or a text file
|
|
11
|
+
# and load it into an array of hashes for further processing.
|
|
12
|
+
#
|
|
13
|
+
# IANA's Language Subtag Registry incorporates multiple standards for the
|
|
14
|
+
# definition of language- and locale-defining strings, including:
|
|
15
|
+
# ISO 3166: English country names and code elements
|
|
16
|
+
# ( http://www.iso.org/iso/english_country_names_and_code_elements )
|
|
17
|
+
# ISO 639.2: Codes for the Representation of Names of Languages
|
|
18
|
+
# ( http://www.loc.gov/standards/iso639-2/php/code_list.php )
|
|
19
|
+
# The registry's format is specified in RFC 4646
|
|
20
|
+
# ( http://www.ietf.org/rfc/rfc4646.txt )
|
|
21
|
+
class LanguageSubtagRegistry
|
|
22
|
+
# Entries always have these keys: Type, [Tag or Subtag], Description, Added
|
|
23
|
+
# All keys used in the IANA format:
|
|
24
|
+
Keys = [
|
|
25
|
+
"Type",
|
|
26
|
+
"Tag",
|
|
27
|
+
"Subtag",
|
|
28
|
+
"Description",
|
|
29
|
+
"Added",
|
|
30
|
+
"Preferred-Value",
|
|
31
|
+
"Deprecated",
|
|
32
|
+
"Suppress-Script",
|
|
33
|
+
"Prefix",
|
|
34
|
+
"Comments" ]
|
|
35
|
+
IANAHost = 'www.iana.org'
|
|
36
|
+
IANAPath = '/assignments/language-subtag-registry'
|
|
37
|
+
IANAFile = File.dirname(__FILE__) + "/../../example-data/lsr.txt"
|
|
38
|
+
@@tags = []
|
|
39
|
+
@@file_date = ""
|
|
40
|
+
|
|
41
|
+
def self.tags
|
|
42
|
+
@@tags
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.file_date
|
|
46
|
+
@@file_date
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Load data directly from IANA site
|
|
50
|
+
def self.get(path=IANAPath, host=IANAHost)
|
|
51
|
+
require 'net/http'
|
|
52
|
+
site = Net::HTTP.new host
|
|
53
|
+
response = site.request_get path
|
|
54
|
+
self.load(response.body)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Load data from a text file
|
|
58
|
+
def self.open(filename=IANAFile)
|
|
59
|
+
file = File.open(filename, 'r')
|
|
60
|
+
self.load(file.read)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Load data from text string
|
|
64
|
+
def self.load(text)
|
|
65
|
+
@@tags = []
|
|
66
|
+
@@file_date = ""
|
|
67
|
+
item = {}
|
|
68
|
+
prev = []
|
|
69
|
+
text.each do |line|
|
|
70
|
+
line.chomp!
|
|
71
|
+
case line
|
|
72
|
+
when /^%%$/
|
|
73
|
+
(@@tags << item; item = {}) unless item.empty? # separator; append last entry, if present
|
|
74
|
+
when /^File-Date: .*/
|
|
75
|
+
@@file_date = line.gsub('File-Date: ','') # File-date entry
|
|
76
|
+
when /^ [^ ].*/
|
|
77
|
+
item[prev].kind_of?(Array) ? item[prev].last += " " + line.strip : item[prev] += " " + line.strip # continuation line
|
|
78
|
+
else # everything else (the actual key: value pairs)
|
|
79
|
+
key, val = line.split(':', 2) # the main pair (ie, "Subtag: en")
|
|
80
|
+
if /\.\./.match val # value specifies a range, not simply a string
|
|
81
|
+
start, finish = val.strip.split('..', 2)
|
|
82
|
+
val = Range.new(start, finish)
|
|
83
|
+
else # otherwise it's just a string
|
|
84
|
+
val.strip!
|
|
85
|
+
end
|
|
86
|
+
if item.has_key?(key) # append to array if this key already exists
|
|
87
|
+
item[key] = [item[key]] unless item[key].kind_of? Array
|
|
88
|
+
item[key] << val
|
|
89
|
+
else # otherwise simply assign the item
|
|
90
|
+
item[key] = val
|
|
91
|
+
end
|
|
92
|
+
prev = key # in case of continuation (wrapped text)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
@@tags << item
|
|
96
|
+
nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Dump data to:
|
|
100
|
+
# IANA's flat text format (String)
|
|
101
|
+
# YAML (String)
|
|
102
|
+
# A hash of hashes, with the keys being the tags (Hash)
|
|
103
|
+
def self.dump(format = "iana")
|
|
104
|
+
begin
|
|
105
|
+
format = format.strip.downcase
|
|
106
|
+
rescue
|
|
107
|
+
raise ArgumentError, "Invalid argument type; expected String"
|
|
108
|
+
end
|
|
109
|
+
case format
|
|
110
|
+
when "iana"
|
|
111
|
+
new_text = "File-Date: " + @@file_date + $/ + "%%" + $/
|
|
112
|
+
new_text << @@tags.map do |item|
|
|
113
|
+
Keys.map do |key|
|
|
114
|
+
val = item[key]
|
|
115
|
+
if val
|
|
116
|
+
if val.kind_of? Array
|
|
117
|
+
val.map { |i| key + ": " + i.to_s }.join($/)
|
|
118
|
+
else
|
|
119
|
+
key + ": " + val.to_s
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
nil
|
|
123
|
+
end
|
|
124
|
+
end.compact.join($/) + $/
|
|
125
|
+
end.join('%%' + $/)
|
|
126
|
+
when "yaml"
|
|
127
|
+
require 'yaml'
|
|
128
|
+
YAML::dump([@@file_date, @@tags])
|
|
129
|
+
when "hash"
|
|
130
|
+
taghash = {}
|
|
131
|
+
@@tags.each do |tag|
|
|
132
|
+
tag = tag.clone
|
|
133
|
+
val = tag.delete("Tag") || tag.delete("Subtag")
|
|
134
|
+
taghash[val.to_s] = tag
|
|
135
|
+
end
|
|
136
|
+
taghash
|
|
137
|
+
else
|
|
138
|
+
raise ArgumentError, "Invalid format option"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/iana/port.rb
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# lib/iana/port.rb
|
|
6
|
+
|
|
7
|
+
module IANA
|
|
8
|
+
module Port
|
|
9
|
+
Port = Struct.new('PORT', :keyword, :protocol, :description)
|
|
10
|
+
|
|
11
|
+
# load IANA ports list from flat file:
|
|
12
|
+
# http://www.iana.org/assignments/port-numbers
|
|
13
|
+
def self.load(pathname)
|
|
14
|
+
raise ArgumentError, 'nil pathname' if pathname.nil?
|
|
15
|
+
raise ArgumentError, 'invalid pathname class' if pathname.class != String
|
|
16
|
+
raise ArgumentError, 'empty pathname' if pathname.empty?
|
|
17
|
+
|
|
18
|
+
# TODO: better error checking for files with incorrect content
|
|
19
|
+
|
|
20
|
+
ports = {}
|
|
21
|
+
updated = nil
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
f = File.new(pathname, 'r')
|
|
25
|
+
while (line = f.gets)
|
|
26
|
+
line.chomp!
|
|
27
|
+
|
|
28
|
+
# extract update stamp
|
|
29
|
+
if line =~ /^\(last updated (\d{4}-\d{2}-\d{2})\)\s*$/
|
|
30
|
+
updated = $1
|
|
31
|
+
next
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# skip commented lines
|
|
35
|
+
next if line =~ /^#/
|
|
36
|
+
|
|
37
|
+
# skip lines which do not contain the /{proto} pattern
|
|
38
|
+
if line !~ /\/tcp/ && line !~ /\/udp/ && line !~ /\/sctp/ && \
|
|
39
|
+
line !~ /\/dccp/
|
|
40
|
+
next
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
line.strip!
|
|
44
|
+
tokens = line.split(/[\s]+/)
|
|
45
|
+
|
|
46
|
+
# if first token is a port/proto pair then the port is unnamed
|
|
47
|
+
if tokens[0] =~ /\//
|
|
48
|
+
name = nil
|
|
49
|
+
num,proto = tokens[0].split(/\//)
|
|
50
|
+
tokens.delete_at(0)
|
|
51
|
+
else
|
|
52
|
+
name = tokens[0]
|
|
53
|
+
num,proto = tokens[1].split(/\//)
|
|
54
|
+
2.times { tokens.delete_at(0) }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# remainder of tokens serves as the description
|
|
58
|
+
desc = tokens.join(' ')
|
|
59
|
+
|
|
60
|
+
p = Port.new(name, proto, desc)
|
|
61
|
+
|
|
62
|
+
if ports[num.to_i].nil?
|
|
63
|
+
ports[num.to_i] = p
|
|
64
|
+
else
|
|
65
|
+
c = []
|
|
66
|
+
c << ports[num.to_i]
|
|
67
|
+
c << p
|
|
68
|
+
ports[num.to_i] = c.flatten
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
ensure
|
|
72
|
+
f.close if !f.nil?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
return ports, updated
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# lib/iana/protocol.rb
|
|
6
|
+
|
|
7
|
+
# rubygems
|
|
8
|
+
require 'nokogiri'
|
|
9
|
+
|
|
10
|
+
module IANA
|
|
11
|
+
module Protocol
|
|
12
|
+
Protocol = Struct.new('PROTOCOL', :name, :description, :references)
|
|
13
|
+
|
|
14
|
+
# load IANA protocols list from XML file:
|
|
15
|
+
# http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml
|
|
16
|
+
def self.load(pathname)
|
|
17
|
+
raise ArgumentError, 'nil pathname' if pathname.nil?
|
|
18
|
+
raise ArgumentError, 'invalid pathname class' if pathname.class != String
|
|
19
|
+
raise ArgumentError, 'empty pathname' if pathname.empty?
|
|
20
|
+
|
|
21
|
+
protocols = {}
|
|
22
|
+
updated = nil
|
|
23
|
+
|
|
24
|
+
begin
|
|
25
|
+
f = File.new(pathname, 'r')
|
|
26
|
+
doc = Nokogiri::XML(f)
|
|
27
|
+
updated = doc.css('registry/updated').text
|
|
28
|
+
doc.css('registry/registry/record').each do |r|
|
|
29
|
+
# range
|
|
30
|
+
value = r.css('value').text
|
|
31
|
+
if value =~ /-/ then
|
|
32
|
+
low,high = value.split('-').map(&:to_i)
|
|
33
|
+
else
|
|
34
|
+
low = value.to_i
|
|
35
|
+
high = low
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# name
|
|
39
|
+
name = r.css('name').text
|
|
40
|
+
name = nil if !name.nil? && name.empty?
|
|
41
|
+
|
|
42
|
+
# description
|
|
43
|
+
description = r.css('description').text
|
|
44
|
+
description = nil if !description.nil? && description.empty?
|
|
45
|
+
|
|
46
|
+
# references
|
|
47
|
+
xref = []
|
|
48
|
+
r.css('xref').each do |x|
|
|
49
|
+
data = x['data']
|
|
50
|
+
xref << data if !data.nil? && !data.empty?
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if low == high then
|
|
54
|
+
protocols[low] = Protocol.new(name, description, xref)
|
|
55
|
+
else
|
|
56
|
+
# create an entry for each range element
|
|
57
|
+
(high-low+1).times do |i|
|
|
58
|
+
protocols[low+i] = Protocol.new(name, description, xref)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
ensure
|
|
63
|
+
f.close if !f.nil?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
return protocols, updated
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/iana/tld.rb
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# lib/tld.rb
|
|
6
|
+
|
|
7
|
+
module IANA
|
|
8
|
+
module TLD
|
|
9
|
+
# Download official IANA Top Level Domain list
|
|
10
|
+
# http://data.iana.org/TLD/tlds-alpha-by-domain.txt
|
|
11
|
+
def self.iana_list
|
|
12
|
+
open("http://data.iana.org/TLD/tlds-alpha-by-domain.txt").read.
|
|
13
|
+
split("\n").
|
|
14
|
+
reject {|ln| ln =~ /^#/ }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# is specified tld a valid IANA Top Level Domain?
|
|
18
|
+
def self.valid?(tld)
|
|
19
|
+
iana_list.include?(tld.to_s.upcase)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# is specified domain name a TLD?
|
|
23
|
+
def self.tld?(tld)
|
|
24
|
+
valid?(tld)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|
data/lib/iana/version.rb
ADDED
data/lib/iana.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
# vim: expandtab tabstop=2 softtabstop=2 shiftwidth=2
|
|
4
|
+
|
|
5
|
+
# lib/iana.rb
|
|
6
|
+
module IANA
|
|
7
|
+
end # IANA
|
|
8
|
+
|
|
9
|
+
require 'open-uri'
|
|
10
|
+
require 'open-uri/cached'
|
|
11
|
+
|
|
12
|
+
#require 'consumer'
|
|
13
|
+
require 'iana/ethertype'
|
|
14
|
+
require 'iana/port'
|
|
15
|
+
require 'iana/protocol'
|
|
16
|
+
require 'iana/tld'
|
|
17
|
+
require 'iana/lsr'
|
|
18
|
+
|
|
19
|
+
# TODO implement consumer model
|
|
20
|
+
# TODO complete documentaion
|
|
21
|
+
# TODO implement unit tests
|
|
22
|
+
# TODO lookup needs to be more flexible
|
|
23
|
+
|
|
24
|
+
raise RuntimeError, 'This library is for require only' if $0 == __FILE__
|