module Hooray # # Main runner # class Seek attr_accessor :network, :opts, :nodes NET_MASK = 24 TIMEOUT = 1 def initialize(network = nil, *params) @network = network || Seek.local_mask set_query(params) set_nodes end alias_method :devices, :nodes # # Form need params based on user input # def set_query(params) return if params.empty? ports, words = params.flatten.partition { |s| s =~ /\d+/ } @ports = ports.map(&:to_i).first # TODO @protocol = words.select { |w| w =~ /udp|tcp/ }.join end # # Map results to @nodes << Node.new() # # BUG: sometimes ping returns true # When you run list consecutively. Pretty weird! # So we need to remove those without mac def set_nodes @nodes = ping.sort.map do |n| Node.new(ip: n, mac: arp_table[n.to_s]) # , name: find_name(n)) end.reject { |n| n.mac.nil? } # remove those without mac end def ping_class return Net::Ping::External unless @protocol @protocol =~ /udp/ ? Net::Ping::UDP : Net::Ping::TCP end # # fast -> -sn -PA # def ping scan = [] bots = [] # pa "Starting #{Settings.list} on '#{network}' #{@ports} #{@protocol}" @network.to_range.each do |ip| # next if ip == my_lan_ip bots << Thread.new do if ping_class.new(ip.to_s, @ports, TIMEOUT).ping? scan << ip print '.' end end end bots.each(&:join) puts scan end # # ARP Table reader # def arp_table return @arp_table if @arp_table @arp_table ||= {} `arp -na`.split(/\n/).each do |l| _q, ip, _at, mac, *iface = l.split(/\s+/) next unless mac =~ /:\w{2}:/ ip = ip[1..-2] # (ip) -> ip @arp_table.merge!(ip => mac) if iface end @arp_table end class << self def my_ips Socket.ip_address_list.select do |ip| ip.ipv4_private? && !ip.ipv4_loopback? end end def my_lan_ip IPAddr.new(my_ips.first.ip_address) end def local_mask my_lan_ip.mask(NET_MASK) end end end end