wlvalidate 0.1.6 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/wlvalidate.rb +163 -48
  2. metadata +20 -4
data/lib/wlvalidate.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  Results of the below calls will be returned in the following format
4
4
  (TYPE, RESULT, DATA and EXT_DATA are return values in each hash line)
5
5
  +=======+===========+===================+===========++========+=================+======================+
6
- [ TYPE | RESULT | DATA | EXT_DATA ][ Status | Return Type | Return on all paths? ]
6
+ [ CALL | RESULT | DATA | EXT_DATA ][ Status | Return Type | Return on all paths? ]
7
7
  +=======+===========+===================+===========++========+=================+======================+
8
8
  | A | PASS/FAIL | (none) | (none) || Done | Array of hashes | Yes |
9
9
  | SPF | PASS/FAIL | SPF record | Fail type || Done | Hash | Yes |
@@ -15,10 +15,6 @@
15
15
  | ALL | (multi) | (multi) | (multi) || Done | Array of hashes | (n/a) |
16
16
  +-------+-----------+-------------------+-----------++--------+-----------------+----------------------+
17
17
 
18
- TO DO:
19
- - Add master/slave DNS option
20
- - Validate hashes for Ruby
21
-
22
18
  =end
23
19
 
24
20
  # Must have dnsruby gem installed for this to work
@@ -27,15 +23,84 @@ include Dnsruby
27
23
 
28
24
  module WLValidate
29
25
  class Validate
30
- def initialize(attributes=nil)
31
- @intDNSTimeout = 5
32
- @intDNSIPLoops = 5
26
+ @@dns_updated = 0
27
+ @@dns_server = "8.8.8.8"
28
+ @@default_dns_server = "8.8.4.4"
29
+ @@dns_type = 1
30
+
31
+ def initialize( dns_server="8.8.4.4", dns_type=1 )
32
+ # PURPOSE: Executes code before anything else runs (hence Initialize)
33
+ # RETURNS: Not a darn thing...
34
+ # NOTES: We want to soak in parameters for DNS servers (array), DNS type (integer) and DNS timeouts (integer):
35
+ # Resulting global variables: @dns_servers, @dns_type, @dns_timeout
36
+ # If these values are not set during instancing, we want to put in some default values
37
+ #
38
+ # VARS: @dns_server: single string, non-array of IP address
39
+ # @dns_type: integer where 1 = local config, 2 = authorative server, 3 = Specific server
40
+
41
+ @dns_updated = 0
42
+ @dns_server = dns_server.to_s
43
+ @default_dns_server = "8.8.4.4"
44
+ @dns_type = dns_type.to_i
45
+
46
+ if (dns_type.to_i == 3)
47
+ if (dns_server)
48
+ @dns_server = dns_server
49
+ else
50
+ @dns_server = @default_dns_server
51
+ end
52
+ end
53
+ end
54
+
55
+ def get_info()
56
+ hashReturn = Hash.new
57
+ hashReturn = { "dns_server" => @dns_server, "dns_type" => @dns_type, "dns_timeout" => @dns_timeout, "dns_updated" => @dns_updated }
58
+ return hashReturn
33
59
  end
34
60
 
35
- def self.ALL(strWL, strDomain)
61
+ def set_auth_ns(strDomain)
62
+ # Since we can't get strDomain during __init__, we will check to see if @dns_type = 2 (auth) and if
63
+ # @dns_server is empty. If so, then we want to get the authorative NS and set it globally.
64
+ if ((@dns_updated == 0) && (@dns_type == 2))
65
+ iplist = []
66
+ begin
67
+ res = Dnsruby::Resolver.new
68
+
69
+ res.retry_times=(1)
70
+ ns_req = nil
71
+ ns_req = res.query(strDomain, 'NS')
72
+
73
+ res.recurse=(0)
74
+
75
+ (ns_req.answer.select {|r| r.type == 'NS'}).each do |nsrr|
76
+ ns = nsrr.domainname
77
+
78
+ local_res = Dnsruby::Resolver.new
79
+ a_req=nil
80
+ a_req = local_res.query(ns, 'A')
81
+
82
+ (a_req.answer.select {|r| r.type == 'A'}).each do |r|
83
+ ip = r.address
84
+ res.nameserver=(ip.to_s)
85
+ soa_req=nil
86
+ soa_req = res.query(strDomain, 'SOA', 'IN')
87
+ iplist.push(ip.to_s)
88
+ end
89
+ end
90
+ iplist.shuffle!
91
+ @dns_server = iplist.first
92
+ @dns_updated = 1
93
+ rescue
94
+ @dns_server = @default_dns_server
95
+ @dns_updated = 1
96
+ end
97
+ end
98
+ end
99
+
100
+ def ALL(strWL, strDomain)
36
101
  # PURPOSE: Execute all of the below methods as a single call
