hooray 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e7ef2ad4641d2f2c855dbd7269067c578e0810c4
4
+ data.tar.gz: 63abe0efb004ead77086adf20558e42d788b1ca6
5
+ SHA512:
6
+ metadata.gz: 6feb8a504adfb80d0310f63d9805f2e0572d58f7d498ca642c7b10702ba4c59e4b2485d9163afe9e02e2bd8fd1215055ed3fbdb18bc27a489d1941f6a21f8a6e
7
+ data.tar.gz: f59f4a37cc59cd917d5ccd0efb843a98d294b48de8eee7d63e91aebe1aba3fecd915cb0429b36d0c59da2aa81e1f91bb69572abcf5f0e0722ccd6801ec0da9c5
@@ -0,0 +1,81 @@
1
+ Hooray
2
+ ======
3
+
4
+ Find devices around you.
5
+
6
+ ```
7
+ hoo list
8
+ ```
9
+ ```
10
+ Motorola Mobility | 192.168.1.70 | 34:bb:XX:XX:XX:XX
11
+ Giga-byte Technology Co. | 192.168.1.71 | 94:de:XX:XX:XX:XX
12
+ Veih's Android | 192.168.1.72 | 04:46:XX:XX:XX:XX
13
+ Nery's LG | 192.168.1.73 | cc:fa:XX:XX:XX:XX
14
+ nofxx's iPhone | 192.168.1.77 | 64:a3:XX:XX:XX:XX
15
+ LG Electronics | 192.168.1.79 | cc:fa:XX:XX:XX:XX
16
+ TP-Link | 192.168.1.253 | f8:d1:XX:XX:XX:XX
17
+ Siemens Subscriber Networks | 192.168.1.254 | 00:0b:XX:XX:XX:XX
18
+ ---
19
+ 8 devices @ 2014-12-11 13:32:04 -0200 2.85s
20
+ ```
21
+
22
+ Find running services:
23
+
24
+ ```
25
+ hoo list web
26
+ ```
27
+ ```
28
+ nofxx desktop | 192.168.1.77 | 64:a3:XX:XX:XX:XX
29
+ ```
30
+
31
+ Or simply by ports:
32
+
33
+
34
+ ```
35
+ hoo list 80
36
+ hoo list 6777 udp
37
+ ```
38
+
39
+ Monitor:
40
+
41
+ ```
42
+ hoo watch
43
+ ```
44
+ ```
45
+ New nodes @ 2014-12-11 13:53:06 -0200
46
+ NAME | IP | MAC
47
+ -------------|--------------|------------------
48
+ iPhone nofxx | 192.168.1.76 | 64:a3:XX:XX:XX:XX
49
+ ```
50
+
51
+ Use as a lib:
52
+ ```
53
+ require 'hooray'
54
+ Hooray::Seek.lan(port, protocol).devices
55
+ Hooray::Seek.new(network, port, protocol).devices
56
+ ```
57
+
58
+ ## Why?
59
+
60
+ Bind macs or fix IP's is also boring and a per device work.
61
+ As more we use wifi/ethernet devices in our company, nmap gets boring.
62
+ Not to mention slow, there's no easy way to assign names to devices I know,
63
+ which makes OS scan/port scan a needed option most times (thus making it slower).
64
+ Also (please open a issue if you know how) even in fast mode nmap won't run in under 2s.
65
+ And, on recent updates, you need sudo for all of that.
66
+
67
+ ## How?
68
+
69
+ ```
70
+ hoo init
71
+ ```
72
+
73
+ A ~/.horray folder is prepopulated:
74
+ devices.yml regex list you mac addresses with names you recognize.
75
+ services.yml regex list ports to names you recognize.
76
+
77
+
78
+ ## Credits
79
+
80
+ * Ruby net-ping gem.
81
+ * Nmap`s mac precompiled prefixes.
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new
7
+ RuboCop::RakeTask.new
8
+
9
+ task default: [:spec, :rubocop]
data/bin/hoo ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ require 'hooray'
5
+
6
+ puts
7
+ puts ' Hooray!'
8
+
9
+ Hooray::CLI.start(ARGV)
@@ -0,0 +1,20 @@
1
+ # require 'pry'
2
+ require 'yaml'
3
+ require 'open3'
4
+ require 'socket'
5
+ require 'ipaddr'
6
+ require 'macaddr'
7
+ require 'net/ping'
8
+ require 'paint/pa'
9
+ require 'table_print'
10
+
11
+ require 'hooray/settings'
12
+ require 'hooray/node'
13
+ require 'hooray/port'
14
+ require 'hooray/seek'
15
+
16
+ require 'hooray/cli'
17
+
18
+ # Hooray!
19
+ module Hooray
20
+ end
@@ -0,0 +1,114 @@
1
+ require 'thor'
2
+
3
+ module Hooray
4
+ # Nice cli
5
+ class CLI < Thor
6
+ class_option :verbose, type: :boolean, aliases: :v
7
+ class_option :network, type: :string, aliases: :n
8
+
9
+ def initialize(*args)
10
+ super
11
+ return if ARGV.first =~ /init/
12
+ Settings.load!
13
+ @start = Time.now
14
+ end
15
+
16
+ desc 'init', 'creates settings on ~'
17
+ long_desc <<-LONG
18
+
19
+ Creates local settings on your home folder.
20
+
21
+ LONG
22
+ def init
23
+ return if Dir.exist?(Settings::CONFIG_DIR)
24
+ pa 'Creating ~/.hooray directory', :red
25
+ Dir.mkdir(Settings::CONFIG_DIR)
26
+ settings_dir = File.join(File.dirname(__FILE__), 'settings')
27
+ %w(settings devices services).each do |file|
28
+ pa "Creating ~/.hooray/#{file}.yml", :red
29
+ FileUtils.cp "#{settings_dir}/#{file}.yml", Settings::CONFIG_DIR
30
+ end
31
+ end
32
+
33
+ desc 'list FILTER', 'list and apply FILTER'
34
+ long_desc <<-LONG
35
+
36
+ Lists out all devices connected to the current network.
37
+
38
+ LONG
39
+ def list(*filter)
40
+ pa "Listing devices * #{filter}", :red
41
+ print_table Seek.new(options[:network], *filter).nodes
42
+ end
43
+
44
+ desc 'watch FILTER', 'watch in realtime FILTER'
45
+ long_desc <<-LONG
46
+
47
+ Keeps listing out all devices connected to the current network.
48
+
49
+ LONG
50
+ def watch
51
+ print_table old_seek = Seek.new(options[:network]).nodes
52
+ pa "Starting watch...", :red
53
+ loop do
54
+ sleep 5
55
+ new_seek = Seek.new(options[:network]).nodes
56
+ print_change :new, (new_seek - old_seek)
57
+ print_change :old, (old_seek - new_seek), :red
58
+ old_seek = new_seek
59
+ # binding.pry
60
+ end
61
+ end
62
+
63
+ desc 'update', 'updates ssh config files'
64
+ long_desc <<-LONG
65
+
66
+ Updates your config files based on devices.
67
+
68
+ LONG
69
+ def update
70
+ end
71
+
72
+ desc 'local', 'local port status'
73
+ long_desc <<-LONG
74
+
75
+ This is a helper for those who can never remember netstat options.
76
+
77
+ LONG
78
+ def local
79
+ Kernel.system 'netstat -na | grep "tcp.*LISTEN"'
80
+ end
81
+
82
+ private
83
+
84
+ def debug(message)
85
+ return unless options[:verbose]
86
+ say message
87
+ end
88
+
89
+ def print_change(txt, changes, color = :blue)
90
+ return if changes.empty?
91
+ pa "#{txt.to_s.capitalize} nodes @ #{Time.now}", color
92
+ tp changes, :name, :ip, :mac
93
+ end
94
+
95
+ def print_table(nodes)
96
+ tp nodes, :name, :ip, :mac
97
+ puts "---"
98
+ took = (Time.now - @start).round(2)
99
+ pa "#{nodes.count} devices @ #{Time.now} #{took}s", '#777', :bold
100
+ end
101
+
102
+ def method_missing(*params)
103
+ case params.size
104
+ when 1 then
105
+ puts "Do you want to `#{params.first}` to a device?"
106
+ puts "Use #{ARGV.first} #{params.first} <device name>"
107
+ when 2 then
108
+ command, device = *params
109
+ system "#{command} "
110
+ else super
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,38 @@
1
+ module Hooray
2
+ # Node representing a device
3
+ class Node
4
+ attr_accessor :host, :name, :nick, :mac, :ip, :ports
5
+
6
+ def initialize(params = {})
7
+ @ip = params[:ip]
8
+ @mac = params[:mac]
9
+ @mac ||= Mac.addr if @ip == Seek.my_lan_ip
10
+ set_name
11
+ end
12
+
13
+ def set_name
14
+ return unless mac
15
+ if [Mac.addr].flatten.include?(mac)
16
+ @name = Socket.gethostname
17
+ else
18
+ @name = Settings.device(mac) || Settings.family(mac)
19
+ end
20
+ end
21
+
22
+ def to_ip
23
+ Addrinfo.ip(ip)
24
+ end
25
+
26
+ def <=>(other)
27
+ ip <=> other.ip
28
+ end
29
+
30
+ def eql?(other)
31
+ ip == other.ip || mac == other.mac
32
+ end
33
+
34
+ def hash
35
+ [ip, mac].hash
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ module Hooray
2
+ class Port < Struct.new(:number, :protocol, :name)
3
+ def name
4
+ @name || Settings.services[number][protocol]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module Hooray
2
+ #
3
+ # Main runner
4
+ #
5
+ class Scan < Struct.new(:target, :ports, :opts)
6
+ def run
7
+ scan = []
8
+ bots = []
9
+ pa "Starting #{Settings.list} on '#{target}' #{ports}"
10
+ [ports].flatten.each do |port|
11
+ bots << Thread.new do
12
+ scan << ip if Net::Ping::TCP.new(ip.to_s, port, 1).ping?
13
+ end
14
+ end
15
+ bots.each(&:join)
16
+ scan
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,79 @@
1
+ module Hooray
2
+ #
3
+ # Main runner
4
+ #
5
+ class Seek
6
+ attr_accessor :network, :opts, :nodes
7
+
8
+ NET_MASK = 24
9
+ TIMEOUT = 1
10
+
11
+ def initialize(network = nil, *params)
12
+ @network = network || Seek.local_mask
13
+ unless params.empty?
14
+ ports, words = params.flatten.partition { |s| s =~ /\d+/ }
15
+ @ports = ports.map(&:to_i).first # TODO
16
+ @protocol = words.select { |w| w =~ /udp|tcp/ }.join
17
+ end
18
+
19
+ @nodes = ping.sort.map do |n|
20
+ Node.new(ip: n, mac: arp_table[n.to_s]) # , name: find_name(n))
21
+ end
22
+ end
23
+ alias_method :nodes, :devices
24
+
25
+ def ping_class
26
+ return Net::Ping::External unless @protocol
27
+ @protocol =~ /udp/ ? Net::Ping::UDP : Net::Ping::TCP
28
+ end
29
+
30
+ #
31
+ # fast -> -sn -PA
32
+ #
33
+ def ping
34
+ scan = []
35
+ bots = []
36
+ # pa "Starting #{Settings.list} on '#{network}' #{@ports} #{@protocol}"
37
+ @network.to_range.each do |ip|
38
+ # next if ip == my_lan_ip
39
+ bots << Thread.new do
40
+ if ping_class.new(ip.to_s, @ports, TIMEOUT).ping?
41
+ scan << ip
42
+ print '.'
43
+ end
44
+ end
45
+ end
46
+ bots.each(&:join)
47
+ puts
48
+ scan
49
+ end
50
+
51
+ def arp_table
52
+ return @arp_table if @arp_table
53
+ @arp_table ||= {}
54
+ `arp -n`.split(/\n/).each do |l|
55
+ ip, _hw, mac, _flag, iface = l.split(/\s+/)
56
+ # p "#{ip} #{mac} #{iface}"
57
+ @arp_table.merge!(ip => mac) if iface
58
+ end
59
+ @arp_table
60
+ end
61
+
62
+ class << self
63
+
64
+ def my_ips
65
+ Socket.ip_address_list.select do |ip|
66
+ ip.ipv4_private? && !ip.ipv4_loopback?
67
+ end
68
+ end
69
+
70
+ def my_lan_ip
71
+ IPAddr.new(my_ips.first.ip_address)
72
+ end
73
+
74
+ def local_mask
75
+ my_lan_ip.mask(NET_MASK)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,59 @@
1
+ module Hooray
2
+ # App settings
3
+ class Settings
4
+ CONFIG_DIR = ENV['HOME'] + '/.hooray/'
5
+
6
+ class << self
7
+ attr_accessor :all, :services, :devices, :macs
8
+
9
+ def no_config_folder
10
+ puts "No config folder, run `#{$PROGRAM_NAME} init`"
11
+ puts
12
+ exit 1
13
+ end
14
+
15
+ def load!
16
+ no_config_folder unless Dir.exist?(CONFIG_DIR)
17
+ @all = YAML.load_file(CONFIG_DIR + 'settings.yml')
18
+ @services = YAML.load_file(CONFIG_DIR + 'services.yml')
19
+ @devices = YAML.load_file(CONFIG_DIR + 'devices.yml')
20
+ @macs = {}
21
+ File.read(CONFIG_DIR + 'nmap-mac-prefixes').each_line do |line|
22
+ next if line =~ /^\s*#/
23
+ prefix, *name = *line.split(/\s/)
24
+ @macs.store(prefix, name.join(' '))
25
+ end
26
+ end
27
+
28
+ def list
29
+ out = 'SCAN: '
30
+ out += ' SYN' if syn_scan
31
+ out += ' SERVICE' if service_scan
32
+ out += ' OS' if os_fingerprint
33
+ out
34
+ end
35
+
36
+ def device(mac)
37
+ devices[mac.to_sym] || devices[mac.to_s]
38
+ end
39
+
40
+ def family(mac)
41
+ prefix = mac.to_s.gsub(':', '')[0,6].upcase
42
+ macs[prefix]
43
+ end
44
+
45
+ def all
46
+ @all ||= {}
47
+ end
48
+
49
+ def method_missing(meth, *params)
50
+ if meth =~ /=/
51
+ all[meth.to_s.gsub('=', '')] = params.first
52
+ else
53
+ arg = meth.to_s.gsub('?', '')
54
+ all[arg] || all[arg.to_sym]
55
+ end
56
+ end
57
+ end # class << self
58
+ end # Settings
59
+ end # Hooray