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.
@@ -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
+
@@ -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.
@@ -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.
@@ -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
@@ -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: []