wlvalidate 0.1.6 → 0.3.2

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.
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