rangescan 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a7560ddf707ab1d55befca7e8cdffd4274618845256d4da74575d99d613c4ab9
4
- data.tar.gz: 296098c05eac8e1c7e6294a503aa6b591b2617d2fcdc3f6f4093299e9a174a53
3
+ metadata.gz: 4144b13853677049e63de5a4214bffd4140923b9627aa165793bd08a5fd3664f
4
+ data.tar.gz: 5e9a1489605be94188c2a4310013062451630b12764db065af20081c1bc2d2af
5
5
  SHA512:
6
- metadata.gz: c8a7d6badbbaa041657f86015462f3049cce8e852073a268caadfcfc76fbfd555b31c69b1380ee4846bc92279ce98cb4758d33612d7a4656bad6ca5e2a1d06f0
7
- data.tar.gz: 51537dc5b498beb430a225486b6b2ce259172e485d5bde54ed5400b191f2d909a7cb01bcf4372f1a6af72d8b1dd33e06da605449c53270d69bc60077b8e1748d
6
+ metadata.gz: e82b98bb97b2742ca54bcfd47cecde7a4bee65d7fefe841f7b76cc6dfec7832c397e8d2e422afc5f64a2533ff453bb3cf83c6ad1cbeb98948845ab5710eb84e6
7
+ data.tar.gz: 5e6e6173d6a858749fce649d25fd658a91a0d2941238f2ca730e07511e147e48440d713e07247c4a40c3299765760b403596b4122ac259a52d5e3847bfbfb4c2
@@ -0,0 +1,5 @@
1
+ version = 1
2
+
3
+ [[analyzers]]
4
+ name = "ruby"
5
+ enabled = true
data/.gitignore CHANGED
@@ -45,9 +45,9 @@ build-iPhoneSimulator/
45
45
 
46
46
  # for a library or gem, you might want to ignore these files since the code is
47
47
  # intended to run in multiple environments; otherwise, check them in:
48
- # Gemfile.lock
49
- # .ruby-version
50
- # .ruby-gemset
48
+ Gemfile.lock
49
+ .ruby-version
50
+ .ruby-gemset
51
51
 
