irrc 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d0cea0cd7090c9cdc0050e02cc02368a03e48f12
4
+ data.tar.gz: 022c5535b1e8acb15e3641fcff65959105ebd5c7
5
+ SHA512:
6
+ metadata.gz: f3883807ba6822641f396177a1fb187f0d50c96595ac9b4b33c6d2693a789ac720cd7b324aa1b780ee76898760afd247cf93803a0a9d606c668e0bf826bb9f51
7
+ data.tar.gz: 0e89f38a1c5b90241301ff54839949cc1778dc0194163659f8e60c23b457fe5e29cfbb25806ab41c707dffb9348eb07f29ef27a0230620445076e0d0460f728f
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1.0
5
+ - 2.1.1
6
+ - ruby-head
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :test do
4
+ gem 'rspec'
5
+ end
6
+
7
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Shintaro Kojima
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,195 @@
1
+ # irrc
2
+
3
+ [![Build Status](https://travis-ci.org/codeout/irrc.svg)](https://travis-ci.org/codeout/irrc)
4
+ [![Code Climate](https://codeclimate.com/github/codeout/irrc.png)](https://codeclimate.com/github/codeout/irrc)
5
+ [![Inline docs](http://inch-ci.org/github/codeout/irrc.svg)](http://inch-ci.org/github/codeout/irrc)
6
+
7
+ irrc is a lightweight and flexible client of IRR / Whois Database to expand arbitrary as-set and route-set objects into a list of origin ASs and prefixes belonging to those ASs. It will concurrently queries multiple IRR / Whois Databases for performance.
8
+
9
+ ## Features
10
+
11
+ * Fast. irrc runs multi-threaded micro clients to process simultaneous IRR / Whois queries for performance. It also uses object caches.
12
+ * Handy. irrc's CLI client provides an easy way to resolve prefixes from as-set and route-set objects. It works even when multiple objects given as arguments.
13
+ * Dual stack. irrc returns both IPv4 and IPv6 prefixes by default. There is no need to kick a command twice for dual stacked result.
14
+ * Flexible. irrc provides an extensible ruby library which allows to modify IRR / Whois queries more flexibly.
15
+ * Pretty print. irrc shows prefixes in YAML format like [this](#example).
16
+ * Pure ruby. irrc doesn't depend on any other ruby gem.
17
+ * Lightweight. irrc is designed to gather prefixes from arbitrary as-set and route-set. It's implemented as simple as possible to achieve that. In other words, domain name related features are not supported.
18
+
19
+
20
+ ## Installation
21
+
22
+ For bundler:
23
+
24
+ gem 'irrc'
25
+
26
+ And then:
27
+
28
+ $ bundle
29
+
30
+ Otherwise:
31
+
32
+ $ gem install irrc
33
+
34
+
35
+ ## Usage
36
+
37
+ ### CLI
38
+
39
+ irrc privides a peval-like CLI interface.
40
+
41
+ * Query JPIRR about AS-JPNIC and AS-OCN
42
+
43
+ ```shell
44
+ $ irrc -h jpirr AS-JPNIC AS-OCN
45
+ ```
46
+
47
+ * Query JPIRR about AS-JPNIC with authoritative IRR (SOURCE:) based filter
48
+
49
+ ```shell
50
+ $ irrc -h jpirr -s radb -s apnic AS-JPNIC
51
+ ```
52
+
53
+ * Query JPIRR about AS-JPNIC for IPv4 only
54
+
55
+ ```shell
56
+ $ irrc -h jpirr -4 AS-JPNIC
57
+ ```
58
+
59
+ ### As a Library
60
+
61
+ You can load irrc as a library and use it easily in your own code.
62
+
63
+ ```ruby
64
+ require 'irrc'
65
+
66
+ client = Irrc::Client.new
67
+ client.query(:jpirr, 'AS-JPNIC', source: :jpirr) # queries JPIRR about AS-JPNIC with a SOURCE: filter
68
+ client.query(:ripe, 'AS-RIPENCC', protocol: :ipv4) # queries RIPE Whoisd about AS-RIPENCC for IPv4 only
69
+ client.perform # returns the results in a Hash
70
+ ```
71
+
72
+
73
+ ## Example
74
+
75
+ ```shell
76
+ $ irrc -h jpirr AS-JPNIC
77
+ ```
78
+
79
+ will result in a YAML:
80
+
81
+ ```yaml
82
+ ---
83
+ AS-JPNIC: # queried object
84
+ :ipv4:
85
+ AS2515: # AS-JPNIC has AS2515 as a origin AS
86
+ - 202.12.30.0/24 # 4 IPv4 prefixes belonging to AS2515
87
+ - 192.41.192.0/24 #
88
+ - 211.120.240.0/21 #
89
+ - 211.120.248.0/24 #
90
+ :ipv6:
91
+ AS2515:
92
+ - 2001:0fa0::/32
93
+ - 2001:dc2::/32
94
+ - 2001:DC2::/32
95
+ ```
96
+
97
+
98
+ ## Supported Ruby Versions
99
+
100
+ * Ruby >= 2.0.0
101
+
102
+ Successfully tested with 2.0.0, 2.1.0, 2.1.1, 2.1.2.
103
+
104
+
105
+ ## Threading
106
+
107
+ irrc will send queries to multiple IRR / Whois servers simultaneously in multi-threads. Single-thread processing for each server by default.
108
+
109
+ To configure the number of threads per server:
110
+
111
+ ### CLI
112
+
113
+ ```shell
114
+ $ irrc -h jpirr -t 2 AS-JPNIC AS-OCN # 2 threads to query JPIRR
115
+ ```
116
+
117
+ ### AS a Library
118
+
119
+ ```ruby
120
+ client = Irrc::Client.new(2) # 2 threads per IRR / Whois server
121
+ ```
122
+
123
+
124
+ ## Debugging
125
+
126
+ irrc uses ```STDERR``` printer for a logger by default, which reports more severe messages than INFO.
127
+
128
+ ### CLI
129
+
130
+ To display debug information including raw messages of IRR / Whois protocol:
131
+
132
+ ```shell
133
+ $ irrc -h jpirr -d AS-JPNIC
134
+ ```
135
+
136
+ ### As a Library
137
+
138
+ To use modified Logger:
139
+
140
+ ```ruby
141
+ client = Irrc::Client.new {|c| c.logger = Rails.logger }
142
+ ```
143
+
144
+
145
+ ## Quick Benchmark
146
+
147
+ Here is a quick performance comparison with peval and irrpt.
148
+
149
+ * Ordinary as-set
150
+
151
+ | CLI command | user | system | cpu | total |
152
+ | :------------------------------ | --------: | ---------: | ------: | ---------: |
153
+ | peval -h jpirr.nic.ad.jp AS-OCN | 0.14s | 0.04s | 1% | 9.397 |
154
+ | irrpt_eval AS-OCN | 0.35s | 0.06s | 5% | 8.021 |
155
+ | **irrc -h jpirr AS-OCN** | **0.42s** | **0.09s** | **4%** | **10.639** |
156
+
157
+ * Huge as-set
158
+
159
+ Object caching may contribute to the query performance.
160
+
161
+ | CLI command | user | system | cpu | total |
162
+ | :---------------------------------------- | ----------: | ---------: | ------: | ----------: |
163
+ | peval -h jpirr.nic.ad.jp AS-HURRICANE | 67.29s | 1.21s | 22% | 4:58.16 |
164
+ | irrpt_eval AS-HURRICANE | 163.10s | 1.38s | 43% | 6:18.17 |
165
+ | **irrc -h jpirr AS-HURRICANE** | **20.26s** | **1.84s** | **7%** | **4:54.37** |
166
+
167
+ * Multiple as-set
168
+
169
+ Multi-threading and object caching may contribute to the query performance.
170
+
171
+ | CLI command | user | system | cpu | total |
172
+ | :------------------------------------------------------------- | ----------: | ---------: | ------: | ----------: |
173
+ | for i in AS-HURRICANE AS-GBLX; peval -h jpirr.nic.ad.jp $i | 76.47s | 1.08s | 20% | 6:15.80 |
174
+ | irrpt_fetch | 174.21s | 1.29s | 44% | 6:38.50 |
175
+ | irrc -h jpirr AS-HURRICANE AS-GBLX | 22.28s | 1.75s | 8% | 4:34.31 |
176
+ | **irrc -h jpirr -t 2 AS-HURRICANE AS-GBLX** | **23.04s** | **1.81s** | **9%** | **4:09.27** |
177
+
178
+
179
+ ## Contributing
180
+
181
+ Please fork it, fix and then send a pull request. :tada:
182
+
183
+ To run tests just type:
184
+
185
+ ```shell
186
+ $ rake
187
+ ```
188
+
189
+ Please report issues or enhancement requests to [GitHub issues](https://github.com/codeout/irrc/issues).
190
+ For questions or feedbacks write to my twitter @codeout.
191
+
192
+
193
+ ## Copyright and License
194
+
195
+ Copyright (c) 2014 Shintaro Kojima. Code released under the [MIT license](LICENSE).
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |spec|
5
+ spec.pattern = FileList['spec/**/*_spec.rb']
6
+ end
7
+
8
+ task default: :spec
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby -Ilib
2
+
3
+ require 'irrc/cli'
4
+
5
+ Irrc::Cli::Client.new(ARGV).start
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'irrc/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'irrc'
8
+ spec.version = Irrc::VERSION
9
+ spec.authors = ['Shintaro Kojima']
10
+ spec.email = ['goodies@codeout.net']
11
+ spec.summary = 'IRR / Whois client to expand as-set and route-set into a list of origin ASs and prefixes'
12
+ spec.description = 'irrc is a lightweight and flexible client of IRR / Whois Database to expand arbitrary as-set and route-set objects into a list of origin ASs and prefixes belonging to the ASs. It allows concurrent queries to IRR / Whois Databases for performance.'
13
+ spec.homepage = 'https://github.com/codeout/irrc'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.6'
22
+ spec.add_development_dependency 'rake'
23
+ end
@@ -0,0 +1,2 @@
1
+ require 'irrc/client'
2
+ require 'irrc/version'
@@ -0,0 +1 @@
1
+ require 'irrc/cli/client'
@@ -0,0 +1,108 @@
1
+ require 'optparse'
2
+
3
+ require 'irrc'
4
+ require 'irrc/cli/yaml_printer'
5
+
6
+ module Irrc
7
+ module Cli
8
+ class Client
9
+ def initialize(args)
10
+ @args = args
11
+ @options = Struct.new(:host, :source, :protocol, :threads, :debug).new(nil, [], [], 1, nil)
12
+ end
13
+
14
+ def start
15
+ OptionParser.new(&method(:options)).parse!(@args)
16
+
17
+ verify_arguments
18
+ set_default_arguments
19
+
20
+ Irrc::Cli::YamlPrinter.print perform
21
+
22
+ rescue
23
+ $stderr.print "#{$!.class}: " unless $!.instance_of?(RuntimeError)
24
+ $stderr.puts $!.message
25
+
26
+ exit 1
27
+ end
28
+
29
+
30
+ private
31
+
32
+ def options(opts)
33
+ opts.banner = <<-EOS
34
+ Usage: #{opts.program_name} [options] [objects ...]
35
+
36
+ Description:
37
+ Better IRR client to resolve as-set, route-set or aut-num object into prefixes.
38
+
39
+ If no [-4|-6|--ipv4|--ipv6] option given, it tries both of ipv4 and ipv6.
40
+
41
+ Options:
42
+ EOS
43
+
44
+ opts.on '-h HOST', 'Specify FQDN of IRR / Whois server to send queries.',
45
+ 'IRR / Whois name is also acceptable. This switch is mandatory.' do |host|
46
+ @options.host = host
47
+ end
48
+
49
+ opts.on '-s SOURCE', '--source', 'Specify an authoritative IRR / Whois source name.',
50
+ 'Multiply this option for multiple SOURCE.',
51
+ "eg) #{opts.program_name} -s jpirr -s radb AS-JPNIC" do |source|
52
+ @options.source |= [source]
53
+ end
54
+
55
+ opts.on '-4', '--ipv4', 'Resolve IPv4 prefixes.' do
56
+ @options.protocol |= [:ipv4]
57
+ end
58
+
59
+ opts.on '-6', '--ipv6', 'Resolve IPv6 prefixes.' do
60
+ @options.protocol |= [:ipv6]
61
+ end
62
+
63
+ opts.on '-t NUMBER', '--threads', 'Number of threads to resolve prefixes per IRR / Whois server.' do |threads|
64
+ @options.threads = threads
65
+ end
66
+
67
+ opts.on '-d', '--debug', 'Print raw queries, answers and additional informations.' do
68
+ @options.debug = true
69
+ end
70
+ end
71
+
72
+ def verify_arguments
73
+ if @args.empty?
74
+ $stderr.puts <<-EOS
75
+ Missing Argument: objects required.
76
+
77
+ Use --help for usage.
78
+ EOS
79
+ exit 1
80
+ end
81
+
82
+ unless @options.host
83
+ $stderr.puts <<-EOS
84
+ Missing Argument: -h option is required.
85
+
86
+ Use --help for usage.
87
+ EOS
88
+ exit 1
89
+ end
90
+ end
91
+
92
+ def set_default_arguments
93
+ @options.protocol = [:ipv4, :ipv6] if @options.protocol.empty?
94
+ end
95
+
96
+ def perform
97
+ client = if @options.debug
98
+ Irrc::Client.new(@options.threads) {|c| c.logger = Logger.new(STDERR) }
99
+ else
100
+ Irrc::Client.new(@options.threads)
101
+ end
102
+
103
+ client.query(@options.host, @args, source: @options.source, protocol: @options.protocol)
104
+ client.perform
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,13 @@
1
+ require 'yaml'
2
+
3
+ module Irrc
4
+ module Cli
5
+ class YamlPrinter
6
+ class << self
7
+ def print(hash)
8
+ puts hash.to_yaml
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,109 @@
1
+ require 'irrc/irr'
2
+ require 'irrc/irrd'
3
+ require 'irrc/whoisd'
4
+ require 'irrc/query'
5
+
6
+ module Irrc
7
+
8
+ # Public: IRR / Whois client to manage child client workers and queues.
9
+ class Client
10
+ # Public: Create a new IRR / Whois client worker manager.
11
+ # You can customize the logger by specifying a block.
12
+ # The default logger is STDERR printer of more severe messages than INFO.
13
+ #
14
+ # threads - Number of threads to resolve prefixes per IRR / Whois server. (default: 1)
15
+ # block - An optional block that can be used to customize the logger.
16
+ #
17
+ # Examples
18
+ #
19
+ # Irrc::Client.new(2) {|c|
20
+ # c.logger = Logger.new('irrc.log')
21
+ # }
22
+ def initialize(threads=1, &block)
23
+ @thread_limit = threads.to_i
24
+ @block = block
25
+ end
26
+
27
+ # Public: Enqueue an IRR / Whois query.
28
+ #
29
+ # host - FQDN of IRR / Whois server. IRR name is also acceptable. (eg: jpirr)
30
+ # objects - IRR objects to extract. (eg: as-set, route-set, aut-num object)
31
+ # Array form is also acceptable for multiple objects.
32
+ # options - The Hash options to pass to IRR. (default: {procotol: [:ipv4, :ipv6]})
33
+ # :source - Specify authoritative IRR source names.
34
+ # If not given, any source will be accepted. (optional)
35
+ # :protocol - :ipv4, :ipv6 or [:ipv4, :ipv6]
36
+ # A String or Symbol of protcol name is acceptable. (optional)
37
+ #
38
+ # Examples
39
+ #
40
+ # client.query(:jpirr, 'AS-JPNIC', source: :jpirr, protocol: :ipv4)
41
+ # client.query(:jpirr, 'AS-JPNIC', source: [:jpirr, :radb])
42
+ def query(host, objects, options={})
43
+ raise ArgumentError, 'host required.' unless host
44
+ fqdn = Irrc::Irr.host(host) || host
45
+
46
+ queues[fqdn] ||= Queue.new
47
+ Array(objects).map {|object|
48
+ queues[fqdn] << Irrc::Query.new(object, options)
49
+ }
50
+ end
51
+
52
+ # Public: Run the query threads.
53
+ #
54
+ # Returns Raw level Array of Queries.
55
+ def run
56
+ done = []
57
+
58
+ queues.each_with_object([]) {|(fqdn, queue), workers|
59
+ @thread_limit.times.map {
60
+ workers << Thread.start {
61
+ done.push *worker_class(fqdn).new(fqdn, queues[fqdn], &@block).run
62
+ }
63
+ }
64
+ }.each {|t| t.join }
65
+
66
+ done
67
+ end
68
+
69
+ # Public: Run the query threads.
70
+ #
71
+ # Returns Decorated result Hash. See an example below:
72
+ #
73
+ # {"as-jpnic"=> # IRR object to query
74
+ # {:ipv4=> # protocol
75
+ # {"AS2515"=> # origin aut-num object
76
+ # ["202.12.30.0/24", # prefixes
77
+ # "192.41.192.0/24", #
78
+ # "211.120.240.0/21", #
79
+ # "211.120.248.0/24"]}, #
80
+ # :ipv6=>
81
+ # {"AS2515"=>
82
+ # ["2001:dc2::/32",
83
+ # "2001:0fa0::/32",
84
+ # "2001:DC2::/32"]}}}
85
+ def perform
86
+ decorate(run)
87
+ end
88
+
89
+
90
+ private
91
+
92
+ def queues
93
+ @_queues ||= {}
94
+ end
95
+
96
+ def worker_class(fqdn)
97
+ type = Irrc::Irr.type(fqdn) or raise "Unknown type of IRR for '#{fqdn}'."
98
+ Module.const_get("Irrc::#{type.capitalize}::Client")
99
+ end
100
+
101
+ def decorate(queries)
102
+ Hash[
103
+ queries.map {|query|
104
+ [query.object, query.result.to_h.select {|_, val| val }] if query.succeeded?
105
+ }.compact
106
+ ]
107
+ end
108
+ end
109
+ end