spf-query 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +57 -0
- data/.rspec +1 -0
- data/.travis.yml +18 -0
- data/ChangeLog.md +6 -0
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.md +75 -0
- data/Rakefile +23 -0
- data/bin/spf-query +28 -0
- data/lib/resolv/dns/resource/in/spf.rb +9 -0
- data/lib/spf/query.rb +3 -0
- data/lib/spf/query/exceptions.rb +8 -0
- data/lib/spf/query/ip.rb +22 -0
- data/lib/spf/query/macro.rb +28 -0
- data/lib/spf/query/macro_string.rb +25 -0
- data/lib/spf/query/mechanism.rb +52 -0
- data/lib/spf/query/modifier.rb +24 -0
- data/lib/spf/query/parser.rb +281 -0
- data/lib/spf/query/query.rb +48 -0
- data/lib/spf/query/record.rb +204 -0
- data/lib/spf/query/version.rb +5 -0
- data/spec/mechanism_spec.rb +65 -0
- data/spec/parser_spec.rb +608 -0
- data/spec/query_spec.rb +38 -0
- data/spec/record_spec.rb +212 -0
- data/spec/spec_helper.rb +9 -0
- data/spf-query.gemspec +26 -0
- metadata +120 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a959789345d1c370b28b097cec96f35fc7507a44
|
4
|
+
data.tar.gz: 80505a4705b60f9baea7ed1c53c19b0527864e35
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fcf7ff0d96a794fbd894a5a2624ff3e30ed8c777f7deb1c7ee8e3d24c51e1df3b0a08c2f362c3eab1ce9ed38ba41af51d478bbd4e888c1534341705e85987615
|
7
|
+
data.tar.gz: d6c48a1958219e3c735b476884612017745a50a12492035fe91ee636b9f7d0b9442e695dfc2a39069ae21f8f0dbeb2abe66b0ffbf2eba9d34f719c62820848bc
|
data/.gitignore
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
<<<<<<< HEAD
|
2
|
+
<<<<<<< HEAD
|
3
|
+
/.bundle/
|
4
|
+
/.yardoc
|
5
|
+
/Gemfile.lock
|
6
|
+
/_yardoc/
|
7
|
+
/coverage/
|
8
|
+
/doc/
|
9
|
+
/pkg/
|
10
|
+
/spec/reports/
|
11
|
+
/tmp/
|
12
|
+
*.bundle
|
13
|
+
*.so
|
14
|
+
*.o
|
15
|
+
*.a
|
16
|
+
mkmf.log
|
17
|
+
=======
|
18
|
+
=======
|
19
|
+
>>>>>>> fed1141939dbe709d44dedb0247d31908300c31f
|
20
|
+
*.gem
|
21
|
+
*.rbc
|
22
|
+
/.config
|
23
|
+
/coverage/
|
24
|
+
/InstalledFiles
|
25
|
+
/pkg/
|
26
|
+
/spec/reports/
|
27
|
+
/test/tmp/
|
28
|
+
/test/version_tmp/
|
29
|
+
/tmp/
|
30
|
+
|
31
|
+
## Specific to RubyMotion:
|
32
|
+
.dat*
|
33
|
+
.repl_history
|
34
|
+
build/
|
35
|
+
|
36
|
+
## Documentation cache and generated files:
|
37
|
+
/.yardoc/
|
38
|
+
/_yardoc/
|
39
|
+
/doc/
|
40
|
+
/rdoc/
|
41
|
+
|
42
|
+
## Environment normalisation:
|
43
|
+
/.bundle/
|
44
|
+
/lib/bundler/man/
|
45
|
+
|
46
|
+
# for a library or gem, you might want to ignore these files since the code is
|
47
|
+
# intended to run in multiple environments; otherwise, check them in:
|
48
|
+
# Gemfile.lock
|
49
|
+
# .ruby-version
|
50
|
+
# .ruby-gemset
|
51
|
+
|
52
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
53
|
+
.rvmrc
|
54
|
+
<<<<<<< HEAD
|
55
|
+
>>>>>>> 62c17ee30b1a7d25ef12fab39fd6c2de0bcbadbc
|
56
|
+
=======
|
57
|
+
>>>>>>> fed1141939dbe709d44dedb0247d31908300c31f
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.travis.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0
|
5
|
+
- 2.1
|
6
|
+
- ruby-head
|
7
|
+
- jruby-19mode
|
8
|
+
- jruby-head
|
9
|
+
- rbx-2
|
10
|
+
matrix:
|
11
|
+
allow_failures:
|
12
|
+
- rvm: rbx-2
|
13
|
+
addons:
|
14
|
+
code_climate:
|
15
|
+
repo_token: 7ea441f6db20b42bf77b3d49f149f2fd683b58d714a1a2bc148820e963c77862
|
16
|
+
notifications:
|
17
|
+
slack:
|
18
|
+
secure: Z4Wgg8oVW8i20USH3GKfNB9pFR2tmL9a/Pg42Ck/cHNmBO+3UUDcfr7O1oOCrZEYcpobB+7rhLVHt3H0cSwXNDanpsDebi0ZcNHllSK7xDVLR1r0l6QHY15kCKMVIprrDgxCn80ANCE0Yb1x2V+cvZyNJAau6jTLgRmvUZ0oD1Y=
|
data/ChangeLog.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Trail of Bits
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
# spf-query
|
2
|
+
|
3
|
+
[![Code Climate](https://codeclimate.com/github/trailofbits/spf-query/badges/gpa.svg)](https://codeclimate.com/github/trailofbits/spf-query)
|
4
|
+
[![Test Coverage](https://codeclimate.com/github/trailofbits/spf-query/badges/coverage.svg)](https://codeclimate.com/github/trailofbits/spf-query)
|
5
|
+
[![Build Status](https://travis-ci.org/trailofbits/spf-query.svg)](https://travis-ci.org/trailofbits/spf-query)
|
6
|
+
|
7
|
+
The `spf-query` library searches the [SPF] records for a host. We assume the
|
8
|
+
host uses standard spf 'selectors', and also check if they use their own
|
9
|
+
'selector'.
|
10
|
+
|
11
|
+
## Features
|
12
|
+
|
13
|
+
* Queries and parses SPF records.
|
14
|
+
* Supports querying both TXT and SPF records.
|
15
|
+
|
16
|
+
## Examples
|
17
|
+
|
18
|
+
require 'spf/query'
|
19
|
+
|
20
|
+
SPF::Query::Record.query('twitter.com')
|
21
|
+
# => #<SPF::Query::Record: v=spf1 ip4:199.16.156.0/22 ip4:199.59.148.0/22 ip4:8.25.194.0/23 ip4:8.25.196.0/23 ip4:204.92.114.203 ip4:204.92.114.204/31 ip4:107.20.52.15 ip4:23.21.83.90 include:_spf.google.com include:_thirdparty.twitter.com -all>
|
22
|
+
|
23
|
+
SPF::Query::Record.parse("v=spf1 ip4:199.16.156.0/22 ip4:199.59.148.0/22 ip4:8.25.194.0/23 ip4:8.25.196.0/23 ip4:204.92.114.203 ip4:204.92.114.204/31 ip4:107.20.52.15 ip4:23.21.83.90 include:_spf.google.com include:_thirdparty.twitter.com -all")
|
24
|
+
# => #<SPF::Query::Record: v=spf1 ip4:199.16.156.0/22 ip4:199.59.148.0/22 ip4:8.25.194.0/23 ip4:8.25.196.0/23 ip4:204.92.114.203 ip4:204.92.114.204/31 ip4:107.20.52.15 ip4:23.21.83.90 include:_spf.google.com include:_thirdparty.twitter.com -all>
|
25
|
+
|
26
|
+
|
27
|
+
## Symopsis
|
28
|
+
|
29
|
+
Query a domain:
|
30
|
+
|
31
|
+
spf-query google.com
|
32
|
+
____________________________
|
33
|
+
SPF record search for google.com
|
34
|
+
- found SPF record for google.com at google.com:
|
35
|
+
v=spf1 include:_spf.google.com ip4:216.73.93.70/31 ip4:216.73.93.72/31 ~all
|
36
|
+
____________________________
|
37
|
+
|
38
|
+
|
39
|
+
Query multiple domains:
|
40
|
+
|
41
|
+
spf-query trailofbits.com facebook.com yahoo.com
|
42
|
+
____________________________
|
43
|
+
SPF record search for trailofbits.com
|
44
|
+
- found SPF record for trailofbits.com at trailofbits.com:
|
45
|
+
v=spf1 include:_spf.google.com ~all
|
46
|
+
____________________________
|
47
|
+
|
48
|
+
____________________________
|
49
|
+
SPF record search for facebook.com
|
50
|
+
- found SPF record for facebook.com at facebook.com:
|
51
|
+
v=spf1 redirect=_spf.facebook.com
|
52
|
+
____________________________
|
53
|
+
|
54
|
+
____________________________
|
55
|
+
SPF record search for yahoo.com
|
56
|
+
- found SPF record for yahoo.com at yahoo.com:
|
57
|
+
v=spf1 redirect=_spf.mail.yahoo.com
|
58
|
+
____________________________
|
59
|
+
|
60
|
+
## Requirements
|
61
|
+
|
62
|
+
* [ruby] >= 1.9.1
|
63
|
+
* [parslet] ~> 1.0
|
64
|
+
|
65
|
+
## Install
|
66
|
+
|
67
|
+
$ gem install spf-query
|
68
|
+
|
69
|
+
## License
|
70
|
+
|
71
|
+
See the {file:LICENSE.txt} file.
|
72
|
+
|
73
|
+
[ruby]: https://www.ruby-lang.org/
|
74
|
+
[parslet]: http://kschiess.github.io/parslet/
|
75
|
+
[SPF]: https://tools.ietf.org/html/rfc7208
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'bundler/setup'
|
6
|
+
rescue LoadError => e
|
7
|
+
warn e.message
|
8
|
+
warn "Run `gem install bundler` to install Bundler."
|
9
|
+
exit -1
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rake'
|
13
|
+
require 'bundler/gem_tasks'
|
14
|
+
|
15
|
+
require 'rspec/core/rake_task'
|
16
|
+
RSpec::Core::RakeTask.new
|
17
|
+
|
18
|
+
task :test => :spec
|
19
|
+
task :default => :spec
|
20
|
+
|
21
|
+
require 'yard'
|
22
|
+
YARD::Rake::YardocTask.new
|
23
|
+
task :doc => :yard
|
data/bin/spf-query
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib_dir = File.expand_path('../../lib',__FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
5
|
+
|
6
|
+
require 'spf/query'
|
7
|
+
|
8
|
+
unless ARGV[0]
|
9
|
+
puts "Please supply at least one host name"
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
|
13
|
+
ARGV.each do |arg|
|
14
|
+
puts "____________________________\n"
|
15
|
+
puts "SPF record search for #{arg}"
|
16
|
+
|
17
|
+
if (spf = SPFParse::Record.query(arg))
|
18
|
+
puts " - found SPF record for #{arg}"
|
19
|
+
puts " v=#{spf.version}"
|
20
|
+
|
21
|
+
spf.each do |rule|
|
22
|
+
puts " #{rule}"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
puts " - no SPF record found for #{arg}"
|
26
|
+
end
|
27
|
+
puts "____________________________\n\n"
|
28
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'resolv'
|
2
|
+
|
3
|
+
class Resolv::DNS::Resource::IN::SPF < Resolv::DNS::Resource::IN::TXT
|
4
|
+
# resolv.rb doesn't define an SPF resource type.
|
5
|
+
TypeValue = 99
|
6
|
+
ClassValue = Resolv::DNS::Resource::IN::ClassValue
|
7
|
+
|
8
|
+
Resolv::DNS::Resource::ClassHash[[TypeValue, ClassValue]] = self
|
9
|
+
end
|
data/lib/spf/query.rb
ADDED
data/lib/spf/query/ip.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module SPF
|
2
|
+
module Query
|
3
|
+
class IP
|
4
|
+
|
5
|
+
attr_reader :address
|
6
|
+
|
7
|
+
attr_reader :cidr_length
|
8
|
+
|
9
|
+
def initialize(address,cidr_length=nil)
|
10
|
+
@address = address
|
11
|
+
@cidr_length = cidr_length
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
if @cidr_length then "#{@address}/#{@cidr_length}"
|
16
|
+
else "#{@address}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SPF
|
2
|
+
module Query
|
3
|
+
class Macro
|
4
|
+
|
5
|
+
attr_reader :letter
|
6
|
+
|
7
|
+
attr_reader :digits
|
8
|
+
|
9
|
+
attr_reader :delimiters
|
10
|
+
|
11
|
+
def initialize(letter,options={})
|
12
|
+
@letter = letter
|
13
|
+
@digits = options[:digits]
|
14
|
+
@reverse = options[:reverse]
|
15
|
+
@delimiters = Array(options[:delimiters])
|
16
|
+
end
|
17
|
+
|
18
|
+
def reverse?
|
19
|
+
@reverse
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"%{#{@letter}#{@digits}#{@delimiters.join}}"
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SPF
|
2
|
+
module Query
|
3
|
+
class MacroString
|
4
|
+
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(elements)
|
8
|
+
@elements = elements
|
9
|
+
end
|
10
|
+
|
11
|
+
def each(&block)
|
12
|
+
@elements.each(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](*arguments)
|
16
|
+
@elements[*arguments]
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@elements.join
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module SPF
|
2
|
+
module Query
|
3
|
+
class Mechanism
|
4
|
+
|
5
|
+
QUALIFIERS = {
|
6
|
+
'+' => :pass,
|
7
|
+
'-' => :fail,
|
8
|
+
'~' => :soft_fail,
|
9
|
+
'?' => :neuatral
|
10
|
+
}
|
11
|
+
|
12
|
+
attr_reader :name
|
13
|
+
|
14
|
+
attr_reader :value
|
15
|
+
|
16
|
+
def initialize(name,options={})
|
17
|
+
@name = name
|
18
|
+
|
19
|
+
@value = options[:value]
|
20
|
+
@qualifier = options[:qualifier]
|
21
|
+
end
|
22
|
+
|
23
|
+
def qualifier
|
24
|
+
@qualifier || :pass
|
25
|
+
end
|
26
|
+
|
27
|
+
def pass?
|
28
|
+
@qualifier == :pass || @qualifier.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
def fail?
|
32
|
+
@qualifier == :fail
|
33
|
+
end
|
34
|
+
|
35
|
+
def soft_fail?
|
36
|
+
@qualifier == :soft_fail
|
37
|
+
end
|
38
|
+
|
39
|
+
def neutral?
|
40
|
+
@qualifier == :neutral
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
str = "#{QUALIFIERS.invert[@qualifier]}#{@name}"
|
45
|
+
str << ":#{@value}" if value
|
46
|
+
|
47
|
+
return str
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SPF
|
2
|
+
module Query
|
3
|
+
class Modifier
|
4
|
+
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
def initialize(name,value=nil)
|
10
|
+
@name, @value = name, value
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
if @value then "#{@name}=#{@value}"
|
15
|
+
else "#{@name}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
class UnknownModifier < Modifier
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|