ddis 1.0.0
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.
- data/LICENSE.txt +17 -0
- data/RATIONALE.txt +8 -0
- data/README.md +55 -0
- data/bin/ddis +36 -0
- data/lib/ddis.rb +52 -0
- data/lib/ddis/ip_iterate.rb +43 -0
- data/lib/ddis/store_ips.rb +37 -0
- metadata +102 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
ddis - DNS Discovery utility
|
2
|
+
|
3
|
+
Copyright (C) 2012 James Condron
|
4
|
+
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
6
|
+
it under the terms of the GNU General Public License as published by
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
8
|
+
(at your option) any later version.
|
9
|
+
|
10
|
+
This program is distributed in the hope that it will be useful,
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
13
|
+
GNU General Public License for more details.
|
14
|
+
|
15
|
+
You should have received a copy of the GNU General Public License
|
16
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
17
|
+
|
data/RATIONALE.txt
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Currently at work (https://simplybusiness.co.uk) I've a large infrastructure to monitor and
|
2
|
+
work with. This includes both internal/corporate and production.
|
3
|
+
|
4
|
+
One of the largest areas of technical debt we have is our network and DNS setup; we basically
|
5
|
+
have IPs no longer in use with hostnames set (which then cause issues in provisioning boxen) and
|
6
|
+
IPs which are up and don't have a PTR set.
|
7
|
+
|
8
|
+
This, initially, goes out to search for these.
|
data/README.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
ddis
|
2
|
+
==
|
3
|
+
|
4
|
+
Usage
|
5
|
+
--
|
6
|
+
|
7
|
+
Due to needing stupid rights to stupid ping one must run under root. Stupid root.
|
8
|
+
|
9
|
+
```bash
|
10
|
+
# ddis -h
|
11
|
+
Usage: ddis [options]
|
12
|
+
-r, --range [IP RANGE] IP Range to scan against
|
13
|
+
-u, --unass [UNASSIGNED STRING] Text contained in unassigned IPs
|
14
|
+
-c, --count [NUMBER] Number of times to run through
|
15
|
+
-s, --sleep [SECONDS] Number of seconds to sleep between runs
|
16
|
+
-v, --verbose See extra debug
|
17
|
+
```
|
18
|
+
|
19
|
+
The defaults are:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
ip_range = '127.0.0.1/24'
|
23
|
+
unassign = 'localhost'
|
24
|
+
count = 1
|
25
|
+
secs = 0
|
26
|
+
verbose = nil
|
27
|
+
```
|
28
|
+
|
29
|
+
For the network `10.1.0.0/16` which uses the PTR format `unassigned-0.0.1.10.example.com` we would start as per:
|
30
|
+
|
31
|
+
```bash
|
32
|
+
# ddis -r 10.1.0.0/16 -u unassigned
|
33
|
+
```
|
34
|
+
|
35
|
+
Should we want to run this over a few days to collate the results:
|
36
|
+
|
37
|
+
```bash
|
38
|
+
# ddis -r 10.1.0.0/16 -u unassigned -c 500 -s 10
|
39
|
+
```
|
40
|
+
|
41
|
+
Which would run 500 times with a ten second break between each iteration.
|
42
|
+
|
43
|
+
|
44
|
+
Data
|
45
|
+
--
|
46
|
+
|
47
|
+
The data is stored under redis following the schema:
|
48
|
+
|
49
|
+
```redis
|
50
|
+
ip.#{date.now.to_s}.up # Hosts which are up and have a PTR as per =~ /#{unass}/
|
51
|
+
ip.#{date.now.to_s}.down # Hosts whhich are down but don't have a PTR which has been reset
|
52
|
+
```
|
53
|
+
|
54
|
+
A list of times can be found under `ip.times`; the `date.now.to_s` is set when the object is created and not each time. This gives us
|
55
|
+
th econfidence that leaving ddis over multiple days wont bork our data by spreading it all over.
|
data/bin/ddis
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
5
|
+
|
6
|
+
require 'optparse'
|
7
|
+
require 'ddis'
|
8
|
+
|
9
|
+
ip_range = '127.0.0.1/24'
|
10
|
+
unassign = 'localhost'
|
11
|
+
count = 1
|
12
|
+
secs = 0
|
13
|
+
verbose = nil
|
14
|
+
|
15
|
+
OptionParser.new do |opts|
|
16
|
+
opts.banner = "Usage: ddis [options]"
|
17
|
+
|
18
|
+
opts.on("-r", "--range [IP RANGE]", "IP Range to scan against") { |r| ip_range = r }
|
19
|
+
opts.on("-u", "--unass [UNASSIGNED STRING]", "Text contained in unassigned IPs") { |u| unassign = u }
|
20
|
+
opts.on("-c", "--count [NUMBER]", "Number of times to run through") { |c| count = Integer c }
|
21
|
+
opts.on("-s", "--sleep [SECONDS]", "Number of seconds to sleep between runs") { |s| secs = Integer s }
|
22
|
+
opts.on("-v", "--verbose", "See extra debug") { |v| verbose = true }
|
23
|
+
end.parse!
|
24
|
+
|
25
|
+
ddis = DDis.new ip_range, unassign, verbose
|
26
|
+
ip = ddis.iterator.ip
|
27
|
+
|
28
|
+
(0..count).each do |run|
|
29
|
+
until ip == nil
|
30
|
+
puts "Testing #{ip}" if verbose
|
31
|
+
ddis.test_ip ip
|
32
|
+
ip = ddis.iterator.iterate
|
33
|
+
end
|
34
|
+
warn "Sleeping for #{secs} seconds" if verbose
|
35
|
+
sleep secs
|
36
|
+
end
|
data/lib/ddis.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Helper classes for ddis - DNS Discovery thing
|
4
|
+
|
5
|
+
require 'netaddr'
|
6
|
+
require 'resolv'
|
7
|
+
require 'net/ping/icmp'
|
8
|
+
|
9
|
+
require 'ddis/ip_iterate.rb'
|
10
|
+
require 'ddis/store_ips.rb'
|
11
|
+
|
12
|
+
class DDis
|
13
|
+
attr_accessor :iterator
|
14
|
+
|
15
|
+
def initialize range, unassigned, verbose=nil
|
16
|
+
@verbose = true if verbose
|
17
|
+
|
18
|
+
@unass = unassigned
|
19
|
+
@resolv = Resolv.new
|
20
|
+
@ping = Net::Ping::ICMP.new nil, nil, 1
|
21
|
+
|
22
|
+
ip_range = NetAddr::CIDR.create range
|
23
|
+
@base = ip_range.base
|
24
|
+
@size = ip_range.size
|
25
|
+
@iterator = Iterator.new @base, @size
|
26
|
+
@db = StoreIPs.new
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_ip ip
|
31
|
+
begin
|
32
|
+
hostname = @resolv.getname ip
|
33
|
+
rescue
|
34
|
+
warn "Couldn't get host for #{ip}"
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
38
|
+
@ping.host = ip
|
39
|
+
up = @ping.ping?
|
40
|
+
|
41
|
+
if up and hostname =~ /#{@unass}/
|
42
|
+
warn "#{ip} is up yet has an invalid hostname" if @verbose
|
43
|
+
@db.up_no_dns( ip )
|
44
|
+
end
|
45
|
+
|
46
|
+
if not up and hostname !~ /#{@unass}/
|
47
|
+
warn "#{ip} is down yet has a hostname set" if @verbose
|
48
|
+
@db.down_with_dns( ip )
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Iterate through IPs given a CIDR, start and end IP
|
4
|
+
|
5
|
+
class Iterator
|
6
|
+
attr_accessor :ip
|
7
|
+
|
8
|
+
def initialize start_ip, size
|
9
|
+
@start_ip = start_ip
|
10
|
+
@start_si = size
|
11
|
+
|
12
|
+
@ip = start_ip
|
13
|
+
@esize = 0
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
def increment_last ip
|
18
|
+
return nil if ip == '255.255.255.255' # End of the line
|
19
|
+
|
20
|
+
octets = ip.split "."
|
21
|
+
last = octets[-1]
|
22
|
+
|
23
|
+
return "#{increment_last octets[0..-2].join('.')}.0" if last == '255'
|
24
|
+
last = Integer(last)
|
25
|
+
last += 1
|
26
|
+
return "#{octets[0..-2].join('.')}.#{last}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def iterate
|
30
|
+
@ip = increment_last @ip
|
31
|
+
@esize += 1
|
32
|
+
|
33
|
+
if @esize == @start_si
|
34
|
+
@esize = @start_si
|
35
|
+
@ip = @start_ip
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
return @ip
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Simple redis wrapper
|
4
|
+
|
5
|
+
require 'redis'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
class StoreIPs
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@red = Redis.new
|
12
|
+
@db = Date.today.to_s
|
13
|
+
@red.sadd "ip.dates", @db
|
14
|
+
@red.save
|
15
|
+
end
|
16
|
+
|
17
|
+
def up_no_dns ip
|
18
|
+
@red.srem "ip.#{@db}.down", ip
|
19
|
+
@red.sadd "ip.#{@db}.up", ip
|
20
|
+
@red.save
|
21
|
+
end
|
22
|
+
|
23
|
+
def down_with_dns ip
|
24
|
+
@red.srem "ip.#{@db}.up", ip
|
25
|
+
@red.sadd "ip.#{@db}.down", ip
|
26
|
+
@red.save
|
27
|
+
end
|
28
|
+
|
29
|
+
def dump
|
30
|
+
0 if @red.sinter "ip.@db.down", "ip.@db.up"
|
31
|
+
{
|
32
|
+
:up => @red.smembers( "ip.#{@db}.up" ),
|
33
|
+
:down => @red.smembers( "ip.#{@db}.down" ),
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ddis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- jspc
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-07 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: net-ping
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.3
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.3
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: netaddr
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.5.0
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.0
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: redis
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 3.0.2
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.0.2
|
62
|
+
description: A small utility to determine the conformity of an IP on a network
|
63
|
+
email: james@zero-internet.org.uk
|
64
|
+
executables:
|
65
|
+
- ddis
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files:
|
68
|
+
- LICENSE.txt
|
69
|
+
- README.md
|
70
|
+
files:
|
71
|
+
- LICENSE.txt
|
72
|
+
- RATIONALE.txt
|
73
|
+
- README.md
|
74
|
+
- bin/ddis
|
75
|
+
- lib/ddis.rb
|
76
|
+
- lib/ddis/ip_iterate.rb
|
77
|
+
- lib/ddis/store_ips.rb
|
78
|
+
homepage: https://github.com/jspc/ddis
|
79
|
+
licenses: []
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- lib
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ! '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
requirements: []
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.8.24
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: A small utility to determine the conformity of an IP on a network
|
102
|
+
test_files: []
|