37
102
  # RETURNS: Returns the combined array of hashes as returned by each function
38
- # NOTES: Need to encapsulate all functions in a begin/capture/end to catch anything odd
103
+ # NOTES: All functions have values on all return paths, except for MX (see TODO above)
39
104
 
40
105
  arrayReturns = Array.new
41
106
 
@@ -45,6 +110,7 @@ module WLValidate
45
110
  hashDKIM1 = self.DKIM1(strWL, strDomain)
46
111
  hashDKIM2 = self.DKIM2(strWL, strDomain)
47
112
  arrayMX = self.MX(strWL, strDomain)
113
+ hashInfo = self.get_info()
48
114
 
49
115
  # array.push hashes, and array.concat arrays
50
116
  arrayReturns.push(hashSPF)
@@ -53,11 +119,12 @@ module WLValidate
53
119
  arrayReturns.push(hashDKIM1)
54
120
  arrayReturns.push(hashDKIM2)
55
121
  arrayReturns.concat(arrayMX)
122
+ arrayReturns.push(hashInfo)
56
123
 
57
124
  return arrayReturns
58
125
  end
59
126
 
60
- def self.MX(strWL, strDomain)
127
+ def MX(strWL, strDomain)
61
128
  # PURPOSE: Loop through all <domain> MX records
62
129
  # RETURNS: Array of hashes
63
130
  hashTemp = Hash.new
@@ -66,9 +133,16 @@ module WLValidate
66
133
 
67
134
  if ((strWL == "") || (strDomain == ""))
