rbl_mcafee 0.0.2 → 1.0.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.
- checksums.yaml +4 -4
- data/README.md +9 -4
- data/lib/rbl_mcafee.rb +2 -20
- data/lib/rbl_mcafee/ip.rb +23 -0
- data/lib/rbl_mcafee/version.rb +1 -1
- data/lib/rbl_mcafee/zone.rb +81 -0
- data/spec/rbl_mcafee/ip_spec.rb +37 -0
- data/spec/rbl_mcafee/zone_spec.rb +120 -0
- metadata +7 -3
- data/spec/rbl_mcafee_spec.rb +0 -54
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e020eef8e74971b1837a2c58f2897ea9b8bab9a
|
|
4
|
+
data.tar.gz: 795633fa1241d021c7dcfe73116d97e3f7c57fa8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7699ffe783f39a5a5c38a67dc2e5206bb3c6e73d601b2c05391b54514a4ab77911d4112a133bda0a20a5797744c7542e2cf8aaf9d924dd978d8147058e15bc22
|
|
7
|
+
data.tar.gz: 0f2050bcce6d2ee3e449bcf6bdbad74b7aa72b1d542a5c9441428f0184f87362be1fb7bb0327a31d57be9851a08c38b7dedacea2d1102c45e4cf7d0e82c4f8ed
|
data/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Solution to test if an IP address is listed in the McAfee RBL.
|
|
4
4
|
|
|
5
|
+
McAfee uses the Spamhaus Project (https://www.spamhaus.org/).
|
|
6
|
+
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
Add this line to your application's Gemfile:
|
|
@@ -18,16 +20,19 @@ Or install it yourself as:
|
|
|
18
20
|
|
|
19
21
|
## Usage
|
|
20
22
|
|
|
21
|
-
To verify if an IP address is listed in the
|
|
23
|
+
To verify if an IP address is listed in one of the Spamhaus IP zones:
|
|
22
24
|
|
|
23
25
|
```ruby
|
|
24
|
-
RblMcafee.
|
|
26
|
+
zone = RblMcafee::Zone.new('127.0.0.1')
|
|
27
|
+
zone.pbl?
|
|
28
|
+
zone.sbl?
|
|
29
|
+
zone.xbl?
|
|
25
30
|
```
|
|
26
31
|
|
|
27
32
|
Expected returned values are the following:
|
|
28
33
|
|
|
29
|
-
* `true` when the IP address **is listed** in the
|
|
30
|
-
* `false` when the IP address **isn't listed** in the
|
|
34
|
+
* `true` when the IP address **is listed** in the zone
|
|
35
|
+
* `false` when the IP address **isn't listed** in the zone
|
|
31
36
|
|
|
32
37
|
When a **timeout** occurs, a `RblMcafee::Timeout` exception is raised.
|
|
33
38
|
|
data/lib/rbl_mcafee.rb
CHANGED
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
require "rbl_mcafee/version"
|
|
2
|
-
require 'resolv'
|
|
3
2
|
|
|
4
3
|
module RblMcafee
|
|
5
4
|
# Indicates a timeout checking an IP address
|
|
6
5
|
class Timeout < TimeoutError; end
|
|
7
6
|
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
# RBL
|
|
11
|
-
MC_AFEE_RBL_LISTED_REGEX = /^127\.0\.0\.\d{1,3}$/
|
|
12
|
-
|
|
13
|
-
def self.blacklisted?(ip)
|
|
14
|
-
if !ip.match(Resolv::IPv6::Regex) && !ip.match(Resolv::IPv4::Regex)
|
|
15
|
-
raise ArgumentError, 'Invalid IP'
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
reversed_ip = ip.split('.').reverse.join('.')
|
|
19
|
-
resolved_ip = Resolv::getaddress("#{reversed_ip}.cidr.bl.mcafee.com")
|
|
20
|
-
return !!resolved_ip.match(MC_AFEE_RBL_LISTED_REGEX)
|
|
21
|
-
|
|
22
|
-
rescue Resolv::ResolvError
|
|
23
|
-
false
|
|
24
|
-
rescue Resolv::ResolvTimeout
|
|
25
|
-
raise RblMcafee::Timeout
|
|
26
|
-
end
|
|
7
|
+
# Indicates a failure to resolve an IP address
|
|
8
|
+
class Error < StandardError; end;
|
|
27
9
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module RblMcafee
|
|
2
|
+
class Ip
|
|
3
|
+
attr_reader :ip
|
|
4
|
+
|
|
5
|
+
def initialize(ip)
|
|
6
|
+
@ip = ip
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def valid?
|
|
10
|
+
ipv4? || ipv6?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
def ipv4?
|
|
16
|
+
!!ip.match(Resolv::IPv4::Regex)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def ipv6?
|
|
20
|
+
!!ip.match(Resolv::IPv6::Regex)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/rbl_mcafee/version.rb
CHANGED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require "rbl_mcafee/version"
|
|
2
|
+
require "rbl_mcafee/ip"
|
|
3
|
+
require 'resolv'
|
|
4
|
+
|
|
5
|
+
module RblMcafee
|
|
6
|
+
class Zone
|
|
7
|
+
PBL = :pbl
|
|
8
|
+
SBL = :sbl
|
|
9
|
+
XBL = :xbl
|
|
10
|
+
|
|
11
|
+
attr_reader :ip
|
|
12
|
+
|
|
13
|
+
def initialize(ip)
|
|
14
|
+
raise ArgumentError, 'Invalid IP' unless RblMcafee::Ip.new(ip).valid?
|
|
15
|
+
|
|
16
|
+
@ip = ip
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def pbl?
|
|
20
|
+
zone == PBL
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def sbl?
|
|
24
|
+
zone == SBL
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def xbl?
|
|
28
|
+
zone == XBL
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def zone
|
|
35
|
+
return @zone if defined? @zone
|
|
36
|
+
|
|
37
|
+
@zone = extract_zone(resolved_ip)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Lookup the IP address on "cidr.bl.mcafee.com"
|
|
41
|
+
def resolved_ip
|
|
42
|
+
return @resolved_ip if defined? @resolved_ip
|
|
43
|
+
|
|
44
|
+
reversed_ip = ip.split('.').reverse.join('.')
|
|
45
|
+
@resolved_ip = Resolv::getaddress("#{reversed_ip}.cidr.bl.mcafee.com")
|
|
46
|
+
|
|
47
|
+
rescue Resolv::ResolvError
|
|
48
|
+
@resolved_ip = nil
|
|
49
|
+
rescue Resolv::ResolvTimeout
|
|
50
|
+
raise RblMcafee::Timeout
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# @see https://kc.mcafee.com/corporate/index?page=content&id=KB53783
|
|
55
|
+
# If the reply is in the format 127.0.0.XXX, the host is listed in the
|
|
56
|
+
# McAfee RBL (@see below)
|
|
57
|
+
MC_AFEE_RBL_LISTED_REGEX = /^127\.0\.0\.\d{1,3}$/
|
|
58
|
+
|
|
59
|
+
# @see https://www.spamhaus.org/faq/section/DNSBL%20Usage#202
|
|
60
|
+
#
|
|
61
|
+
# DNSBL | Returns | Contains
|
|
62
|
+
# ------+---------------+---------------------------------------------------
|
|
63
|
+
# SBL | 127.0.0.2-3 | Static UBE sources, verified spam services
|
|
64
|
+
# | | (hosting or support) and ROKSO spammers
|
|
65
|
+
# XBL | 127.0.0.4-7 | Illegal 3rd party exploits, including proxies,
|
|
66
|
+
# \ | worms and trojan exploits
|
|
67
|
+
# PBL | 127.0.0.10-11 | IP ranges which should not be delivering
|
|
68
|
+
# | | unauthenticated SMTP email.
|
|
69
|
+
def extract_zone(resolved_ip)
|
|
70
|
+
return nil if resolved_ip.nil?
|
|
71
|
+
return nil unless resolved_ip.match(MC_AFEE_RBL_LISTED_REGEX)
|
|
72
|
+
|
|
73
|
+
case resolved_ip.split('.').last.to_i
|
|
74
|
+
when 2..3 then SBL
|
|
75
|
+
when 4..7 then XBL
|
|
76
|
+
when 10..11 then PBL
|
|
77
|
+
else nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'rbl_mcafee/ip'
|
|
2
|
+
|
|
3
|
+
describe RblMcafee::Ip do
|
|
4
|
+
subject { RblMcafee::Ip.new(ip_address) }
|
|
5
|
+
|
|
6
|
+
context 'with an IPv4 address' do
|
|
7
|
+
let(:ip_address) { '1.160.10.240' }
|
|
8
|
+
|
|
9
|
+
it 'detects the IP as IPv4' do
|
|
10
|
+
expect(subject.send(:ipv4?)).to be true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'does not detect the IP as IPv6' do
|
|
14
|
+
expect(subject.send(:ipv6?)).to be false
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'detects the IP as valid' do
|
|
18
|
+
expect(subject.valid?).to be true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context 'with an IPv6 address' do
|
|
23
|
+
let(:ip_address) { '3ffe:1900:4545:3:200:f8ff:fe21:67cf' }
|
|
24
|
+
|
|
25
|
+
it 'does not detect the IP as IPv4' do
|
|
26
|
+
expect(subject.send(:ipv4?)).to be false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'detects the IP as IPv6' do
|
|
30
|
+
expect(subject.send(:ipv6?)).to be true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'detects the IP as valid' do
|
|
34
|
+
expect(subject.valid?).to be true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require 'rbl_mcafee'
|
|
2
|
+
require 'rbl_mcafee/zone'
|
|
3
|
+
|
|
4
|
+
describe RblMcafee::Zone do
|
|
5
|
+
subject { RblMcafee::Zone.new('127.0.0.1') }
|
|
6
|
+
|
|
7
|
+
# Extract zone
|
|
8
|
+
# ----------------------------------------------------------------------------
|
|
9
|
+
it 'extracts the zones correctly' do
|
|
10
|
+
expect(subject.send(:extract_zone, nil)).to be(nil)
|
|
11
|
+
expect(subject.send(:extract_zone,'127.0.0.1')).to be(nil)
|
|
12
|
+
expect(subject.send(:extract_zone,'127.0.0.2')).to be(RblMcafee::Zone::SBL)
|
|
13
|
+
expect(subject.send(:extract_zone,'127.0.0.3')).to be(RblMcafee::Zone::SBL)
|
|
14
|
+
expect(subject.send(:extract_zone,'127.0.0.4')).to be(RblMcafee::Zone::XBL)
|
|
15
|
+
expect(subject.send(:extract_zone,'127.0.0.5')).to be(RblMcafee::Zone::XBL)
|
|
16
|
+
expect(subject.send(:extract_zone,'127.0.0.6')).to be(RblMcafee::Zone::XBL)
|
|
17
|
+
expect(subject.send(:extract_zone,'127.0.0.7')).to be(RblMcafee::Zone::XBL)
|
|
18
|
+
expect(subject.send(:extract_zone,'127.0.0.8')).to be(nil)
|
|
19
|
+
expect(subject.send(:extract_zone,'127.0.0.9')).to be(nil)
|
|
20
|
+
expect(subject.send(:extract_zone,'127.0.0.10')).to be(RblMcafee::Zone::PBL)
|
|
21
|
+
expect(subject.send(:extract_zone,'127.0.0.11')).to be(RblMcafee::Zone::PBL)
|
|
22
|
+
expect(subject.send(:extract_zone,'127.0.0.12')).to be(nil)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# PBL zone
|
|
26
|
+
# ----------------------------------------------------------------------------
|
|
27
|
+
context 'with an IP address listed in the PBL zone' do
|
|
28
|
+
before(:each) { Resolv.stub(:getaddress) { '127.0.0.10' } }
|
|
29
|
+
|
|
30
|
+
it 'is not detected as belonging to the SBL zone' do
|
|
31
|
+
expect(subject.sbl?).to be false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'is not detected as belonging to the XBL zone' do
|
|
35
|
+
expect(subject.xbl?).to be false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'is detected as belonging to the PBL zone' do
|
|
39
|
+
expect(subject.pbl?).to be true
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# SBL zone
|
|
44
|
+
# ----------------------------------------------------------------------------
|
|
45
|
+
context 'with an IP address listed in the SBL zone' do
|
|
46
|
+
before(:each) { Resolv.stub(:getaddress) { '127.0.0.3' } }
|
|
47
|
+
|
|
48
|
+
it 'is detected as belonging to the SBL zone' do
|
|
49
|
+
expect(subject.sbl?).to be true
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'is not detected as belonging to the XBL zone' do
|
|
53
|
+
expect(subject.xbl?).to be false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'is not detected as belonging to the PBL zone' do
|
|
57
|
+
expect(subject.pbl?).to be false
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# XBL zone
|
|
62
|
+
# ----------------------------------------------------------------------------
|
|
63
|
+
context 'with an IP address listed in the XBL zone' do
|
|
64
|
+
before(:each) { Resolv.stub(:getaddress) { '127.0.0.4' } }
|
|
65
|
+
|
|
66
|
+
it 'is not detected as belonging to the SBL zone' do
|
|
67
|
+
expect(subject.sbl?).to be false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'is detected as belonging to the XBL zone' do
|
|
71
|
+
expect(subject.xbl?).to be true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'is not detected as belonging to the PBL zone' do
|
|
75
|
+
expect(subject.pbl?).to be false
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Without zone
|
|
80
|
+
# ----------------------------------------------------------------------------
|
|
81
|
+
context 'with an IP address not listed in any zone' do
|
|
82
|
+
before(:each) { Resolv.stub(:getaddress) { raise Resolv::ResolvError } }
|
|
83
|
+
|
|
84
|
+
it 'is not detected as belonging to the SBL zone' do
|
|
85
|
+
expect(subject.sbl?).to be false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'is not detected as belonging to the XBL zone' do
|
|
89
|
+
expect(subject.xbl?).to be false
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'is not detected as belonging to the PBL zone' do
|
|
93
|
+
expect(subject.pbl?).to be false
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Exceptions
|
|
98
|
+
# ----------------------------------------------------------------------------
|
|
99
|
+
it 'raises an ArgumentError for invalid IP addresses' do
|
|
100
|
+
RblMcafee::Ip.any_instance.stub(:valid?) { false }
|
|
101
|
+
|
|
102
|
+
expect{subject}.to raise_error(ArgumentError)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'raises a RblMcafee::Timeout when a timeout error is raised by Resolv' do
|
|
106
|
+
Resolv.stub(:getaddress) { raise Resolv::ResolvTimeout }
|
|
107
|
+
|
|
108
|
+
expect{subject.sbl?}.to raise_error(RblMcafee::Timeout)
|
|
109
|
+
expect{subject.xbl?}.to raise_error(RblMcafee::Timeout)
|
|
110
|
+
expect{subject.pbl?}.to raise_error(RblMcafee::Timeout)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'raises unknown exceptions raised by Resolv' do
|
|
114
|
+
Resolv.stub(:getaddress) { raise 'oops' }
|
|
115
|
+
|
|
116
|
+
expect{subject.sbl?}.to raise_error('oops')
|
|
117
|
+
expect{subject.xbl?}.to raise_error('oops')
|
|
118
|
+
expect{subject.pbl?}.to raise_error('oops')
|
|
119
|
+
end
|
|
120
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rbl_mcafee
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Romain Salles
|
|
@@ -67,9 +67,12 @@ files:
|
|
|
67
67
|
- README.md
|
|
68
68
|
- Rakefile
|
|
69
69
|
- lib/rbl_mcafee.rb
|
|
70
|
+
- lib/rbl_mcafee/ip.rb
|
|
70
71
|
- lib/rbl_mcafee/version.rb
|
|
72
|
+
- lib/rbl_mcafee/zone.rb
|
|
71
73
|
- rbl_mcafee.gemspec
|
|
72
|
-
- spec/
|
|
74
|
+
- spec/rbl_mcafee/ip_spec.rb
|
|
75
|
+
- spec/rbl_mcafee/zone_spec.rb
|
|
73
76
|
homepage: https://github.com/romainsalles/rbl_mcafee
|
|
74
77
|
licenses:
|
|
75
78
|
- MIT
|
|
@@ -95,4 +98,5 @@ signing_key:
|
|
|
95
98
|
specification_version: 4
|
|
96
99
|
summary: Solution to test if an IP address is listed in the McAfee RBL
|
|
97
100
|
test_files:
|
|
98
|
-
- spec/
|
|
101
|
+
- spec/rbl_mcafee/ip_spec.rb
|
|
102
|
+
- spec/rbl_mcafee/zone_spec.rb
|
data/spec/rbl_mcafee_spec.rb
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
require 'rbl_mcafee'
|
|
2
|
-
|
|
3
|
-
describe RblMcafee do
|
|
4
|
-
subject { RblMcafee.blacklisted?(ip_address) }
|
|
5
|
-
let(:ip_address) { '127.0.0.1' }
|
|
6
|
-
|
|
7
|
-
context 'with a non listed IP address' do
|
|
8
|
-
it 'returns false' do
|
|
9
|
-
Resolv.stub(:getaddress) { raise Resolv::ResolvError.new('whatever') }
|
|
10
|
-
|
|
11
|
-
expect(subject).to be false
|
|
12
|
-
end
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
context 'with a listed IP address' do
|
|
16
|
-
it 'returns true' do
|
|
17
|
-
Resolv.stub(:getaddress) { '127.0.0.11' }
|
|
18
|
-
|
|
19
|
-
expect(subject).to be true
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context 'when a timeout error is raised by Resolv' do
|
|
24
|
-
it 'raises a RblMcafee::Timeout error' do
|
|
25
|
-
Resolv.stub(:getaddress) { raise Resolv::ResolvTimeout }
|
|
26
|
-
|
|
27
|
-
expect{subject}.to raise_error(RblMcafee::Timeout)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
context 'when an unknown exception is raised by Resolv' do
|
|
32
|
-
it 'is re-raised by .blacklisted?' do
|
|
33
|
-
Resolv.stub(:getaddress) { raise 'oops' }
|
|
34
|
-
|
|
35
|
-
expect{subject}.to raise_error('oops')
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
context 'when an invalid IP address is passed as argument' do
|
|
40
|
-
let(:ip_address) { '001.8.9.10' }
|
|
41
|
-
|
|
42
|
-
it 'raises an ArgumentError' do
|
|
43
|
-
expect{subject}.to raise_error(ArgumentError)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
context 'when a valid website address is passed as argument' do
|
|
48
|
-
let(:ip_address) { 'www.mcafee.com' }
|
|
49
|
-
|
|
50
|
-
it 'raises an ArgumentError' do
|
|
51
|
-
expect{subject}.to raise_error(ArgumentError)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
end
|