portfinder 0.0.1 → 0.0.2
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 +4 -4
- data/.codeclimate.yml +18 -0
- data/.gitignore +11 -0
- data/.reek +26 -0
- data/.rubocop.yml +19 -0
- data/.travis.yml +29 -0
- data/Appraisals +7 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +174 -0
- data/Rakefile +32 -0
- data/bin/pf +101 -0
- data/bin/portfinder +101 -0
- data/gemfiles/slop_4.4.0.gemfile +7 -0
- data/gemfiles/slop_4.5.0.gemfile +7 -0
- data/lib/portfinder.rb +67 -3
- data/lib/portfinder/constants.rb +31 -0
- data/lib/portfinder/error.rb +9 -0
- data/lib/portfinder/monitor.rb +48 -0
- data/lib/portfinder/option.rb +23 -0
- data/lib/portfinder/parser.rb +91 -0
- data/lib/portfinder/pool.rb +59 -0
- data/lib/portfinder/scanner.rb +211 -2
- data/lib/portfinder/version.rb +5 -0
- data/portfinder.gemspec +46 -0
- metadata +142 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68802b1d01723c118d38ca4c6b34099bda3d73bf
|
4
|
+
data.tar.gz: f3c807ed4f77a5f3e24a36e3160fd7601cdb7eac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a7c66777be78c5268037be60ca0a472ac053330ad6a3af54159fcac1c688764eb16550072b30e29c155bc2bffffe17f8625819792fb8b2fcfd3708010d756b6
|
7
|
+
data.tar.gz: ace35b8a20fc2d9014e70d10f906c8ecdc871441f8fe1cb70312a8e6ce7747c99ae6eedea9b8274ca148d684f6317f4002bf08cbd4318d88118c3b3eb045deef
|
data/.codeclimate.yml
ADDED
data/.gitignore
ADDED
data/.reek
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# FIXME: Remove
|
2
|
+
TooManyStatements:
|
3
|
+
max_statements: 20
|
4
|
+
UtilityFunction:
|
5
|
+
enabled: false
|
6
|
+
TooManyMethods:
|
7
|
+
max_methods: 20
|
8
|
+
TooManyInstanceVariables:
|
9
|
+
max_instance_variables: 15
|
10
|
+
NestedIterators:
|
11
|
+
max_allowed_nesting: 3
|
12
|
+
LongParameterList:
|
13
|
+
max_params: 5
|
14
|
+
ControlParameter:
|
15
|
+
enabled: false
|
16
|
+
BooleanParameter:
|
17
|
+
enabled: false
|
18
|
+
TooManyConstants:
|
19
|
+
max_constants: 20
|
20
|
+
Attribute:
|
21
|
+
enabled: false
|
22
|
+
DuplicateMethodCall:
|
23
|
+
enabled: false
|
24
|
+
|
25
|
+
exclude_paths:
|
26
|
+
- test
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.2
|
3
|
+
Exclude:
|
4
|
+
- "portfinder.gemspec"
|
5
|
+
Style/StringLiterals:
|
6
|
+
EnforcedStyle: double_quotes
|
7
|
+
Style/UnneededCapitalW:
|
8
|
+
Enabled: false
|
9
|
+
Style/MethodDefParentheses:
|
10
|
+
Enabled: false
|
11
|
+
Metrics/MethodLength:
|
12
|
+
Max: 20
|
13
|
+
Metrics/ClassLength:
|
14
|
+
Max: 200
|
15
|
+
Metrics/AbcSize:
|
16
|
+
Enabled: false
|
17
|
+
# FIXME: Remove
|
18
|
+
Performance/RedundantBlockCall:
|
19
|
+
Enabled: false
|
data/.travis.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
sudo: false
|
2
|
+
language: ruby
|
3
|
+
rvm:
|
4
|
+
- 2.2.7
|
5
|
+
- 2.3.4
|
6
|
+
- 2.4.1
|
7
|
+
- ruby-head
|
8
|
+
gemfile:
|
9
|
+
- gemfiles/slop_4.5.0.gemfile
|
10
|
+
- gemfiles/slop_4.4.0.gemfile
|
11
|
+
matrix:
|
12
|
+
allow_failures:
|
13
|
+
- rvm: ruby-head
|
14
|
+
fast_finish: true
|
15
|
+
cache: bundler
|
16
|
+
before_install: gem install bundler
|
17
|
+
addons:
|
18
|
+
code_climate:
|
19
|
+
repo_token: ac8817e9eb34cc305959d1b0951195e3615ba8efb80d393c5c8b62baafaac369
|
20
|
+
after_success:
|
21
|
+
- bundle exec codeclimate-test-reporter
|
22
|
+
deploy:
|
23
|
+
provider: rubygems
|
24
|
+
api_key:
|
25
|
+
secure: mZCsES86YL9bLz7X4IzZgGIZjEhfRDSe6v69gwB+HrotdJM2+jUY+MwTGv5KEfcAvlc8nB9EQ0NuX/9bZU77XlajCjdkhpg4+wVxJ9yzo2eoS9eYi6KycFqbw1zMTTOPjA9V9jHtxX+FsmASu/ci1aEQ0qtq6b08XnMdrmhZpwDqmf3XaIHMhPKQxTq0XlnMUZOo0EsuW7jXP6M3D+aEdC+lQi4ObBHXX0b2EZyzKwCCZWqhEMquOr6TL9xLIFWg87uV4DtLcmgGqczvCC0dmUAqS4ZTgkwC8IGec47cIQUTCX4NkirabsdBTFlCz0vd6VCoLZ8CT+9dHkCHJjkobcxeLwhsG0im0TzFh6jyok9gLvhSMHqWxfkTymBh/DHgRx1lXM61UPeIZYih0N/c152FXw0GgrWh6+ikGcNQRwpTEWpvNASqIxllsj8Y0S6SaC1Us5yR/WaV836aUFa2R9ip16oUOWM4LadxYi/IOWu6dzP2fHNXGQf8M1IjDczqzxVT5OBa/vj6m+yyd8jORZHPA2dXFi4pCnZgBr3ps/+HiYNbYEonvHODSORSDweeAXtvFBp8GUvkerGp2szROT9S6k2K8XtG8etA14R0jjBLqQRfoMpzNS9Sn/dQ+Z3z1SQ0yTLz1oVI0KG0QAv5QpRoos8sMEwkbZvY2vwbto4=
|
26
|
+
gem: portfinder
|
27
|
+
on:
|
28
|
+
tags: true
|
29
|
+
repo: at-shakil/portfinder
|
data/Appraisals
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Tahmid Shakil
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
# Portfinder
|
2
|
+
|
3
|
+
[](https://travis-ci.org/at-shakil/portfinder)
|
4
|
+
[](https://badge.fury.io/rb/portfinder)
|
5
|
+
[](https://gemnasium.com/github.com/at-shakil/portfinder)
|
6
|
+
[](https://codeclimate.com/github/at-shakil/portfinder/coverage)
|
7
|
+
[](http://inch-ci.org/github/at-shakil/portfinder)
|
8
|
+
[](https://codeclimate.com/github/at-shakil/portfinder)
|
9
|
+
[](https://codeclimate.com/github/at-shakil/portfinder)
|
10
|
+
|
11
|
+
## Summary
|
12
|
+
|
13
|
+
Portfinder is a ruby based port scanner with features like network/CIDR
|
14
|
+
scanning, port randomization, hostname discovery and banner grabbing.
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Portfinder installation is as simple as a gem installation can get.
|
19
|
+
|
20
|
+
```sh
|
21
|
+
gem install portfinder
|
22
|
+
```
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
### As a CLI tool
|
27
|
+
|
28
|
+
```sh
|
29
|
+
portfinder <host> [--port=PORT] [--thread=THREAD] [--randomize]
|
30
|
+
[--out=OUT_FILE] [--verbose]
|
31
|
+
```
|
32
|
+
|
33
|
+
`portfinder` can also be invoked using it's aliased form `pf`.
|
34
|
+
|
35
|
+
To it's simplest form, single port of a host can be scanned.
|
36
|
+
|
37
|
+
```sh
|
38
|
+
portfinder 192.168.1.1 -p 80
|
39
|
+
```
|
40
|
+
|
41
|
+
It is possible to scan multiple ports of a host. In this case, ports can be a
|
42
|
+
*range*,
|
43
|
+
|
44
|
+
```sh
|
45
|
+
portfinder 192.168.1.1 -p 1-1024
|
46
|
+
```
|
47
|
+
|
48
|
+
Or, a list of *selections*:
|
49
|
+
|
50
|
+
```sh
|
51
|
+
portfinder 192.168.1.1 -p 22,80,8080,443
|
52
|
+
```
|
53
|
+
|
54
|
+
Similarly, a scan can be performed on a selection of hosts,
|
55
|
+
|
56
|
+
```sh
|
57
|
+
portfinder 192.168.1.1,192.168.1.100,192.168.1.101 -p 1-65535
|
58
|
+
```
|
59
|
+
|
60
|
+
or, a range of hosts,
|
61
|
+
|
62
|
+
```sh
|
63
|
+
portfinder 192.168.1.1-10 -p 1-65535
|
64
|
+
```
|
65
|
+
|
66
|
+
or, on an entire network block, if you like.
|
67
|
+
|
68
|
+
```sh
|
69
|
+
portfinder 192.168.1.0/24 -p 1-65535
|
70
|
+
```
|
71
|
+
|
72
|
+
If a large number of host needs to be scanned, you may choose to increase the
|
73
|
+
number of concurrent scanners using the available `--thread` option.
|
74
|
+
|
75
|
+
```sh
|
76
|
+
portfinder 192.168.1.0/24 -p 1-65535 -t 20
|
77
|
+
```
|
78
|
+
|
79
|
+
By default, ten scanner threads are spawned at max.
|
80
|
+
|
81
|
+
When multiple ports are being scanned, they get scanned in the ascending order,
|
82
|
+
or in the provided port selection order. If a randomized scan order is expected,
|
83
|
+
`--randomize` flag can be utilized.
|
84
|
+
|
85
|
+
```sh
|
86
|
+
portfinder 192.168.1.0/24 -r
|
87
|
+
```
|
88
|
+
|
89
|
+
### As an API
|
90
|
+
|
91
|
+
A minimal usage example,
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
require "portfinder"
|
95
|
+
|
96
|
+
scanner = Portfinder::Scanner.new("192.168.1.1", [22, 80, 8080], threads = 5)
|
97
|
+
scanner.scan
|
98
|
+
puts "\nOpen ports detected: #{scanner.result[host]}"
|
99
|
+
puts "Raw scan result: #{scanner.result}"
|
100
|
+
yml_stream = scanner.report_as "yml"
|
101
|
+
json_stream = scanner.json_report
|
102
|
+
```
|
103
|
+
|
104
|
+
It is possible to use the API in different modes,
|
105
|
+
|
106
|
+
#### Mode 1: Blocking mode with monitoring
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
scanner =
|
110
|
+
Portfinder::Scanner.new(
|
111
|
+
hosts, ports,
|
112
|
+
randomize: false, threaded: true, threads: 10, thread_for: :port
|
113
|
+
)
|
114
|
+
|
115
|
+
scanner.log do |monitor|
|
116
|
+
puts "Active threads:\t#{monitor.threads}\nScanning now:\n"
|
117
|
+
while true
|
118
|
+
print "\tHost:\t#{monitor.host}\tPort:\t#{monitor.port}\tStatus: #{
|
119
|
+
monitor.state}\r"
|
120
|
+
sleep 0.1
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
scanner.scan
|
125
|
+
puts "\nScan complete!\n\nResult: #{scanner.generate_result}"
|
126
|
+
|
127
|
+
format = "json"
|
128
|
+
file = open("export.#{format}", "wb")
|
129
|
+
file.write scanner.report_as format.to_sym
|
130
|
+
file.close
|
131
|
+
```
|
132
|
+
|
133
|
+
#### Mode 2: Partial blocking (join during result invocation)
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
scanner = Portfinder::Scanner.new("192.168.0.101", 1..65535)
|
137
|
+
#logger can be placed here...
|
138
|
+
|
139
|
+
scanner.scan synchronus = false
|
140
|
+
|
141
|
+
# logger can be placed here...
|
142
|
+
puts "\nScan complete!\n\nResult: #{scanner.generate_result}"
|
143
|
+
```
|
144
|
+
|
145
|
+
#### Mode 3 (GUI): Non-blocking (callback invocation upon completion)
|
146
|
+
|
147
|
+
(NOTE: Parent thread must be alive to receive callback)
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
scanner = Portfinder::Scanner.new("192.168.0.101", 1..65535)
|
151
|
+
|
152
|
+
scanner.scan(false) do
|
153
|
+
puts "\nScan complete!\n\nResult: #{scanner.generate_result}"
|
154
|
+
end
|
155
|
+
|
156
|
+
# logger can be placed here...
|
157
|
+
|
158
|
+
sleep 10
|
159
|
+
```
|
160
|
+
|
161
|
+
Please note that the default scanner scans TCP ports using a full handshake
|
162
|
+
(which is not, well..., stealthy. But, if you were expecting this feature, it's
|
163
|
+
gonna be available on the TCP SYN scanner release).
|
164
|
+
|
165
|
+
It's also worth noting that, the current implementation doesn't check for host
|
166
|
+
status (alive/dead). So, scan can be considerably slow for dead hosts.
|
167
|
+
|
168
|
+
## Contributing
|
169
|
+
|
170
|
+
If you are interested in contributing, please [submit a pull request](https://help.github.com/articles/about-pull-requests/).
|
171
|
+
|
172
|
+
## License
|
173
|
+
|
174
|
+
[MIT](http://opensource.org/licenses/MIT)
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler/setup"
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
require "rdoc/task"
|
6
|
+
|
7
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
8
|
+
rdoc.main = "README.md"
|
9
|
+
rdoc.rdoc_dir = "rdoc"
|
10
|
+
rdoc.title = "Portfinder"
|
11
|
+
rdoc.markup = "markdown"
|
12
|
+
rdoc.options << "--line-numbers"
|
13
|
+
rdoc.rdoc_files.include("README.md")
|
14
|
+
rdoc.rdoc_files.include(
|
15
|
+
[
|
16
|
+
"lib/portfinder.rb", "lib/portfinder/scanner.rb",
|
17
|
+
"lib/portfinder/version.rb"
|
18
|
+
]
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
Rake::TestTask.new(:test) do |t|
|
23
|
+
t.libs << "test"
|
24
|
+
t.libs << "lib"
|
25
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
26
|
+
end
|
27
|
+
|
28
|
+
task :appraise do
|
29
|
+
exec "appraisal install && appraisal rake"
|
30
|
+
end
|
31
|
+
|
32
|
+
task default: :test
|
data/bin/pf
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "slop"
|
3
|
+
require "portfinder"
|
4
|
+
require "portfinder/option"
|
5
|
+
|
6
|
+
module Portfinder
|
7
|
+
# Portfinder command-line interface base class
|
8
|
+
class CLI
|
9
|
+
def self.start argv
|
10
|
+
new(argv).start
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize argv
|
14
|
+
@host, options = preprocess argv
|
15
|
+
@options, @help_str = prepare_options options, @host
|
16
|
+
end
|
17
|
+
|
18
|
+
def start
|
19
|
+
@host ? scan(@options) : help
|
20
|
+
end
|
21
|
+
|
22
|
+
def scan options
|
23
|
+
scanner =
|
24
|
+
Portfinder::Scanner.new(
|
25
|
+
options[:host], options[:port],
|
26
|
+
randomize: options[:randomize], threaded: true,
|
27
|
+
threads: options[:thread], thread_for: :port
|
28
|
+
)
|
29
|
+
scanner.scan
|
30
|
+
puts scanner.generate_result true
|
31
|
+
end
|
32
|
+
|
33
|
+
def help
|
34
|
+
puts @help_str
|
35
|
+
end
|
36
|
+
|
37
|
+
def version
|
38
|
+
puts "v#{Portfinder::VERSION}"
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def preprocess argv
|
45
|
+
default_options = ["-h", "--help"]
|
46
|
+
host = argv[0]
|
47
|
+
if default_options.include? host
|
48
|
+
host = nil
|
49
|
+
options = argv
|
50
|
+
else
|
51
|
+
options = argv[1..-1] || []
|
52
|
+
end
|
53
|
+
|
54
|
+
[host, options]
|
55
|
+
end
|
56
|
+
|
57
|
+
# rubocop:disable Style/MethodLength
|
58
|
+
def option_parser
|
59
|
+
opts = Slop::Options.new
|
60
|
+
opts.banner = "Commands:"
|
61
|
+
opts.separator " portfinder # Display available options"
|
62
|
+
opts.separator(
|
63
|
+
" portfinder <host> # Scans host(s) for provided options"
|
64
|
+
)
|
65
|
+
opts.separator ""
|
66
|
+
opts.separator "Options:"
|
67
|
+
opts.port(
|
68
|
+
"-p", "--port", "# Specify a single port, range or selections",
|
69
|
+
default: 1..1024
|
70
|
+
)
|
71
|
+
opts.int "-t", "--thread", "# Specify threads to spawn", default: 10
|
72
|
+
opts.bool "-r", "--randomize", "# Randomize port scan order"
|
73
|
+
opts.out(
|
74
|
+
"-o", "--out", "# Dump scan result to the specified file",
|
75
|
+
default: "#{@host ? @host.gsub(%r{[./]}, '_') : 'export'}.json"
|
76
|
+
)
|
77
|
+
opts.bool "-v", "--verbose", "# More information during scan"
|
78
|
+
opts.bool "-h", "--help", "# Describe available commands and options"
|
79
|
+
|
80
|
+
Slop::Parser.new opts
|
81
|
+
end
|
82
|
+
|
83
|
+
# Refactor
|
84
|
+
def prepare_options options, host
|
85
|
+
version_opt = ["-V", "--version"]
|
86
|
+
version if version_opt.include?(host)
|
87
|
+
|
88
|
+
parsed = option_parser.parse options
|
89
|
+
parsed_hash = parsed.to_h
|
90
|
+
if host && /^[^-]+/ =~ host
|
91
|
+
parsed_hash.merge!(
|
92
|
+
Slop.parse ["--host", host] { |opt| opt.host "--host" }
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
[parsed_hash, parsed.to_s]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
Portfinder::CLI.start ARGV
|