class Portfinder::Scanner

Portfinder Scanner base class

Attributes

monitor[R]

Scan monitor accessor for in-scan monitoring and logging (readonly)

randomize[R]

Readonly port randomization flag

result[R]

Provides access to raw scan result

Public Class Methods

new(target, port, config = { randomize: true, threaded: true, threads: 10, thread_for: :port) click to toggle source

Scanner initializer

   # File lib/portfinder/scanner.rb
12 def initialize target, port, config = {
13   randomize: true, threaded: true, threads: 10, thread_for: :port
14 }
15   @hosts = host_range target
16   @randomize = config[:randomize]
17   @ports = port_range port
18   @threaded = config[:threaded]
19   @thread_for = config[:thread_for]
20   @result = {}
21   @monitor = Monitor.new
22   @pool =
23     Pool.new(
24       threads_to_open(
25         @thread_for, config[:threads], @hosts, @ports
26       )
27     )
28 end

Public Instance Methods

generate_result(pretty = false) click to toggle source

Generates scan result in the specified format

   # File lib/portfinder/scanner.rb
61 def generate_result pretty = false
62   @result = @pool.complete_result if @threaded
63   pretty ? pretty_print(@result) : @result
64 end
json_report() click to toggle source

Generates a JSON report

   # File lib/portfinder/scanner.rb
79 def json_report
80   report_as :json
81 end
log(&logger) click to toggle source

Defines a logger (accepts logger as a block)

   # File lib/portfinder/scanner.rb
56 def log &logger
57   Thread.new { logger.call @monitor }
58 end
report_as(format) click to toggle source

Generates a report in the specified format from the scan result

   # File lib/portfinder/scanner.rb
67 def report_as format
68   case format
69   when :json
70     JSON.pretty_generate @result
71   when :yml
72     YAML.dump @result
73   else
74     raise ArgumentError, "Unknown format: #{format}"
75   end
76 end
scan(synchronus = true, &callback) click to toggle source

Scans host(s) according to provided specification

   # File lib/portfinder/scanner.rb
31 def scan synchronus = true, &callback
32   @monitor.start
33   if @threaded
34     case @thread_for
35     when :ip
36       scan_threaded_ip
37     when :port
38       scan_threaded_port
39     end
40 
41     if synchronus
42       @pool.shutdown
43       @monitor.stop
44     elsif callback
45       @pool.shutdown(false) do
46         callback.call
47         @monitor
48       end
49     end
50   else
51     synchronus_scan
52   end
53 end
yml_report() click to toggle source

Generates a YAML report

   # File lib/portfinder/scanner.rb
84 def yml_report
85   report_as :yml
86 end

Private Instance Methods

host_range(target) click to toggle source
    # File lib/portfinder/scanner.rb
121 def host_range target
122   type = target.class
123   if [Array, Enumerator].include? type
124     target
125   elsif type == String
126     [target]
127   else
128     []
129   end
130 end
port_open?(host, port) click to toggle source
    # File lib/portfinder/scanner.rb
199 def port_open? host, port
200   socket = Socket.new :INET, :STREAM, 0
201   address = Socket.pack_sockaddr_in(port, host)
202 
203   begin
204     socket.connect address
205     socket.close
206     port
207   rescue StandardError
208     nil
209   end
210 end
port_range(port) click to toggle source

:reek: FeatureEnvy

    # File lib/portfinder/scanner.rb
133 def port_range port
134   port = port.dup
135   port = [port] if port.class == Integer
136   @randomize ? port.to_a.shuffle : port
137 end
pretty_print(result) click to toggle source
   # File lib/portfinder/scanner.rb
90 def pretty_print result
91   formatted = "Scan complete!\n\n"
92   result.keys.each do |ip|
93     ports = result[ip].to_s.gsub(/[\[\]]/, "")
94     formatted << "IP: #{ip}\n\tOpen ports: #{ports}\n\n"
95   end
96 
97   formatted
98 end
scan_synchronized_port() click to toggle source
    # File lib/portfinder/scanner.rb
182 def scan_synchronized_port
183   scannable_pairs(@hosts, @ports).each do |pair|
184     host, port = pair
185     @monitor.update(*pair)
186 
187     if port_open?(*pair)
188       ports = @result[host]
189       @result[host] = ports ? ports.push(port).sort : [port]
190     end
191   end
192 end
scan_threaded_ip() click to toggle source
    # File lib/portfinder/scanner.rb
139 def scan_threaded_ip
140   @monitor.threads = @pool.size
141   @pool.result_format do |result, args, value|
142     result = result.dup
143     if value.any?
144       host = args[0]
145       result[host] = value
146     end
147     result
148   end
149 
150   @hosts.each do |host|
151     @pool.schedule host do
152       open_ports = []
153       @ports.each do |port|
154         @monitor.update host, port
155         open_ports << port if port_open? host, port
156       end
157       open_ports.sort
158     end
159   end
160 end
scan_threaded_port() click to toggle source
    # File lib/portfinder/scanner.rb
162 def scan_threaded_port
163   @monitor.threads = @pool.size
164   @pool.result_format do |result, args, value|
165     result = result.dup
166     if value
167       host = args[0][0]
168       ports = result[host]
169       result[host] = ports ? ports.push(value).sort : [value]
170     end
171     result
172   end
173 
174   scannable_pairs(@hosts, @ports).each do |pair|
175     @pool.schedule(pair) do
176       @monitor.update(*pair)
177       port_open?(*pair)
178     end
179   end
180 end
scannable_pairs(hosts, ports) click to toggle source
    # File lib/portfinder/scanner.rb
100 def scannable_pairs hosts, ports
101   Enumerator.new(hosts.size * ports.size) do |pair|
102     hosts.each do |host|
103       ports.each do |port|
104         pair << [host, port]
105       end
106     end
107   end
108 end
synchronus_scan() click to toggle source
    # File lib/portfinder/scanner.rb
194 def synchronus_scan
195   scan_synchronized_port
196   @monitor.stop
197 end
threads_to_open(thread_for, max, hosts, ports) click to toggle source
    # File lib/portfinder/scanner.rb
110 def threads_to_open thread_for, max, hosts, ports
111   case thread_for
112   when :ip
113     host_count = hosts.size
114     host_count > max ? max : host_count
115   when :port
116     tasks = scannable_pairs(hosts, ports).size
117     tasks > max ? max : tasks
118   end
119 end