domain-probe 1.0.0 → 1.2.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/README.md CHANGED
@@ -1,3 +1,34 @@
1
1
  = Domain::Probe
2
2
 
3
- Domain::Probe is a simple library to probe the DNS records under specific domain, as many as possible
3
+ Domain::Probe is a simple library to probe the DNS records under specific domain, as many as possible
4
+
5
+ == Features
6
+
7
+ * Queries from authority name servers
8
+ * Recursive resolving
9
+ * Zone name detection
10
+
11
+
12
+ == Requirements
13
+
14
+ * Ruby >= 1.8.7
15
+
16
+
17
+ == Install
18
+
19
+ Just use RubyGems:
20
+
21
+ $ gem install domain-probe
22
+
23
+ If you want to install from source, you can use Rake:
24
+
25
+ $ rake install
26
+
27
+
28
+ == How to use
29
+
30
+ 1. require 'domain-probe'
31
+ 2. include Probe
32
+ 3. collect_records "www.facebook.com"
33
+
34
+
@@ -32,7 +32,14 @@ module Probe
32
32
  # collect the records under domain domain
33
33
  #
34
34
  def self.collect_records domain
35
- self.new.collect_records domain
35
+ self.new(domain).collect_records
36
+ end
37
+
38
+ #
39
+ # collect the ns records
40
+ #
41
+ def self.collect_ns_records domain
42
+ self.new(domain).collect_ns_records
36
43
  end
37
44
 
38
45
  #
@@ -40,7 +47,8 @@ module Probe
40
47
  #
41
48
  #
42
49
  #
43
- def initialize()
50
+ def initialize(domain)
51
+ @domain = domain.downcase
44
52
  @a_records = []
45
53
  @aaaa_records = []
46
54
  @cname_records = []
@@ -49,6 +57,7 @@ module Probe
49
57
  @txt_records = []
50
58
  @hinfo_records = []
51
59
  @srv_records = []
60
+ @spf_records = []
52
61
  @ns_records = []
53
62
  @semaphore = Mutex.new
54
63
  end
@@ -62,14 +71,17 @@ module Probe
62
71
  attr_accessor :hinfo_records
63
72
  attr_accessor :srv_records
64
73
  attr_accessor :ns_records
74
+ attr_accessor :spf_records
65
75
  attr_accessor :semaphore
76
+ attr_accessor :domain
66
77
 
67
78
  #
68
79
  # collect the records under domain domain
69
80
  #
70
- def collect_records domain
71
- raise ArgumentError, "Domain name is expected" unless domain
72
- domain = zone = Util.detect_zone(domain)
81
+ def collect_records
82
+ raise ArgumentError, "Domain name is expected" unless self.domain
83
+ domain = zone = Util.detect_zone(self.domain)
84
+ return [] if !zone
73
85
 
74
86
  threads = []
75
87
  nameservers = Util.detect_nameservers zone
@@ -108,6 +120,9 @@ module Probe
108
120
  #SRV records
109
121
  threads << threaded_resolve(domain,Net::DNS::SRV,zone,nameservers)
110
122
 
123
+ #SPF records
124
+ threads << threaded_resolve(domain,Net::DNS::SPF,zone,nameservers)
125
+
111
126
  #NS records
112
127
  threads << threaded_resolve(domain,Net::DNS::NS,zone,nameservers)
113
128
 
@@ -115,7 +130,36 @@ module Probe
115
130
  t.join
116
131
  end
117
132
 
118
- self.a_records + self.aaaa_records + self.cname_records + self.mx_records + self.mr_records + self.txt_records + self.hinfo_records + self.srv_records + self.ns_records
133
+ results = {
134
+ "a" => self.a_records,
135
+ "aaaa" => self.aaaa_records,
136
+ "cname" => self.cname_records,
137
+ "mx" => self.mx_records,
138
+ "mr" => self.mr_records,
139
+ "txt" => self.txt_records,
140
+ "hinfo" => self.hinfo_records,
141
+ "srv" => self.srv_records,
142
+ "ns" => self.ns_records,
143
+ "spf" => self.spf_records
144
+ }
145
+ end
146
+
147
+ def collect_ns_records
148
+ raise ArgumentError, "Domain name is expected" unless self.domain
149
+ domain = zone = Util.detect_zone(self.domain)
150
+ return [] if !zone
151
+
152
+ threads = []
153
+ nameservers = Util.detect_nameservers zone
154
+
155
+ #NS records
156
+ threads << threaded_resolve(domain,Net::DNS::NS,zone,nameservers)
157
+
158
+ threads.each do |t|
159
+ t.join
160
+ end
161
+
162
+ self.ns_records
119
163
  end
120
164
 
121
165
  private
