wlvalidate 0.1.5

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 +316 -0
  2. metadata +45 -0
data/lib/wlvalidate.rb ADDED
@@ -0,0 +1,316 @@
1
+ =begin
2
+
3
+ Results of the below calls will be returned in the following format
4
+ (TYPE, RESULT, DATA and EXT_DATA are return values in each hash line)
5
+ +=======+===========+===================+===========++========+=================+======================+
6
+ [ TYPE | RESULT | DATA | EXT_DATA ][ Status | Return Type | Return on all paths? ]
7
+ +=======+===========+===================+===========++========+=================+======================+
8
+ | A | PASS/FAIL | (none) | (none) || Done | Array of hashes | Yes |
9
+ | SPF | PASS/FAIL | SPF record | Fail type || Done | Hash | Yes |
10
+ | CNAME | PASS/FAIL | CNAME | (none) || Done | Hash | Yes |
11
+ | DKIM1 | PASS/FAIL | (none) | CNAME/TXT || Done | Hash | Yes |
12
+ | DKIM2 | PASS/FAIL | (none) | CNAME/TXT || Done | Hash | Yes |
13
+ | MX | INFO | MX Hostname | Priority || Done | Array of hashes | |
14
+ +-------+-----------+-------------------+-----------++--------+-----------------+----------------------+
15
+ | ALL | (multi) | (multi) | (multi) || Done | Array of hashes | (n/a) |
16
+ +-------+-----------+-------------------+-----------++--------+-----------------+----------------------+
17
+
18
+ TO DO:
19
+ - Add master/slave DNS option
20
+ - Validate hashes for Ruby
21
+
22
+ =end
23
+
24
+ # Must have dnsruby gem installed for this to work
25
+ require 'dnsruby'
26
+ include Dnsruby
27
+
28
+ module WLValidate
29
+ class Validate
30
+ def initialize(attributes=nil)
31
+ @intDNSTimeout = 5
32
+ @intDNSIPLoops = 5
33
+ end
34
+
35
+ def self.ALL(strWL, strDomain)
36
+ # PURPOSE: Execute all of the below methods as a single call
37
+ # 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
39
+
40
+ arrayReturns = Array.new
41
+
42
+ hashSPF = self.SPF(strWL, strDomain)
43
+ hashCNAME = self.CNAME(strWL, strDomain)
44
+ hashA = self.A(strWL, strDomain)
45
+ hashDKIM1 = self.DKIM1(strWL, strDomain)
46
+ hashDKIM2 = self.DKIM2(strWL, strDomain)
47
+ arrayMX = self.MX(strWL, strDomain)
48
+
49
+ # array.push hashes, and array.concat arrays
50
+ arrayReturns.push(hashSPF)
51
+ arrayReturns.push(hashCNAME)
52
+ arrayReturns.concat(hashA)
53
+ arrayReturns.push(hashDKIM1)
54
+ arrayReturns.push(hashDKIM2)
55
+ arrayReturns.concat(arrayMX)
56
+
57
+ return arrayReturns
58
+ end
59
+
60
+ def self.MX(strWL, strDomain)
61
+ # PURPOSE: Loop through all <domain> MX records
62
+ # RETURNS: Array of hashes
63
+ hashTemp = Hash.new
64
+ arrayReturn = Array.new
65
+ arrayMX = Array.new
66
+
67
+ if ((strWL == "") || (strDomain == ""))
68
+ hashReturn = { "type" => "MX", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more parameters are missing!" }
69
+ end
70
+
71
+ Dnsruby::DNS.open {|dns|
72
+ begin
73
+ arrayMX = dns.getresources(strDomain, Dnsruby::Types.MX)
74
+ if (arrayMX.count > 0)
75
+ arrayMX.sort!
76
+ arrayMX.each do |r|
77
+ myExchange = r.exchange.to_s
78
+ myPreference = r.preference.to_s
79
+ hashTemp = { "type" => "MX", "result" => "INFO", "data" => myExchange, "ext_data" => myPreference }
80
+ arrayReturn.push(hashTemp)
81
+ hashTemp = {}
82
+ end
83
+ else
84
+ hashTemp = { "type" => "MX", "result" => "FAIL", "data" => "No records", "ext_data" => "No MX records exist for this domain" }
85
+ arrayReturn.push(hashTemp)
86
+ hashTemp = {}
87
+ end
88
+ rescue
89
+ hashTemp = { "type" => "MX", "result" => "ERROR", "data" => "Unable to resolve", "ext_data" => "Unable to resolve MX records for domain " + strDomain }
90
+ arrayReturn.push(hashTemp)
91
+ hashTemp = {}
92
+ end
93
+ }
94
+ if arrayReturn.empty?
95
+ hashReturn = { "type" => "MX", "result" => "FAIL", "data" => "No data", "ext_data" => "No MX records in domain" }
96
+ arrayReturn.push(hashReturn)
97
+ hashReturn = {}
98
+ end
99
+ return arrayReturn
100
+ end
101
+
102
+ def self.A(strWL, strDomain)
103
+ # PURPOSE: Loop through all oN.<wl>.<domain>.<tlds> to get IPs, then also do reverse DNS checks
104
+ # RETURNS: Hash - see above for definition
105
+
106
+ hashReturn = Hash.new
107
+ arrayReturn = Array.new
108
+
109
+ if ((strWL == "") || (strDomain == ""))
110
+ hashReturn = { "type" => "A", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
111
+ end
112
+
113
+ i = 1
114
+ intDNSIPLoops = 11
115
+ while i < intDNSIPLoops do
116
+ begin
117
+ tmpHost = "o" + i.to_s + "." + strWL + "." + strDomain
118
+ tmpIP = Dnsruby::Resolv.getaddress(tmpHost)
119
+ resolvedHost = Dnsruby::Resolv.getname(tmpIP)
120
+ if tmpHost == resolvedHost
121
+ hashReturn = { "type" => "A", "result" => "PASS", "data" => tmpHost, "ext_data" => tmpIP }
122
+ arrayReturn.push(hashReturn)
123
+ hashReturn = {}
124
+ end
125
+ rescue Dnsruby::ResolvTimeout
126
+ hashReturn = { "type" => "A", "result" => "ERROR", "data" => tmpHost, "ext_data" => "Timed out while attempting rDNS lookup" }
127
+ arrayReturn.push(hashReturn)
128
+ hashReturn = {}
129
+ rescue
130
+ #hashReturn = { "type" => "A", "result" => "ERROR", "data" => tmpHost, "ext_data" => "Unable to resolve rDNS for host" }
131
+ #arrayReturn.push(hashReturn)
132
+ #hashReturn = {}
133
+ end
134
+ i += 1
135
+ end
136
+ if arrayReturn.empty?
137
+ hashReturn = { "type" => "A", "result" => "FAIL", "data" => "No data", "ext_data" => "No SendGrid IPs" }
138
+ arrayReturn.push(hashReturn)
139
+ hashReturn = {}
140
+ end
141
+
142
+ return arrayReturn
143
+ end
144
+
145
+ def self.CNAME(strWL, strDomain)
146
+ # PURPOSE: Get CNAME record and make sure it's mapped to 'sendgrid.net'
147
+ # RETURNS: Hash - See above for definition
148
+
149
+ hashReturn = Hash.new
150
+ boolFoundMatch = false
151
+
152
+ if ((strWL == "") || (strDomain == ""))
153
+ hashReturn = { "type" => "CNAME", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
154
+ end
155
+
156
+ Dnsruby::DNS.open {|dns|
157
+ begin
158
+ strHost = strWL + "." + strDomain
159
+ arrayCNAME = dns.getresources(strHost, Dnsruby::Types.CNAME)
160
+ arrayCNAME.each do |r|
161
+ if boolFoundMatch == false
162
+ tmpCNAME = r.domainname.to_s
163
+ if tmpCNAME.match %r{sendgrid.net}
164
+ hashReturn = { "type" => "CNAME", "result" => "PASS", "data" => strHost, "ext_data" => tmpCNAME }
165
+ boolFoundMatch = true
166
+ end
167
+ end
168
+ if hashReturn.empty?
169
+ hashReturn = { "type" => "CNAME", "result" => "FAIL", "data" => "No data", "ext_data" => "No matching CNAME records found" }
170
+ end
171
+ end
172
+ rescue Dnsruby::ResolvTimeout
173
+ hashReturn = { "type" => "CNAME", "result" => "ERROR", "data" => strHost, "ext_data" => "Timed out while attempting rDNS lookup" }
174
+ rescue
175
+ hashReturn = { "type" => "CNAME", "result" => "ERROR", "data" => strHost, "ext_data" => "Unable to resolve host, or query timed out" }
176
+ end
177
+ }
178
+ return hashReturn
179
+ end
180
+
181
+ def self.DKIM1(strWL, strDomain)
182
+ # PURPOSE: Get TXT/CNAME record for smtpapi._domainkey.<domain>.<tlds>
183
+ # RETURNS: Hash - See above for definition
184
+
185
+ hashReturn = Hash.new
186
+ boolFoundMatch = false
187
+ strHost = "smtpapi._domainkey." + strDomain
188
+ strDKIM = "k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPtW5iwpXVPiH5FzJ7Nrl8USzuY9zqqzjE0D1r04xDN6qwziDnmgcFNNfMewVKN2D1O+2J9N14hRprzByFwfQW76yojh54Xu3uSbQ3JP0A7k8o8GutRF8zbFUA8n0ZH2y0cIEjMliXY4W4LwPA7m4q0ObmvSjhd63O9d8z1XkUBwIDAQAB"
189
+ strDKIM_k = "rsa"
190
+ strDKIM_t = "s"
191
+ strDKIM_p = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPtW5iwpXVPiH5FzJ7Nrl8USzuY9zqqzjE0D1r04xDN6qwziDnmgcFNNfMewVKN2D1O+2J9N14hRprzByFwfQW76yojh54Xu3uSbQ3JP0A7k8o8GutRF8zbFUA8n0ZH2y0cIEjMliXY4W4LwPA7m4q0ObmvSjhd63O9d8z1XkUBwIDAQAB"
192
+
193
+ if ((strWL == "") || (strDomain == ""))
194
+ hashReturn = { "type" => "DKIM1", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
195
+ end
196
+
197
+ Dnsruby::DNS.open {|dns|
198
+ begin
199
+ arrayDKIM1 = dns.getresources(strHost, Dnsruby::Types.TXT)
200
+ arrayDKIM1.each do |r|
201
+ if boolFoundMatch == false
202
+ puts "DKIM data: #{r.data}"
203
+ r.data.split(" ").each {|k|
204
+ puts "#{k}"
205
+ }
206
+ puts "r.name.to_s => #{r.name.to_s}"
207
+ if (r.name.to_s == "dkim.sendgrid.net")
208
+ hashReturn = { "type" => "DKIM1", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "cname" }
209
+ boolFoundMatch = true
210
+ 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)}}) )
211
+ hashReturn = { "type" => "DKIM1", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "txt" }
212
+ boolFoundMatch = true
213
+ else
214
+ hashReturn = { "type" => "DKIM1", "result" => "FAIL", "data" => strHost, "ext_data" => "No DKIM record found as either CNAME or TXT" }
215
+ end
216
+ end
217
+ end
218
+ if hashReturn.empty?
219
+ hashReturn = { "type" => "DKIM2", "result" => "FAIL", "data" => strHost, "ext_data" => "No matching DKIM/TXT records found" }
220
+ end
221
+ rescue
222
+ hashReturn = { "type" => "DKIM1", "result" => "ERROR", "data" => strHost, "ext_data" => "Unable to resolve host, or query timed out" }
223
+ end
224
+ }
225
+ return hashReturn
226
+ end
227
+
228
+ def self.DKIM2(strWL, strDomain)
229
+ # PURPOSE: Get TXT/CNAME record for smtpapi._domainkey.<wl>.<domain>.<tlds>
230
+ # RETURNS: Hash - See above for definition
231
+
232
+ hashReturn = Hash.new
233
+ boolFoundMatch = false
234
+ strHost = "smtpapi._domainkey." + strWL + "." + strDomain
235
+ strDKIM = "k=rsa; t=s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPtW5iwpXVPiH5FzJ7Nrl8USzuY9zqqzjE0D1r04xDN6qwziDnmgcFNNfMewVKN2D1O+2J9N14hRprzByFwfQW76yojh54Xu3uSbQ3JP0A7k8o8GutRF8zbFUA8n0ZH2y0cIEjMliXY4W4LwPA7m4q0ObmvSjhd63O9d8z1XkUBwIDAQAB"
236
+
237
+ if ((strWL == "") || (strDomain == ""))
238
+ hashReturn = { "type" => "DKIM2", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
239
+ end
240
+
241
+ Dnsruby::DNS.open {|dns|
242
+ begin
243
+ arrayDKIM2 = dns.getresources(strHost, Dnsruby::Types.TXT)
244
+ arrayDKIM2.each do |r|
245
+ if boolFoundMatch == false
246
+ if (r.name.to_s == "dkim.sendgrid.net")
247
+ hashReturn = { "type" => "DKIM2", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "cname" }
248
+ boolFoundMatch = true
249
+ elsif ((r.name.to_s == strHost) && (r.data == strDKIM))
250
+ hashReturn = { "type" => "DKIM2", "result" => "PASS", "data" => r.name.to_s, "ext_data" => "txt" }
251
+ boolFoundMatch = true
252
+ else
253
+ hashReturn = { "type" => "DKIM2", "result" => "FAIL", "data" => strHost, "ext_data" => "No DKIM record found as either CNAME or TXT" }
254
+ end
255
+ end
256
+ end
257
+ if hashReturn.empty?
258
+ hashReturn = { "type" => "DKIM2", "result" => "FAIL", "data" => strHost, "ext_data" => "No matching DKIM/TXT records found" }
259
+ end
260
+ rescue
261
+ hashReturn = { "type" => "DKIM2", "result" => "ERROR", "data" => strHost, "ext_data" => "Unable to resolve host, or query timed out" }
262
+ end
263
+ }
264
+ return hashReturn
265
+ end
266
+
267
+ def self.SPF(strWL, strDomain)
268
+ # PURPOSE: Get TXT record and make sure it has include:sendgrid.net
269
+ # RETURNS: Hash - See above for definition
270
+
271
+ hashReturn = Hash.new
272
+ boolFoundMatch = false
273
+
274
+ if ((strWL == "") || (strDomain == ""))
275
+ hashReturn = { "type" => "SPF", "result" => "ERROR", "data" => "Missing parameters", "ext_data" => "One or more expected paramters are missing!" }
276
+ end
277
+
278
+ Dnsruby::DNS.open {|dns|
279
+ begin
280
+ arrayTXT = dns.getresources(strDomain, Dnsruby::Types.TXT)
281
+ if arrayTXT.to_s != "[]"
282
+ arrayTXT.each do |r|
283
+ if boolFoundMatch == false
284
+ rTXT = r.strings.to_s
285
+ if ((rTXT.match('v=spf1')) && (rTXT.match('include:sendgrid.net')))
286
+ if rTXT.match %r{~al}
287
+ hashReturn = { "type" => "SPF", "result" => "PASS", "data" => rTXT, "ext_data" => "softfail" }
288
+ elsif rTXT.match %r{-al}
289
+ hashReturn = { "type" => "SPF", "result" => "PASS", "data" => rTXT, "ext_data" => "fail" }
290
+ elsif rTXT =~/^+al/
291
+ hashReturn = { "type" => "SPF", "result" => "PASS", "data" => rTXT, "ext_data" => "pass" }
292
+ elsif rTXT.match %r{\?al}
293
+ hashReturn = { "type" => "SPF", "result" => "PASS", "data" => rTXT, "ext_data" => "neutral" }
294
+ else
295
+ hashReturn = { "type" => "SPF", "result" => "PASS", "data" => rTXT, "ext_data" => "" }
296
+ end
297
+ boolFoundMatch = true
298
+ else
299
+ hashReturn = { "type" => "SPF", "result" => "FAIL", "data" => "No record", "ext_data" => "The requested SPF record was not found" }
300
+ end
301
+ end
302
+ end
303
+ if hashReturn.empty?
304
+ hashReturn = { "type" => "SPF", "result" => "FAIL", "data" => "No record", "ext_data" => "No matching DKIM/TXT records found" }
305
+ end
306
+ else
307
+ hashReturn = { "type" => "SPF", "result" => "FAIL", "data" => "No record", "ext_data" => "No TXT records found for domain" }
308
+ end
309
+ rescue
310
+ hashReturn = { "type" => "SPF", "result" => "ERROR", "data" => "No record", "ext_data" => "The requested SPF record was not found" }
311
+ end
312
+ }
313
+ return hashReturn
314
+ end
315
+ end
316
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wlvalidate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jayson M. Sperling
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-08 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: SendGrid Rails Gem to validate White Label settings
15
+ email: jayson.sperling@sendgrid.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/wlvalidate.rb
21
+ homepage: http://dev.tluw.net/sg/wlvalidate
22
+ licenses: []
23
+ post_install_message:
24
+ rdoc_options: []
25
+ require_paths:
26
+ - lib
27
+ required_ruby_version: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ requirements: []
40
+ rubyforge_project:
41
+ rubygems_version: 1.8.23
42
+ signing_key:
43
+ specification_version: 3
44
+ summary: SendGrid White Label Validator
45
+ test_files: []