hooray 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +81 -0
- data/Rakefile +9 -0
- data/bin/hoo +9 -0
- data/lib/hooray.rb +20 -0
- data/lib/hooray/cli.rb +114 -0
- data/lib/hooray/node.rb +38 -0
- data/lib/hooray/port.rb +7 -0
- data/lib/hooray/scan.rb +19 -0
- data/lib/hooray/seek.rb +79 -0
- data/lib/hooray/settings.rb +59 -0
- data/lib/hooray/settings/devices.yml +9 -0
- data/lib/hooray/settings/nmap-mac-prefixes +19651 -0
- data/lib/hooray/settings/services.yml +11 -0
- data/lib/hooray/settings/settings.yml +7 -0
- data/lib/hooray/version.rb +3 -0
- data/spec/hooray/node_spec.rb +24 -0
- data/spec/hooray/seek_spec.rb +16 -0
- data/spec/spec_helper.rb +15 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -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
|
data/README.md
ADDED
@@ -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.
|
data/Rakefile
ADDED
data/bin/hoo
ADDED
data/lib/hooray.rb
ADDED
@@ -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
|
data/lib/hooray/cli.rb
ADDED
@@ -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
|
data/lib/hooray/node.rb
ADDED
@@ -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
|
data/lib/hooray/port.rb
ADDED
data/lib/hooray/scan.rb
ADDED
@@ -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
|
data/lib/hooray/seek.rb
ADDED
@@ -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
|