@@ -137,23 +181,25 @@ module Probe
137
181
  self.semaphore.synchronize {
138
182
  case record.type
139
183
  when "A"
140
- self.a_records << record unless self.a_records.include? record
184
+ self.a_records << record.to_hash(zone) unless self.a_records.include? record.to_hash(zone)
141
185
  when "AAAA"
142
- self.aaaa_records << record unless self.aaaa_records.include? record
186
+ self.aaaa_records << record.to_hash(zone) unless self.aaaa_records.include? record.to_hash(zone)
143
187
  when "CNAME"
144
- self.cname_records << record unless self.cname_records.include? record
188
+ self.cname_records << record.to_hash(zone) unless self.cname_records.include? record.to_hash(zone)
145
189
  when "NS"
146
- self.ns_records << record unless self.ns_records.include? record
190
+ self.ns_records << record.to_hash(zone) unless self.ns_records.include? record.to_hash(zone)
147
191
  when "MX"
148
- self.mx_records << record unless self.mx_records.include? record
192
+ self.mx_records << record.to_hash(zone) unless self.mx_records.include? record.to_hash(zone)
149
193
  when "MR"
150
- self.mr_records << record unless self.mr_records.include? record
194
+ self.mr_records << record.to_hash(zone) unless self.mr_records.include? record.to_hash(zone)
151
195
  when "TXT"
152
- self.txt_records << record unless self.txt_records.include? record
196
+ self.txt_records << record.to_hash(zone) unless self.txt_records.include? record.to_hash(zone)
153
197
  when "SRV"
154
- self.srv_records << record unless self.srv_records.include? record
198
+ self.srv_records << record.to_hash(zone) unless self.srv_records.include? record.to_hash(zone)
155
199
  when "HINFO"
156
- self.hinfo_records << record unless self.hinfo_records.include? record
200
+ self.hinfo_records << record.to_hash(zone) unless self.hinfo_records.include? record.to_hash(zone)
201
+ when "SPF"
202
+ self.spf_records << record.to_hash(zone) unless self.spf_records.include? record.to_hash(zone)
157
203
  else
158
204
  #nothing to do?
159
205
  end
@@ -169,11 +215,11 @@ module Probe
169
215
  packet = resolver.query(domain, type)
170
216
  return unless packet
171
217
 
172
- if packet.header.auth?
218
+ if packet.header.auth? || !packet.answer.empty?
173
219
  packet.answer.each &single_record_handler if packet.answer
174
220
  packet.authority.each &single_record_handler if packet.authority
175
221
  packet.additional.each &single_record_handler if packet.additional
176
- elsif packet.answer.empty? && !packet.authority.empty?
222
+ elsif !packet.authority.empty?
177
223
  #following down
178
224
  nameservers = Util.organize_authorities(packet.authority,packet.additional)
179
225
  #tail recursive
@@ -206,17 +252,8 @@ module Probe
206
252
  DomainProbe.collect_records domain
207
253
  end
208
254
 
209
- def collect_records_print_beautifully domain
210
- start = Time.now.to_i
211
- records = DomainProbe.collect_records(domain)
212
- finish = Time.now.to_i
213
- print "-----------------------","\n"
214
- records.each{ |record|
215
- print record, "\n"
216
- }
217
- print "-----------------------","\n"
218
- print "Time elapsed:\t",finish - start,"seconds. \n"
219
- nil
255
+ def collect_ns_records domain
256
+ DomainProbe.collect_ns_records domain
220
257
  end
221
258
 
222
259
  end
@@ -64,9 +64,6 @@ module Probe
64
64
 
65
65
  private
66
66
 
67
-
68
-
69
-
70
67
  #
71
68
  #iterate the elements to find a set of host names
72
69
  #
@@ -77,17 +74,19 @@ module Probe
77
74
 
78
75
  links.each { |link|
79
76
  next unless link[attribute]
80
- head = link[attribute].index("//")
77
+ attribute_value = link[attribute].downcase
78
+ head = attribute_value.index("//")
81
79
  next unless head
82
- tail = link[attribute].index(domain)
83
- next unless tail
80
+ tail = attribute_value.index(domain)
81
+ next unless tail && (tail > head)
84
82
 
85
83
  #slice the host in the url
86
84
  host = link[attribute].slice(head+DOUBLE_SLASH_LENGTH,tail-head-DOUBLE_SLASH_LENGTH)
87
85
 
88
- #remove the trailing dot if any
89
- host.slice!(host.length-1) if host.end_with? "."
90
- set.add host
86
+ next unless host.end_with? "."
87
+
88
+ host.chop!#remove the trailing dot if any
89
+ set.add host unless host.empty?
91
90
  }
92
91
 
93
92
  set
@@ -1,12 +1,93 @@
1
1
  require 'net/dns/resolver'
2
2
 
3
3
  #
4
- # Hack: the RR in net-dns didn't implement the ==,eql?,hash.methods
4
+ # Hack:
5
+ # 1.the RR in net-dns didn't implement the ==,eql?,hash.methods
6
+ # 2.Monkey-patch to support SPF records
5
7
  #
6
8
  module Net
7
9
  module DNS
8
10
  class RR
11
+
12
+ #
13
+ # removing trailing dot, if there is one
14
+ #
15
+ def remove_trailing_dot_if_any domain
16
+ return domain.chop if domain && domain.end_with?(".")
17
+ domain
18
+ end
19
+
20
+ def to_hash zone
21
+ cooked_value = name
22
+ if zone
23
+ zone << "." unless zone.end_with? "."
24
+ if name == zone
25
+ cooked_value = "@"
26
+ else
27
+ index = name.index(zone)
28
+ cooked_value = name[0,index - 1] if index && index > 0
29
+ end
30
+ end
31
+
32
+ {:name => cooked_value, :ttl => ttl}
33
+ end
34
+
35
+
36
+
37
+ class A
38
+ def to_hash zone
39
+ super(zone).merge({:address => address.to_s})
40
+ end
41
+ end
42
+
43
+ class CNAME
44
+ def to_hash zone
45
+ super(zone).merge({:cname => remove_trailing_dot_if_any(cname)})
46
+ end
47
+ end
48
+
49
+ class MX
50
+ def to_hash zone
51
+ super(zone).merge({:exchange => remove_trailing_dot_if_any(exchange),:preference => preference.to_s})
52
+ end
53
+ end
54
+
55
+ class MR
56
+ def to_hash zone
57
+ super(zone).merge({:newname => remove_trailing_dot_if_any(newname)})
58
+ end
59
+ end
60
+
61
+ class HINFO
62
+ def to_hash zone
63
+ super(zone).merge({:cpu => cpu,:os => os})
64
+ end
65
+ end
66
+
67
+ class SRV
68
+ def to_hash zone
69
+ super(zone)
70
+ end
71
+ end
72
+
73
+ class NS
74
+ def to_hash zone
75
+ super(zone).merge({:nsdname => remove_trailing_dot_if_any(nsdname)})
76
+ end
77
+ end
78
+
79
+ class AAAA
80
+ def to_hash zone
81
+ super(zone).merge({:address => address.to_s})
82
+ end
83
+ end
84
+
9
85
  class TXT
86
+
87
+ def to_hash zone
88
+ super(zone).merge({:value => txt})
89
+ end
90
+
10
91
  def value
11
92
  @txt.to_s
12
93
  end
@@ -29,6 +110,24 @@ module Net
29
110
  def hash
30
111
  self.data.hash
31
112
  end
113
+
114
+ class SPF < Net::DNS::RR::TXT
115
+
116
+ private
117
+ def set_type
118
+ @type = Net::DNS::RR::Types.new("SPF")
119
+ end
120
+ end
121
+
122
+ class Types
123
+ TYPES['SPF'] = 99
124
+ end
125
+
126
+ end
127
+
128
+ module QueryTypes
129
+ SPF = 99
32
130
  end
131
+
33
132
  end
34
133
  end
@@ -22,9 +22,9 @@ module Probe
22
22
  begin
23
23
  names.size.times { |index|
24
24
  resovler = Net::DNS::Resolver.new
25
- packet = resovler.query(domain, Net::DNS::NS)
25
+ packet = resovler.query(domain, Net::DNS::SOA)
26
26
  packet.answer.each { |record|
27
- next unless record.name == domain && record.type == "NS"
27
+ next unless record.name == domain && record.type == "SOA"
28
28
  zone = domain
29
29
  break
30
30
  } if packet && packet.answer
@@ -114,8 +114,8 @@ module Probe
114
114
  # removing trailing dot, if there is one
115
115
  #
116
116
  def self.remove_trailing_dot_if_any domain
117
- return domain unless !domain || domain.end_with?(".")
118
- domain.chop
117
+ return domain.chop if domain && domain.end_with?(".")
118
+ domain
119
119
  end
120
120
 
121
121
  #
@@ -1,4 +1,4 @@
1
1
  module Probe
2
- VERSION = "1.0.0"
2
+ VERSION = "1.2.0"
3
3
  end
4
4
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: domain-probe
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-21 00:00:00.000000000 Z
12
+ date: 2012-04-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &70294597444060 !ruby/object:Gem::Requirement
16
+ requirement: &70267579051820 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70294597444060
24
+ version_requirements: *70267579051820
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70294597442500 !ruby/object:Gem::Requirement
27
+ requirement: &70267579051020 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70294597442500
35
+ version_requirements: *70267579051020
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: net-dns
38
- requirement: &70294597440720 !ruby/object:Gem::Requirement
38
+ requirement: &70267579050440 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70294597440720
46
+ version_requirements: *70267579050440
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: nokogiri
49
- requirement: &70294597439640 !ruby/object:Gem::Requirement
49
+ requirement: &70267579049620 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70294597439640
57
+ version_requirements: *70267579049620
58
58
  description: A simple library to probe the dns records under specific domain, as many
59
59
  as possilbe
60
60
  email:
@@ -87,12 +87,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
87
87
  - - ! '>='
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
+ segments:
91
+ - 0
92
+ hash: 3749752069138402762
90
93
  required_rubygems_version: !ruby/object:Gem::Requirement
91
94
  none: false
92
95
  requirements:
93
96
  - - ! '>='
94
97
  - !ruby/object:Gem::Version
95
98
  version: '0'
99
+ segments:
100
+ - 0
101
+ hash: 3749752069138402762
96
102
  requirements: []
97
103
  rubyforge_project: domain-probe
98
104
  rubygems_version: 1.8.10