hooray 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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