irrc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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