52
52
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
53
  .rvmrc
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  # rangescan
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/rangescan.svg)](https://badge.fury.io/rb/rangescan)
3
4
  [![Build Status](https://travis-ci.com/ninoseki/rangescan.svg?branch=master)](https://travis-ci.com/ninoseki/rangescan)
4
5
  [![Coverage Status](https://coveralls.io/repos/github/ninoseki/rangescan/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/rangescan?branch=master)
5
6
  [![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/rangescan/badge)](https://www.codefactor.io/repository/github/ninoseki/rangescan)
@@ -26,13 +27,14 @@ Usage:
26
27
 
27
28
  Options:
28
29
  [--host=HOST] # Host header
29
- [--port=N] # Port to check (80 or 443)
30
- [--scheme=SCHEME] # Scheme to use (http or https)
30
+ [--port=N] # Port
31
+ [--scheme=SCHEME] # Scheme (http or https)
31
32
  [--timeout=N] # Timeout in seconds
32
- [--user-agent=USER_AGENT] # User Agent header
33
- [--veryfy-ssl], [--no-veryfy-ssl] # Verify SSL or not
33
+ [--user-agent=USER_AGENT] # User Agent
34
+ [--verify-ssl], [--no-verify-ssl] # Whether to verify SSL or not
35
+ [--max-concurrency=N] # Concurrency limit for HTTP requests to scan
34
36
 
35
- Scan an IP range & filter by a regexp
37
+ Scan an IP range & filter by a regexp (default regexp = .)
36
38
  ```
37
39
 
38
40
  ## License
@@ -3,6 +3,7 @@
3
3
  require "rangescan/version"
4
4
 
5
5
  require "rangescan/range"
6
+ require "rangescan/utils"
6
7
  require "rangescan/scanner"
7
8
  require "rangescan/matcher"
8
9
 
@@ -5,14 +5,15 @@ require "json"
5
5
 
6
6
  module RangeScan
7
7
  class CLI < Thor
8
- desc "scan [IP_WITH_SUBNET_MASK, REGEXP]", "Scan an IP range & filter by a regexp"
8
+ desc "scan [IP_WITH_SUBNET_MASK, REGEXP]", "Scan an IP range & filter by a regexp (default regexp = .)"
9
9
  method_option :host, type: :string, desc: "Host header"
10
10
  method_option :port, type: :numeric, desc: "Port"
11
11
  method_option :scheme, type: :string, desc: "Scheme (http or https)"
12
12
  method_option :timeout, type: :numeric, desc: "Timeout in seconds"
13
13
  method_option :user_agent, type: :string, desc: "User Agent"
14
14
  method_option :verify_ssl, type: :boolean, desc: "Whether to verify SSL or not"
15
- def scan(ip_with_subnet_mask, regexp)
15
+ method_option :max_concurrency, type: :numeric, desc: "Concurrency limit for HTTP requests to scan"
16
+ def scan(ip_with_subnet_mask, regexp = ".")
16
17
  symbolized_options = symbolize_hash_keys(options)
17
18
  range = Range.new(ip_with_subnet_mask)
18
19
 
@@ -11,7 +11,11 @@ module RangeScan
11
11
  def filter(results)
12
12
  results.select do |result|
13
13
  body = result.dig(:body) || ""
14
- body =~ regexp
14
+ begin
15
+ body =~ regexp
16
+ rescue ArgumentError, Encoding::CompatibilityError
17
+ false
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "protocol/http1/connection"
4
+
5
+ module Protocol
6
+ module HTTP1
7
+ class Connection
8
+ def write_request(authority, method, path, version, headers)
9
+ host = authority
10
+ if headers.include?("host")
11
+ host = headers["host"]
12
+ headers.delete "host"
13
+ end
14
+
15
+ @stream.write("#{method} #{path} #{version}\r\n")
16
+ @stream.write("host: #{host}\r\n")
17
+
18
+ write_headers(headers)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,54 +1,88 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "http"
4
- require "parallel"
3
+ require "async"
4
+ require "async/barrier"
5
+ require "async/semaphore"
6
+ require "async/http"
7
+ require "etc"
8
+
9
+ require "rangescan/monkey_patch"
5
10
 
6
11
  module RangeScan
7
12
  class Scanner
8
13
  attr_reader :context
9
14
  attr_reader :host
15
+ attr_reader :max_concurrency
10
16
  attr_reader :port
17
+ attr_reader :processor_count
11
18
  attr_reader :scheme
12
19
  attr_reader :ssl_context
13
20
  attr_reader :timeout
14
21
  attr_reader :user_agent
22
+ attr_reader :verify_ssl
15
23
 
16
- def initialize(host: nil, port: nil, scheme: "http", verify_ssl: true, timeout: 5, user_agent: nil)
24
+ def initialize(host: nil, port: nil, scheme: "http", verify_ssl: true, timeout: 5, user_agent: nil, max_concurrency: nil)
17
25
  @host = host
18
26
  @port = port || (scheme == "http" ? 80 : 443)
19
27
  @timeout = timeout
20
28
  @scheme = scheme
21
29
  @user_agent = user_agent
22
30
 
31
+ @verify_ssl = verify_ssl
32
+
23
33
  @ssl_context = OpenSSL::SSL::SSLContext.new
24
34
  @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE unless verify_ssl
35
+
36
+ @max_concurrency = max_concurrency || Etc.nprocessors * 2
37
+ end
38
+
39
+ def url_for(ipv4)
40
+ return "#{scheme}://#{ipv4}" if (port == 80 && scheme == "http") || (port == 443 && scheme == "https")
41
+
42
+ "#{scheme}://#{ipv4}:#{port}"
25
43
  end
26
44
 
27
45
  def scan(ipv4s)
28
- Parallel.map(ipv4s) do |ipv4|
29
- get ipv4
30
- end.compact
46
+ results = []
47
+ Async do
48
+ barrier = Async::Barrier.new
49
+ semaphore = Async::Semaphore.new(max_concurrency, parent: barrier)
50
+
51
+ ipv4s.each do |ipv4|
52
+ semaphore.async do
53
+ url = url_for(ipv4)
54
+
55
+ endpoint = Async::HTTP::Endpoint.parse(url, ssl_context: ssl_context, timeout: timeout)
56
+ client = Async::HTTP::Client.new(endpoint, retries: 0)
57
+ res = client.get(endpoint.path, default_request_headers)
58
+
59
+ headers = res.headers.fields.to_h
60
+ body = res.read || ""
61
+
62
+ results << {
63
+ url: url,
64
+ ipv4: ipv4,
65
+ code: res.status,
66
+ headers: Utils.to_utf8(headers),
67
+ body: Utils.to_utf8(body)
68
+ }
69
+ rescue Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, EOFError, OpenSSL::SSL::SSLError, Async::TimeoutError
70
+ next
71
+ end
72
+ end
73
+ barrier.wait
74
+ end
75
+ results.compact
31
76
  end
32
77
 
33
78
  private
34
79
 
35
- def default_headers
36
- { host: host, user_agent: user_agent }.compact
80
+ def default_request_headers
81
+ @default_request_headers ||= { "host" => host, "user-agent" => user_agent }.compact
37
82
  end
38
83
 
39
84
  def ssl_options
40
85
  scheme == "http" ? {} : { ssl_context: ssl_context }
41
86
  end
42
-
43
- def get(ipv4)
44
- url = "#{scheme}://#{ipv4}:#{port}"
45
-
46
- begin
47
- res = HTTP.timeout(timeout).headers(default_headers).get(url, ssl_options)
48
- { ipv4: ipv4, code: res.code, body: res.body.to_s }
49
- rescue StandardError
50
- nil
51
- end
52
- end
53
87
  end
54
88
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RangeScan
4
+ class Utils
5
+ class << self
6
+ def to_utf8(obj)
7
+ return obj.dup.force_encoding(Encoding::UTF_8) if obj.is_a?(String)
8
+
9
+ obj.map do |k, v|
10
+ k = k.dup.force_encoding(Encoding::UTF_8) if k.is_a?(String)
11
+ v = v.dup.force_encoding(Encoding::UTF_8) if v.is_a?(String)
12
+ [k, v]
13
+ end.to_h
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RangeScan
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -30,10 +30,10 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "glint", "~> 0.1"
31
31
  spec.add_development_dependency "rake", "~> 13.0"
32
32
  spec.add_development_dependency "rspec", "~> 3.9"
33
- spec.add_development_dependency "webmock", "~> 3.8"
33
+ spec.add_development_dependency "webmock", "~> 3.9"
34
34
 
35
- spec.add_dependency "http", "~> 4.4"
35
+ spec.add_dependency "async", "~> 1.26"
36
+ spec.add_dependency "async-http", "~> 0.52"
36
37
  spec.add_dependency "ipaddress", "~> 0.8"
37
- spec.add_dependency "parallel", "~> 1.19"
38
38
  spec.add_dependency "thor", "~> 1.0"
39
39
  end
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": [
3
+ "config:base"
4
+ ]
5
+ }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rangescan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-16 00:00:00.000000000 Z
11
+ date: 2020-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,56 +86,56 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.8'
89
+ version: '3.9'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.8'
96
+ version: '3.9'
97
97
  - !ruby/object:Gem::Dependency
98
- name: http
98
+ name: async
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '4.4'
103
+ version: '1.26'
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '4.4'
110
+ version: '1.26'
111
111
  - !ruby/object:Gem::Dependency
112
- name: ipaddress
112
+ name: async-http
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0.8'
117
+ version: '0.52'
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
- version: '0.8'
124
+ version: '0.52'
125
125
  - !ruby/object:Gem::Dependency
126
- name: parallel
126
+ name: ipaddress
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - "~>"
130
130
  - !ruby/object:Gem::Version
131
- version: '1.19'
131
+ version: '0.8'
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - "~>"
137
137
  - !ruby/object:Gem::Version
138
- version: '1.19'
138
+ version: '0.8'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: thor
141
141
  requirement: !ruby/object:Gem::Requirement
@@ -158,11 +158,11 @@ executables:
158
158
  extensions: []
159
159
  extra_rdoc_files: []
160
160
  files:
161
+ - ".deepsource.toml"
161
162
  - ".gitignore"
162
163
  - ".rspec"
163
164
  - ".travis.yml"
164
165
  - Gemfile
165
- - Gemfile.lock
166
166
  - LICENSE
167
167
  - README.md
168
168
  - Rakefile
@@ -172,16 +172,19 @@ files:
172
172
  - lib/rangescan.rb
173
173
  - lib/rangescan/cli.rb
174
174
  - lib/rangescan/matcher.rb
175
+ - lib/rangescan/monkey_patch.rb
175
176
  - lib/rangescan/range.rb
176
177
  - lib/rangescan/scanner.rb
178
+ - lib/rangescan/utils.rb
177
179
  - lib/rangescan/version.rb
178
180
  - rangescan.gemspec
181
+ - renovate.json
179
182
  homepage: https://github.com/ninoseki/rangescan
180
183
  licenses:
181
184
  - MIT
182
185
  metadata:
183
186
  homepage_uri: https://github.com/ninoseki/rangescan
184
- post_install_message:
187
+ post_install_message:
185
188
  rdoc_options: []
186
189
  require_paths:
187
190
  - lib
@@ -197,7 +200,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
197
200
  version: '0'
198
201
  requirements: []
199
202
  rubygems_version: 3.1.2
200
- signing_key:
203
+ signing_key:
201
204
  specification_version: 4
202
205
  summary: Scan websites on a specific IP range
203
206
  test_files: []
@@ -1,94 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- rangescan (0.1.0)
5
- http (~> 4.4)
6
- ipaddress (~> 0.8)
7
- parallel (~> 1.19)
8
- thor (~> 1.0)
9
-
10
- GEM
11
- remote: https://rubygems.org/
12
- specs:
13
- addressable (2.7.0)
14
- public_suffix (>= 2.0.2, < 5.0)
15
- coveralls (0.8.23)
16
- json (>= 1.8, < 3)
17
- simplecov (~> 0.16.1)
18
- term-ansicolor (~> 1.3)
19
- thor (>= 0.19.4, < 2.0)
20
- tins (~> 1.6)
21
- crack (0.4.3)
22
- safe_yaml (~> 1.0.0)
23
- diff-lcs (1.3)
24
- docile (1.3.2)
25
- domain_name (0.5.20190701)
26
- unf (>= 0.0.5, < 1.0.0)
27
- ffi (1.13.1)
28
- ffi-compiler (1.0.1)
29
- ffi (>= 1.0.0)
30
- rake
31
- glint (0.1.0)
32
- hashdiff (1.0.1)
33
- http (4.4.1)
34
- addressable (~> 2.3)
35
- http-cookie (~> 1.0)
36
- http-form_data (~> 2.2)
37
- http-parser (~> 1.2.0)
38
- http-cookie (1.0.3)
39
- domain_name (~> 0.5)
40
- http-form_data (2.3.0)
41
- http-parser (1.2.1)
42
- ffi-compiler (>= 1.0, < 2.0)
43
- ipaddress (0.8.3)
44
- json (2.3.0)
45
- parallel (1.19.1)
46
- public_suffix (4.0.5)
47
- rake (13.0.1)
48
- rspec (3.9.0)
49
- rspec-core (~> 3.9.0)
50
- rspec-expectations (~> 3.9.0)
51
- rspec-mocks (~> 3.9.0)
52
- rspec-core (3.9.2)
53
- rspec-support (~> 3.9.3)
54
- rspec-expectations (3.9.2)
55
- diff-lcs (>= 1.2.0, < 2.0)
56
- rspec-support (~> 3.9.0)
57
- rspec-mocks (3.9.1)
58
- diff-lcs (>= 1.2.0, < 2.0)
59
- rspec-support (~> 3.9.0)
60
- rspec-support (3.9.3)
61
- safe_yaml (1.0.5)
62
- simplecov (0.16.1)
63
- docile (~> 1.1)
64
- json (>= 1.8, < 3)
65
- simplecov-html (~> 0.10.0)
66
- simplecov-html (0.10.2)
67
- sync (0.5.0)
68
- term-ansicolor (1.7.1)
69
- tins (~> 1.0)
70
- thor (1.0.1)
71
- tins (1.25.0)
72
- sync
73
- unf (0.1.4)
74
- unf_ext
75
- unf_ext (0.0.7.7)
76
- webmock (3.8.3)
77
- addressable (>= 2.3.6)
78
- crack (>= 0.3.2)
79
- hashdiff (>= 0.4.0, < 2.0.0)
80
-
81
- PLATFORMS
82
- ruby
83
-
84
- DEPENDENCIES
85
- bundler (~> 2.1)
86
- coveralls (~> 0.8)
87
- glint (~> 0.1)
88
- rake (~> 13.0)
89
- rangescan!
90
- rspec (~> 3.9)
91
- webmock (~> 3.8)
92
-
93
- BUNDLED WITH
94
- 2.1.4