lib/hooray/seek.rb
module Hooray
#
# Main runner
#
class Seek
attr_accessor :network, :ports, :opts
NET_MASK = 24
TIMEOUT = 1
RANGE_REGEX = /\.{2,3}/
def initialize(network = nil, *params)
@scan = {}
config_network network
config_filters params
end
def config_network(str)
@network = str && !str.empty? ? IPAddr.new(str) : Hooray::Local.mask
end
def config_filters(params)
return if params.empty?
# Map services 'foo' -> 3000 udp
params.map! { |o| Settings.service(o) || o }
# Map Ranges 1..3 -> [1,2,3]
params.map! do |o|
next o unless o =~ RANGE_REGEX
Range.new(*o.split(RANGE_REGEX)).to_a
end
numbers, words = params.flatten.partition { |s| s.to_s =~ /\d+/ }
@ports, @protocol = numbers.map(&:to_i), words.join
end
#
# Map results to @nodes << Node.new()
#
def nodes
return @nodes if @nodes
@nodes = sweep.map do |k, v|
Node.new(ip: k, mac: Hooray::Local.arp_table[k.to_s], ports: v)
end # .reject { |n| n.mac.nil? } # remove those without mac
end
alias_method :devices, :nodes
#
# Decide how to ping
def ping_class
return Net::Ping::External unless ports
return Net::Ping::TCP unless @protocol =~ /tcp|udp|http|wmi/
Net::Ping.const_get(@protocol.upcase)
end
#
# Creates a bot per port on IP
def scan_bot(ip)
(ports || [nil]).each do |port|
Thread.new do
if ping_class.new(ip.to_s, port, TIMEOUT).ping?
@scan[ip] << port
print '.'
end
end
end
end
#
# fast -> -sn -PA
#
def sweep
network.to_range.each do |ip|
@scan[ip] = []
scan_bot(ip)
end
Thread.list.reject { |t| t == Thread.current }.each(&:join)
@scan.reject! { |_k, v| v.empty? }
end
def to_s
"Seek #{network} #{ports}"
end
end
end