68
135
  hashReturn = { "type" => "MX", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more parameters are missing!" }
136
+ arrayReturn.push(hashReturn)
137
+ end
138
+
139
+ set_auth_ns(strDomain)
140
+
141
+ if ((@dns_type == 2) || (@dns_type == 3))
142
+ dns_params = {:nameserver=>@dns_server}
69
143
  end
70
144
 
71
- Dnsruby::DNS.open {|dns|
145
+ Dnsruby::DNS.open(dns_params) {|dns|
72
146
  begin
73
147
  arrayMX = dns.getresources(strDomain, Dnsruby::Types.MX)
74
148
  if (arrayMX.count > 0)
@@ -76,7 +150,11 @@ module WLValidate
76
150
  arrayMX.each do |r|
77
151
  myExchange = r.exchange.to_s
78
152
  myPreference = r.preference.to_s
79
- hashTemp = { "type" => "MX", "result" => "INFO", "data" => myExchange, "ext_data" => myPreference }
153
+ if myExchange.match %r{sendgrid.}
154
+ hashTemp = { "type" => "MX", "result" => "ERROR", "data" => myExchange, "ext_data" => "SendGrid is listed as handling incoming email on the root domain - this is generally a bad idea unless you're using ParseAPI..." }
155
+ else
156
+ hashTemp = { "type" => "MX", "result" => "INFO", "data" => myExchange, "ext_data" => myPreference }
157
+ end
80
158
  arrayReturn.push(hashTemp)
81
159
  hashTemp = {}
82
160
  end
@@ -99,7 +177,7 @@ module WLValidate
99
177
  return arrayReturn
100
178
  end
101
179
 
102
- def self.A(strWL, strDomain)
180
+ def A(strWL, strDomain)
103
181
  # PURPOSE: Loop through all oN.<wl>.<domain>.<tlds> to get IPs, then also do reverse DNS checks
104
182
  # RETURNS: Hash - see above for definition
105
183
 
@@ -108,8 +186,11 @@ module WLValidate
108
186
 
109
187
  if ((strWL == "") || (strDomain == ""))
110
188
  hashReturn = { "type" => "A", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
189
+ arrayReturn.push(hashReturn)
111
190
  end
112
191
 
192
+ set_auth_ns(strDomain)
193
+
113
194
  i = 1
114
195
  intDNSIPLoops = 11
115
196
  while i < intDNSIPLoops do
@@ -142,7 +223,7 @@ module WLValidate
142
223
  return arrayReturn
143
224
  end
144
225
 
145
- def self.CNAME(strWL, strDomain)
226
+ def CNAME(strWL, strDomain)
146
227
  # PURPOSE: Get CNAME record and make sure it's mapped to 'sendgrid.net'
147
228
  # RETURNS: Hash - See above for definition
148
229
 
@@ -153,7 +234,13 @@ module WLValidate
153
234
  hashReturn = { "type" => "CNAME", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
154
235
  end
155
236
 
156
- Dnsruby::DNS.open {|dns|
237
+ set_auth_ns(strDomain)
238
+
239
+ if ((@dns_type == 2) || (@dns_type == 3))
240
+ dns_params = {:nameserver=>@dns_server}
241
+ end
242
+
243
+ Dnsruby::DNS.open(dns_params) {|dns|
157
244
  begin
158
245
  strHost = strWL + "." + strDomain
159
246
  arrayCNAME = dns.getresources(strHost, Dnsruby::Types.CNAME)
@@ -166,9 +253,12 @@ module WLValidate
166
253
  end
167
254
  end
168
255
  if hashReturn.empty?
169
- hashReturn = { "type" => "CNAME", "result" => "FAIL", "data" => "No data", "ext_data" => "No matching CNAME records found" }
256
+ hashReturn = { "type" => "CNAME", "result" => "FAIL", "data" => strHost, "ext_data" => "No matching CNAME records found" }
170
257
  end
171
258
  end
259
+ if boolFoundMatch == false
260
+ hashReturn = { "type" => "CNAME", "result" => "FAIL", "data" => strHost, "ext_data" => "No matching CNAME records found" }
261
+ end
172
262
  rescue Dnsruby::ResolvTimeout
173
263
  hashReturn = { "type" => "CNAME", "result" => "ERROR", "data" => strHost, "ext_data" => "Timed out while attempting rDNS lookup" }
174
264
  rescue
@@ -178,7 +268,7 @@ module WLValidate
178
268
  return hashReturn
179
269
  end
180
270
 
181
- def self.DKIM1(strWL, strDomain)
271
+ def DKIM1(strWL, strDomain)
182
272
  # PURPOSE: Get TXT/CNAME record for smtpapi._domainkey.<domain>.<tlds>
183
273
  # RETURNS: Hash - See above for definition
184
274
 
@@ -186,32 +276,41 @@ module WLValidate
186
276
  boolFoundMatch = false
187
277
  strHost = "smtpapi._domainkey." + strDomain
188
278
  strDKIM = "k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPtW5iwpXVPiH5FzJ7Nrl8USzuY9zqqzjE0D1r04xDN6qwziDnmgcFNNfMewVKN2D1O+2J9N14hRprzByFwfQW76yojh54Xu3uSbQ3JP0A7k8o8GutRF8zbFUA8n0ZH2y0cIEjMliXY4W4LwPA7m4q0ObmvSjhd63O9d8z1XkUBwIDAQAB"
189
- strDKIM_k = "rsa"
190
- strDKIM_t = "s"
191
- strDKIM_p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPtW5iwpXVPiH5FzJ7Nrl8USzuY9zqqzjE0D1r04xDN6qwziDnmgcFNNfMewVKN2D1O+2J9N14hRprzByFwfQW76yojh54Xu3uSbQ3JP0A7k8o8GutRF8zbFUA8n0ZH2y0cIEjMliXY4W4LwPA7m4q0ObmvSjhd63O9d8z1XkUBwIDAQAB"
192
279
 
193
280
  if ((strWL == "") || (strDomain == ""))
194
281
  hashReturn = { "type" => "DKIM1", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
195
282
  end
196
283
 
197
- Dnsruby::DNS.open {|dns|
284
+ set_auth_ns(strDomain)
285
+
286
+ if ((@dns_type == 2) || (@dns_type == 3))
287
+ dns_params = {:nameserver=>@dns_server}
288
+ end
289
+
290
+ Dnsruby::DNS.open(dns_params) {|dns|
198
291
  begin
199
292
  arrayDKIM1 = dns.getresources(strHost, Dnsruby::Types.TXT)
200
293
  arrayDKIM1.each do |r|
201
- if boolFoundMatch == false
202
- if (r.name.to_s == "dkim.sendgrid.net")
203
- hashReturn = { "type" => "DKIM1", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "cname" }
204
- boolFoundMatch = true
205
- elsif ( (r.name.to_s == strHost) && (r.data.split(" ")[0].match %r{#{Regexp.escape(strDKIM_k)}}) && (r.data.split(" ")[1].match %r{#{Regexp.escape(strDKIM_t)}}) && (r.data.split(" ")[2].match %r{#{Regexp.escape(strDKIM_p)}}) )
206
- hashReturn = { "type" => "DKIM1", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "txt" }
294
+ if r.name.to_s.match %r{dkim.sendgrid.net}
295
+ hashReturn = { "type" => "DKIM1", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "CNAME" }
296
+ boolFoundMatch = true
297
+ end
298
+ if ((r.name.to_s == strHost) && (r.data == strDKIM))
299
+ hashReturn = { "type" => "DKIM1", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "TXT" }
300
+ boolFoundMatch = true
301
+ end
302
+ end
303
+ if ((boolFoundMatch == false) || (hashReturn.empty?))
304
+ arrayDKIM1CNAME = dns.getresources(strHost, Dnsruby::Types.CNAME)
305
+ arrayDKIM1CNAME.each do |c|
306
+ if c.rdata_to_string.match %r{dkim.sendgrid.net}
307
+ hashReturn = { "type" => "DKIM1", "result" => "PASS", "data" => c.name.to_s, "ext_data" => "CNAME" }
207
308
  boolFoundMatch = true
208
- else
209
- hashReturn = { "type" => "DKIM1", "result" => "FAIL", "data" => strHost, "ext_data" => "No DKIM record found as either CNAME or TXT" }
210
309
  end
211
310
  end
212
311
  end
213
- if hashReturn.empty?
214
- hashReturn = { "type" => "DKIM2", "result" => "FAIL", "data" => strHost, "ext_data" => "No matching DKIM/TXT records found" }
312
+ if ((boolFoundMatch == false) || (hashReturn.empty?))
313
+ hashReturn = { "type" => "DKIM1", "result" => "FAIL", "data" => strHost, "ext_data" => "No matching DKIM/TXT records found" }
215
314
  end
216
315
  rescue
217
316
  hashReturn = { "type" => "DKIM1", "result" => "ERROR", "data" => strHost, "ext_data" => "Unable to resolve host, or query timed out" }
@@ -220,7 +319,7 @@ module WLValidate
220
319
  return hashReturn
221
320
  end
222
321
 
223
- def self.DKIM2(strWL, strDomain)
322
+ def DKIM2(strWL, strDomain)
224
323
  # PURPOSE: Get TXT/CNAME record for smtpapi._domainkey.<wl>.<domain>.<tlds>
225
324
  # RETURNS: Hash - See above for definition
226
325
 
@@ -228,31 +327,41 @@ module WLValidate
228
327
  boolFoundMatch = false
229
328
  strHost = "smtpapi._domainkey." + strWL + "." + strDomain
230
329
  strDKIM = "k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPtW5iwpXVPiH5FzJ7Nrl8USzuY9zqqzjE0D1r04xDN6qwziDnmgcFNNfMewVKN2D1O+2J9N14hRprzByFwfQW76yojh54Xu3uSbQ3JP0A7k8o8GutRF8zbFUA8n0ZH2y0cIEjMliXY4W4LwPA7m4q0ObmvSjhd63O9d8z1XkUBwIDAQAB"
231
- strDKIM_k = "rsa"
232
- strDKIM_t = "s"
233
- strDKIM_p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPtW5iwpXVPiH5FzJ7Nrl8USzuY9zqqzjE0D1r04xDN6qwziDnmgcFNNfMewVKN2D1O+2J9N14hRprzByFwfQW76yojh54Xu3uSbQ3JP0A7k8o8GutRF8zbFUA8n0ZH2y0cIEjMliXY4W4LwPA7m4q0ObmvSjhd63O9d8z1XkUBwIDAQAB"
234
330
 
235
331
  if ((strWL == "") || (strDomain == ""))
236
332
  hashReturn = { "type" => "DKIM2", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
237
333
  end
238
334
 
239
- Dnsruby::DNS.open {|dns|
335
+ set_auth_ns(strDomain)
336
+
337
+ if ((@dns_type == 2) || (@dns_type == 3))
338
+ dns_params = {:nameserver=>@dns_server}
339
+ end
340
+
341
+ Dnsruby::DNS.open(dns_params) {|dns|
240
342
  begin
241
343
  arrayDKIM2 = dns.getresources(strHost, Dnsruby::Types.TXT)
242
344
  arrayDKIM2.each do |r|
243
- if boolFoundMatch == false
244
- if (r.name.to_s == "dkim.sendgrid.net")
245
- hashReturn = { "type" => "DKIM2", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "cname" }
246
- boolFoundMatch = true
247
- elsif ( (r.name.to_s == strHost) && (r.data.split(" ")[0].match %r{#{Regexp.escape(strDKIM_k)}}) && (r.data.split(" ")[1].match %r{#{Regexp.escape(strDKIM_t)}}) && (r.data.split(" ")[2].match %r{#{Regexp.escape(strDKIM_p)}}) )
248
- hashReturn = { "type" => "DKIM2", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "txt" }
345
+ if r.name.to_s.match %r{dkim.sendgrid.net}
346
+ hashReturn = { "type" => "DKIM2", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "CNAME" }
347
+ boolFoundMatch = true
348
+ end
349
+ if ((r.name.to_s == strHost) && (r.data == strDKIM))
350
+ hashReturn = { "type" => "DKIM2", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "TXT" }
351
+ boolFoundMatch = true
352
+ end
353
+ end
354
+
355
+ if ((boolFoundMatch == false) || (hashReturn.empty?))
356
+ arrayDKIM2CNAME = dns.getresources(strHost, Dnsruby::Types.CNAME)
357
+ arrayDKIM2CNAME.each do |c|
358
+ if c.rdata_to_string.match %r{dkim.sendgrid.net}
359
+ hashReturn = { "type" => "DKIM2", "result" => "PASS", "data" => c.name.to_s, "ext_data" => "CNAME" }
249
360
  boolFoundMatch = true
250
- else
251
- hashReturn = { "type" => "DKIM2", "result" => "FAIL", "data" => strHost, "ext_data" => "No DKIM record found as either CNAME or TXT" }
252
361
  end
253
362
  end
254
363
  end
255
- if hashReturn.empty?
364
+ if ((boolFoundMatch == false) || (hashReturn.empty?))
256
365
  hashReturn = { "type" => "DKIM2", "result" => "FAIL", "data" => strHost, "ext_data" => "No matching DKIM/TXT records found" }
257
366
  end
258
367
  rescue
@@ -262,7 +371,7 @@ module WLValidate
262
371
  return hashReturn
263
372
  end
264
373
 
265
- def self.SPF(strWL, strDomain)
374
+ def SPF(strWL, strDomain)
266
375
  # PURPOSE: Get TXT record and make sure it has include:sendgrid.net
267
376
  # RETURNS: Hash - See above for definition
268
377
 
@@ -273,7 +382,13 @@ module WLValidate
273
382
  hashReturn = { "type" => "SPF", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
274
383
  end
275
384
 
276
- Dnsruby::DNS.open {|dns|
385
+ set_auth_ns(strDomain)
386
+
387
+ if ((@dns_type == 2) || (@dns_type == 3))
388
+ dns_params = {:nameserver=>@dns_server}
389
+ end
390
+
391
+ Dnsruby::DNS.open(dns_params) {|dns|
277
392
  begin
278
393
  arrayTXT = dns.getresources(strDomain, Dnsruby::Types.TXT)
279
394
  if arrayTXT.to_s != "[]"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wlvalidate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-08 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2013-02-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: dnsruby
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
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: '0'
14
30
  description: SendGrid Rails Gem to validate White Label settings
15
31
  email: jayson.sperling@sendgrid.com
16
32
  executables: []
@@ -38,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
38
54
  version: '0'
39
55
  requirements: []
40
56
  rubyforge_project:
41
- rubygems_version: 1.8.23
57
+ rubygems_version: 1.8.24
42
58
  signing_key:
43
59
  specification_version: 3
44
60
  summary: SendGrid White Label Validator