enricher 0.0.4 → 0.0.7
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 +119 -10
- data/Rakefile +9 -1
- data/enricher.gemspec +1 -0
- data/lib/enricher.rb +26 -8
- data/lib/enricher/bgpranking.rb +15 -17
- data/lib/enricher/cdn.rb +112 -0
- data/lib/enricher/encoder.rb +84 -55
- data/lib/enricher/exceptions.rb +3 -3
- data/lib/enricher/ipvoid.rb +78 -0
- data/lib/enricher/resolver.rb +30 -0
- data/lib/enricher/version.rb +2 -2
- data/lib/enricher/virustotal.rb +51 -0
- data/lib/vash.rb +3 -1
- metadata +33 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3a26447430c0aabed962d287dd55ecb300c4b55
|
4
|
+
data.tar.gz: 8afd50139c78292f1cdd4931c966a8f0414675cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d7c1bca11cc0e5cec806a22fa4fb878492673c24c479b1b3d0a786c013b09258dec97b355ed4597bca3a1820029a95f388c0b41a01a45669168be13545e8bfb
|
7
|
+
data.tar.gz: 378842b2949ad62ea3f0718600bfccbe0581a3339408e9287e388afb7ebd412d76601c33f72b9ea40677bec02c143df9e70629b20a8910bb50b2720badd85de4
|
data/README.md
CHANGED
@@ -2,33 +2,142 @@
|
|
2
2
|
|
3
3
|
IPv4 Data Enricher
|
4
4
|
|
5
|
+
[](http://badge.fury.io/rb/enricher)
|
6
|
+
|
5
7
|
### Static Calculators:
|
6
8
|
|
7
|
-
Calculate ASN, CC3, Bogon, and Lat Long.
|
9
|
+
Calculate Maxmind ASN, CC3, Bogon inclusion, and geodata such as Lat Long.
|
10
|
+
|
11
|
+
CDN Hostname check regex lookup.
|
8
12
|
|
9
13
|
### Online Calculators:
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
BGP Ranking with http://bgpranking.circl.lu/ ASN Calculator
|
16
|
+
|
17
|
+
Full Bogon Checking with Team Cymru List
|
18
|
+
|
19
|
+
Reverse DNS Lookups from (L3 DNS Servers 4.2.2.2/3/4)
|
20
|
+
|
21
|
+
|
22
|
+
### Usage
|
23
|
+
|
24
|
+
```
|
25
|
+
>> require 'enricher'
|
26
|
+
=> true
|
27
|
+
```
|
28
|
+
|
29
|
+
#### For Pure Offline Meta Data Enhancement
|
30
|
+
```
|
31
|
+
>> a = Enricher::Encoder.encode('10.48.185.173')
|
32
|
+
=> {:ip=>170965421, :asn=>"--", :asn_rank=>"0.0", :geoip=>"--", :bogon=>true}
|
33
|
+
|
34
|
+
>> a = Enricher::Encoder.encode('108.48.185.173')
|
35
|
+
=> {:ip=>1815132589, :asn=>"AS701", :asn_rank=>"0.000011", :geoip=>"USA", :bogon=>false}
|
36
|
+
```
|
37
|
+
|
38
|
+
#### For Online Meta Data Enrichment
|
39
|
+
```
|
40
|
+
2.1.2 :006 > a = Enricher::Encoder.encode_online('96.3.8.26')
|
41
|
+
=> {:ip=>1610811418, :asn=>"AS11232", :asn_rank=>"0.000048", :geoip=>"USA", :bogon=>false, :reverse=>"host-26-8-3-96.midco.net.", :cdn=>false}
|
42
|
+
2.1.2 :007 > a = Enricher::Encoder.encode_online('96.6.113.42')
|
43
|
+
=> {:ip=>1611034922, :asn=>"AS20940", :asn_rank=>"0.000411", :geoip=>"USA", :bogon=>false, :reverse=>"a96-6-113-42.deploy.akamaitechnologies.com.", :cdn=>true}
|
44
|
+
2.1.2 :008 > a = Enricher::Encoder.encode_online('119.27.76.185')
|
45
|
+
=> {:ip=>1998277817, :asn=>"AS4837", :asn_rank=>"0.000082", :geoip=>"CHN", :bogon=>false, :reverse=>"", :cdn=>false}
|
46
|
+
2.1.2 :009 > a = Enricher::Encoder.encode_online('199.27.76.185')
|
47
|
+
=> {:ip=>3340455097, :asn=>"AS54113", :asn_rank=>"0.000526", :geoip=>"USA", :bogon=>false, :reverse=>"", :cdn=>false}
|
48
|
+
2.1.2 :010 > a = Enricher::Encoder.encode_online('54.239.195.35')
|
49
|
+
=> {:ip=>921682723, :asn=>"AS16509", :asn_rank=>"0.000293", :geoip=>"USA", :bogon=>false, :reverse=>"server-54-239-195-35.nrt12.r.cloudfront.net.", :cdn=>true}
|
50
|
+
2.1.2 :011 > a = Enricher::Encoder.encode_online('54.239.195.149')
|
51
|
+
=> {:ip=>921682837, :asn=>"AS16509", :asn_rank=>"0.000293", :geoip=>"USA", :bogon=>false, :reverse=>"server-54-239-195-149.nrt12.r.cloudfront.net.", :cdn=>true}
|
52
|
+
2.1.2 :012 > a = Enricher::Encoder.encode_online('72.21.91.8')
|
53
|
+
=> {:ip=>1209359112, :asn=>"AS15133", :asn_rank=>"0.000312", :geoip=>"USA", :bogon=>false, :reverse=>"", :cdn=>false}
|
54
|
+
2.1.2 :013 > a = Enricher::Encoder.encode_online('173.194.121.44')
|
55
|
+
=> {:ip=>2915203372, :asn=>"AS15169", :asn_rank=>"0.000204", :geoip=>"USA", :bogon=>false, :reverse=>"iad23s26-in-f12.1e100.net.", :cdn=>true}
|
56
|
+
2.1.2 :014 > a = Enricher::Encoder.encode_online('205.234.175.175')
|
57
|
+
=> {:ip=>3454709679, :asn=>"AS30081", :asn_rank=>"0.000781", :geoip=>"USA", :bogon=>false, :reverse=>"vip1.G-anycast1.cachefly.net.", :cdn=>true}
|
58
|
+
```
|
59
|
+
|
60
|
+
### Use of Volatile Hash DB
|
61
|
+
|
62
|
+
BGP Scores are stored for 12 hours in a volatile hash cache.
|
63
|
+
|
64
|
+
```
|
65
|
+
2.1.2 :015 > Enricher::BGPRanking.cache
|
66
|
+
=> {:asn12542=>"0.000010", :asn11232=>"0.000048", :asn20940=>"0.000411", :asn4837=>"0.000082", :asn54113=>"0.000526", :asn16509=>"0.000293", :asn15133=>"0.000312", :asn15169=>"0.000204", :asn30081=>"0.000781"}
|
67
|
+
```
|
68
|
+
|
69
|
+
### TODO
|
13
70
|
|
14
|
-
|
71
|
+
* IPv4 reputation with VOIDIP
|
72
|
+
* IPv4 reputation with VirusTotal (uirusu)
|
15
73
|
|
16
74
|
## Requirements
|
17
75
|
|
18
|
-
Intenet connectivity for Online
|
76
|
+
Intenet connectivity is required *only* for Online Meta Data Enhancement.
|
77
|
+
|
78
|
+
### BootStrapping GeoIP
|
79
|
+
|
80
|
+
There is a rake command include to bootstrap the fetching of geoip data if you are a sudo enabled linux user.
|
81
|
+
|
82
|
+
```
|
83
|
+
(/home/shadowbq/.rvm/gems/ruby-2.1.2/gems/enricher-0.0.7)$ rake fetch_geoip_data
|
84
|
+
--2014-12-31 11:32:28-- http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
|
85
|
+
Resolving geolite.maxmind.com (geolite.maxmind.com)... 141.101.115.190, 141.101.114.190, 2400:cb00:2048:1::8d65:72be, ...
|
86
|
+
Connecting to geolite.maxmind.com (geolite.maxmind.com)|141.101.115.190|:80... connected.
|
87
|
+
HTTP request sent, awaiting response... 200 OK
|
88
|
+
Length: 428181 (418K) [application/octet-stream]
|
89
|
+
Saving to: ‘/usr/local/lib/share/enricher/GeoIP.dat.gz’
|
90
|
+
|
91
|
+
100%[=====================================================================================================================================================================================================================================>] 428,181 --.-K/s in 0.08s
|
92
|
+
|
93
|
+
2014-12-31 11:32:28 (5.22 MB/s) - ‘/usr/local/lib/share/enricher/GeoIP.dat.gz’ saved [428181/428181]
|
94
|
+
|
95
|
+
--2014-12-31 11:32:28-- http://geolite.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
|
96
|
+
Resolving geolite.maxmind.com (geolite.maxmind.com)... 141.101.114.190, 141.101.115.190, 2400:cb00:2048:1::8d65:73be, ...
|
97
|
+
Connecting to geolite.maxmind.com (geolite.maxmind.com)|141.101.114.190|:80... connected.
|
98
|
+
HTTP request sent, awaiting response... 200 OK
|
99
|
+
Length: 2056964 (2.0M) [application/octet-stream]
|
100
|
+
Saving to: ‘/usr/local/lib/share/enricher/GeoIPASNum.dat.gz’
|
101
|
+
|
102
|
+
100%[=====================================================================================================================================================================================================================================>] 2,056,964 1.38MB/s in 1.4s
|
103
|
+
|
104
|
+
2014-12-31 11:32:30 (1.38 MB/s) - ‘/usr/local/lib/share/enricher/GeoIPASNum.dat.gz’ saved [2056964/2056964]
|
105
|
+
|
106
|
+
--2014-12-31 11:32:30-- http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
|
107
|
+
Resolving geolite.maxmind.com (geolite.maxmind.com)... 141.101.115.190, 141.101.114.190, 2400:cb00:2048:1::8d65:72be, ...
|
108
|
+
Connecting to geolite.maxmind.com (geolite.maxmind.com)|141.101.115.190|:80... connected.
|
109
|
+
HTTP request sent, awaiting response... 200 OK
|
110
|
+
Length: 11896864 (11M) [application/octet-stream]
|
111
|
+
Saving to: ‘/usr/local/lib/share/enricher/GeoLiteCity.dat.gz’
|
112
|
+
|
113
|
+
100%[=====================================================================================================================================================================================================================================>] 11,896,864 5.10MB/s in 2.2s
|
114
|
+
|
115
|
+
2014-12-31 11:32:32 (5.10 MB/s) - ‘/usr/local/lib/share/enricher/GeoLiteCity.dat.gz’ saved [11896864/11896864]
|
116
|
+
|
117
|
+
>$ ls -la /usr/local/lib/share/enricher/
|
118
|
+
total 22664
|
119
|
+
drwxr-xr-x 2 root root 4096 Dec 31 11:32 .
|
120
|
+
drwxr-xr-x 3 root root 4096 Dec 31 11:23 ..
|
121
|
+
-rw-r--r-- 1 root root 748606 Dec 2 16:43 GeoIP.dat
|
122
|
+
-rw-r--r-- 1 root root 3766172 Dec 12 17:54 GeoIPASNum.dat
|
123
|
+
-rw-r--r-- 1 root root 18678957 Dec 2 16:57 GeoLiteCity.dat
|
124
|
+
|
125
|
+
```
|
126
|
+
|
127
|
+
(Manual Methods)
|
19
128
|
|
20
|
-
Maxmind dat file location requirement: `/usr/local/lib/share/enricher`
|
129
|
+
Maxmind(R) dat file location requirement: `/usr/local/lib/share/enricher`
|
21
130
|
|
22
131
|
You need to download and install each of the free GeoLite country, city or ASN databases, or a subscription database version.
|
23
132
|
|
24
133
|
The last known download locations for the GeoLite database versions are:
|
25
134
|
|
26
|
-
|
27
|
-
|
28
|
-
|
135
|
+
* http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
|
136
|
+
* http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
|
137
|
+
* http://geolite.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz
|
29
138
|
|
30
139
|
|
31
|
-
|
140
|
+
### Automating the update of Static Content (via crontrab)
|
32
141
|
|
33
142
|
We can add a cron-job to automate the monthly process of updating the GeoIP database:
|
34
143
|
|
data/Rakefile
CHANGED
@@ -8,4 +8,12 @@ Rake::TestTask.new do |test|
|
|
8
8
|
test.libs << "test"
|
9
9
|
test.test_files = Dir[ "test/test_*.rb" ]
|
10
10
|
test.verbose = true
|
11
|
-
end
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Fetch the GeoIP Data sets'
|
14
|
+
task :fetch_geoip_data do
|
15
|
+
`sudo mkdir -p /usr/local/lib/share/enricher`
|
16
|
+
`sudo sh -c '/usr/bin/wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz -O /usr/local/lib/share/enricher/GeoIP.dat.gz; /bin/gunzip -f /usr/local/lib/share/enricher/GeoIP.dat.gz'`
|
17
|
+
`sudo sh -c '/usr/bin/wget http://geolite.maxmind.com/download/geoip/database/asnum/GeoIPASNum.dat.gz -O /usr/local/lib/share/enricher/GeoIPASNum.dat.gz; /bin/gunzip -f /usr/local/lib/share/enricher/GeoIPASNum.dat.gz'`
|
18
|
+
`sudo sh -c '/usr/bin/wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz -O /usr/local/lib/share/enricher/GeoLiteCity.dat.gz; /bin/gunzip -f /usr/local/lib/share/enricher/GeoLiteCity.dat.gz'`
|
19
|
+
end
|
data/enricher.gemspec
CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.add_development_dependency 'bundler', '~> 1.0'
|
19
19
|
gem.add_dependency "geoip", '~> 1.2'
|
20
20
|
gem.add_dependency "netaddr", '~> 1.5'
|
21
|
+
gem.add_dependency "net-dns", '~> 0.8'
|
21
22
|
gem.add_dependency "rest-client"
|
22
23
|
gem.add_dependency "json"
|
23
24
|
|
data/lib/enricher.rb
CHANGED
@@ -13,7 +13,8 @@ require 'json'
|
|
13
13
|
require 'geoip'
|
14
14
|
require 'netaddr'
|
15
15
|
require 'rest-client'
|
16
|
-
|
16
|
+
require 'net/dns'
|
17
|
+
#require 'uirusu'
|
17
18
|
|
18
19
|
# Internal
|
19
20
|
module Enricher
|
@@ -24,14 +25,24 @@ module Enricher
|
|
24
25
|
require 'enricher/exceptions'
|
25
26
|
require 'enricher/bogon'
|
26
27
|
require 'enricher/bgpranking'
|
28
|
+
require 'enricher/cdn'
|
29
|
+
require 'enricher/resolver'
|
27
30
|
require 'enricher/encoder'
|
28
31
|
|
29
32
|
DEBUG=false
|
30
33
|
LOGGING=false
|
31
|
-
|
34
|
+
COMMON_DATA_PATHS=[
|
35
|
+
'/usr/local/lib/share/enricher',
|
36
|
+
'/usr/local/share/enricher',
|
37
|
+
'/usr/local/lib/enricher',
|
38
|
+
'/usr/local/etc/enricher',
|
39
|
+
'/etc/enricher',
|
40
|
+
'/var/db/enricher'
|
41
|
+
]
|
42
|
+
|
32
43
|
#Setup Paths
|
33
44
|
LIB_PATH = File.expand_path("../", __FILE__)
|
34
|
-
CONFIG_PATH = File.expand_path("../../db", __FILE__)
|
45
|
+
#CONFIG_PATH = File.expand_path("../../db", __FILE__)
|
35
46
|
|
36
47
|
if Enricher::DEBUG
|
37
48
|
Enricher::DATA_PATH = File.expand_path("../../data", __FILE__)
|
@@ -39,11 +50,18 @@ module Enricher
|
|
39
50
|
Enricher::LOG_PATH = File.expand_path("../../log", __FILE__)
|
40
51
|
logfile = "#{Enricher::LOG_PATH}/enricher.log"
|
41
52
|
end
|
42
|
-
else
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
53
|
+
else
|
54
|
+
COMMON_DATA_PATHS.each do |dirname|
|
55
|
+
if File.exists?(dirname) && File.directory?(dirname)
|
56
|
+
Enricher::DATA_PATH = File.path(dirname)
|
57
|
+
if Enricher::LOGGING
|
58
|
+
logfile = Tempfile.new('enricher.log')
|
59
|
+
Enricher::LOG_PATH = File.dirname(logfile.path)
|
60
|
+
end
|
61
|
+
break
|
62
|
+
else
|
63
|
+
raise EnricherPathMissing, "Enricher data path not found in Common Data Paths. (i.e /usr/local/lib/share/enricher) See README.md"
|
64
|
+
end
|
47
65
|
end
|
48
66
|
end
|
49
67
|
|
data/lib/enricher/bgpranking.rb
CHANGED
@@ -9,33 +9,31 @@ module Enricher
|
|
9
9
|
# >> r = RestClient.post "http://bgpranking.circl.lu/json", { 'method' => 'cached_daily_rank', 'asn' => 198540, 'date' => '2014-02-24' }.to_json, :content_type => :json, :accept => :json
|
10
10
|
# => "[198540, "ELAN-AS Przedsiebiorstwo Uslug Specjalistycznych ELAN mgr inz. Andrzej Niechcial", "2014-02-24", "global", 1.09609375]"
|
11
11
|
# >> a = JSON.parse(r)
|
12
|
-
|
13
12
|
class BGPRanking
|
14
13
|
|
15
14
|
BGP_RANK_URL = "http://bgpranking.circl.lu/json"
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
def self.rank?(addr)
|
17
|
+
asn = addr.strip[/[0-9]+/]
|
18
|
+
if asn =~ /[0-9]+/
|
19
|
+
@@cache ||= Vash.new
|
20
|
+
# Voliate Cache store for 43200 (12hr)
|
21
|
+
@@cache["asn#{asn}".to_sym] ||= self.onlinerank?(asn)
|
22
|
+
else
|
23
|
+
return "0.0"
|
25
24
|
end
|
26
|
-
|
25
|
+
end
|
27
26
|
|
28
27
|
def self.cache
|
29
|
-
|
28
|
+
@@cache
|
30
29
|
end
|
31
30
|
|
32
31
|
private
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
33
|
+
def self.onlinerank?(addr)
|
34
|
+
resp = RestClient.post BGP_RANK_URL, { 'method' => 'cached_daily_rank', 'asn' => addr, 'date' => Date.strptime((Date.today - 1).to_s, '%Y-%m-%d').to_s }.to_json, :content_type => :json, :accept => :json
|
35
|
+
return "%.6f" % JSON.parse(resp)[4]
|
36
|
+
end
|
38
37
|
|
39
38
|
end
|
40
|
-
|
41
|
-
end
|
39
|
+
end
|
data/lib/enricher/cdn.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
module Enricher
|
2
|
+
#
|
3
|
+
# Bogons ipv4 allow for both static simple checks and for dynamic full Bogon list checks provided by Team Cymru.
|
4
|
+
#
|
5
|
+
# CDN List provided by - (23 Dec 2014) https://github.com/WPO-Foundation/webpagetest/blob/master/agent/wpthook/cdn.h
|
6
|
+
#
|
7
|
+
class CDN
|
8
|
+
|
9
|
+
CDN_PROVIDERS = [
|
10
|
+
[".akamai.net", "Akamai"],
|
11
|
+
[".akamaiedge.net", "Akamai"],
|
12
|
+
[".akamaihd.net", "Akamai"],
|
13
|
+
[".edgesuite.net", "Akamai"],
|
14
|
+
[".edgekey.net", "Akamai"],
|
15
|
+
[".srip.ne", "Akamai"],
|
16
|
+
[".akamaitechnologies.com", "Akamai"],
|
17
|
+
[".akamaitechnologies.fr", "Akamai"],
|
18
|
+
[".llnwd.net", "Limelight"],
|
19
|
+
["edgecastcdn.net", "Edgecast"],
|
20
|
+
[".systemcdn.net", "Edgecast"],
|
21
|
+
[".transactcdn.net", "Edgecast"],
|
22
|
+
[".v1cdn.net", "Edgecast"],
|
23
|
+
[".v2cdn.net", "Edgecast"],
|
24
|
+
[".v3cdn.net", "Edgecast"],
|
25
|
+
[".v4cdn.net", "Edgecast"],
|
26
|
+
[".v5cdn.net", "Edgecast"],
|
27
|
+
["hwcdn.net", "Highwinds"],
|
28
|
+
[".simplecdn.net", "Simple CDN"],
|
29
|
+
[".instacontent.net", "Mirror Image"],
|
30
|
+
[".footprint.net", "Level 3"],
|
31
|
+
[".ay1.b.yahoo.com", "Yahoo"],
|
32
|
+
[".yimg.", "Yahoo"],
|
33
|
+
[".yahooapis.com", "Yahoo"],
|
34
|
+
[".google.", "Google"],
|
35
|
+
["googlesyndication.", "Google"],
|
36
|
+
["youtube.", "Google"],
|
37
|
+
[".googleusercontent.com", "Google"],
|
38
|
+
["googlehosted.com", "Google"],
|
39
|
+
[".gstatic.com", "Google"],
|
40
|
+
[".insnw.net", "Instart Logic"],
|
41
|
+
[".inscname.net", "Instart Logic"],
|
42
|
+
[".internapcdn.net", "Internap"],
|
43
|
+
[".cloudfront.net", "Amazon CloudFront"],
|
44
|
+
[".netdna-cdn.com", "NetDNA"],
|
45
|
+
[".netdna-ssl.com", "NetDNA"],
|
46
|
+
[".netdna.com", "NetDNA"],
|
47
|
+
[".cotcdn.net", "Cotendo CDN"],
|
48
|
+
[".cachefly.net", "Cachefly"],
|
49
|
+
["bo.lt", "BO.LT"],
|
50
|
+
[".cloudflare.com", "Cloudflare"],
|
51
|
+
[".afxcdn.net", "afxcdn.net"],
|
52
|
+
[".lxdns.com", "ChinaNetCenter"],
|
53
|
+
[".att-dsa.net", "AT&T"],
|
54
|
+
[".vo.msecnd.net", "Windows Azure"],
|
55
|
+
[".voxcdn.net", "VoxCDN"],
|
56
|
+
[".bluehatnetwork.com", "Blue Hat Network"],
|
57
|
+
[".swiftcdn1.com", "SwiftCDN"],
|
58
|
+
[".cdngc.net", "CDNetworks"],
|
59
|
+
[".gccdn.net", "CDNetworks"],
|
60
|
+
[".panthercdn.com", "CDNetworks"],
|
61
|
+
[".fastly.net", "Fastly"],
|
62
|
+
[".nocookie.net", "Fastly"],
|
63
|
+
[".gslb.taobao.com", "Taobao"],
|
64
|
+
[".gslb.tbcache.com", "Alimama"],
|
65
|
+
[".mirror-image.net", "Mirror Image"],
|
66
|
+
[".yottaa.net", "Yottaa"],
|
67
|
+
[".cubecdn.net", "cubeCDN"],
|
68
|
+
[".r.cdn77.net", "CDN77"],
|
69
|
+
[".incapdns.net", "Incapsula"],
|
70
|
+
[".bitgravity.com", "BitGravity"],
|
71
|
+
[".r.worldcdn.net", "OnApp"],
|
72
|
+
[".r.worldssl.net", "OnApp"],
|
73
|
+
["tbcdn.cn", "Taobao"],
|
74
|
+
[".taobaocdn.com", "Taobao"],
|
75
|
+
[".ngenix.net", "NGENIX"],
|
76
|
+
[".pagerain.net", "PageRain"],
|
77
|
+
[".ccgslb.com", "ChinaCache"],
|
78
|
+
["cdn.sfr.net", "SFR"],
|
79
|
+
[".azioncdn.net", "Azion"],
|
80
|
+
[".azioncdn.com", "Azion"],
|
81
|
+
[".azion.net", "Azion"],
|
82
|
+
[".cdncloud.net.au", "MediaCloud"],
|
83
|
+
[".rncdn1.com", "Reflected Networks"],
|
84
|
+
[".cdnsun.net", "CDNsun"],
|
85
|
+
[".mncdn.com", "Medianova"],
|
86
|
+
[".mncdn.net", "Medianova"],
|
87
|
+
[".mncdn.org", "Medianova"],
|
88
|
+
["cdn.jsdelivr.net", "jsDelivr"],
|
89
|
+
[".nyiftw.net", "NYI FTW"],
|
90
|
+
[".nyiftw.com", "NYI FTW"],
|
91
|
+
[".resrc.it", "ReSRC.it"],
|
92
|
+
[".zenedge.net", "Zenedge"],
|
93
|
+
[".lswcdn.net", "LeaseWeb CDN"],
|
94
|
+
[".revcn.net", "Rev Software"],
|
95
|
+
[".revdn.net", "Rev Software"],
|
96
|
+
[".1e100.net", "Google"]
|
97
|
+
]
|
98
|
+
|
99
|
+
# Expects a hostname string as a variable
|
100
|
+
def self.contains?(hostname = "")
|
101
|
+
if hostname != "" then
|
102
|
+
CDN_PROVIDERS.each { |cdn_entry|
|
103
|
+
if hostname.match(cdn_entry[0]) then
|
104
|
+
return true
|
105
|
+
end
|
106
|
+
}
|
107
|
+
end
|
108
|
+
return false
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
data/lib/enricher/encoder.rb
CHANGED
@@ -1,70 +1,99 @@
|
|
1
1
|
module Enricher
|
2
|
-
|
2
|
+
|
3
3
|
class Encoder
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
|
5
|
+
## Class Methods for the Encoder..
|
6
|
+
class << self
|
7
|
+
|
8
|
+
|
9
|
+
def encode(ip)
|
10
|
+
|
11
|
+
@@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
|
12
|
+
@@geoCoder ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
|
13
|
+
@@geoCoderCity ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoLiteCity.dat")
|
14
|
+
@@res ||= Enricher::Resolver.new
|
15
|
+
|
16
|
+
@@bogon_type ||= self.bogon_type
|
17
|
+
@@bogon ||= Bogon.new(@@bogon_type)
|
18
|
+
|
19
|
+
asn = @@geoASN.asn(ip).number rescue "--"
|
20
|
+
|
21
|
+
{:ip => IPAddr.new(ip).to_i, :asn => asn, :asn_rank => Enricher::BGPRanking.rank?(asn), :geoip => @@geoCoder.country(ip).country_code3, :bogon => @@bogon.contains?(ip)}
|
22
|
+
end
|
10
23
|
|
11
|
-
|
12
|
-
|
24
|
+
def encode_online(ip)
|
25
|
+
@@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
|
26
|
+
@@geoCoder ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
|
27
|
+
@@geoCoderCity ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoLiteCity.dat")
|
28
|
+
@@res ||= Enricher::Resolver.new
|
29
|
+
|
30
|
+
@@bogon_type ||= self.bogon_type(:live)
|
31
|
+
@@bogon ||= Bogon.new(@@bogon_type)
|
32
|
+
|
33
|
+
asn = @@geoASN.asn(ip).number rescue "--"
|
34
|
+
reverse_hostname = self.reverse(ip) rescue ""
|
35
|
+
|
36
|
+
{:ip => IPAddr.new(ip).to_i, :asn => asn, :asn_rank => Enricher::BGPRanking.rank?(asn), :geoip => @@geoCoder.country(ip).country_code3, :bogon => @@bogon.contains?(ip), :reverse => reverse_hostname, :cdn => self.cdn?(reverse_hostname)}
|
37
|
+
end
|
38
|
+
|
39
|
+
def aton(a)
|
40
|
+
IPAddr.new(a).to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
def ntoa(a)
|
44
|
+
IPAddr.new(a, Socket::AF_INET).to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
def rank?(asn)
|
48
|
+
Enricher::BGPRanking.rank?(asn)
|
49
|
+
end
|
50
|
+
|
51
|
+
def bogon?(ip)
|
52
|
+
@@bogon_type ||= self.bogon_type
|
53
|
+
@@bogon ||= Bogon.new(@@bogon_type)
|
54
|
+
return @@bogon.contains?(ip)
|
55
|
+
end
|
13
56
|
|
14
|
-
|
57
|
+
def bogon_type(bogon_sym=:ipv4)
|
58
|
+
bogon_sym
|
59
|
+
end
|
60
|
+
|
61
|
+
def asn(ip)
|
62
|
+
@@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
|
63
|
+
return @@geoASN.asn(ip).number rescue "--"
|
64
|
+
end
|
15
65
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
IPAddr.new(a).to_i
|
21
|
-
end
|
66
|
+
def asn_company(ip)
|
67
|
+
@@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
|
68
|
+
return @@geoASN.asn(ip).asn rescue "--"
|
69
|
+
end
|
22
70
|
|
23
|
-
|
24
|
-
|
25
|
-
|
71
|
+
def cc3(ip)
|
72
|
+
@@geoCoder ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
|
73
|
+
return @@geoCoder.country(ip).country_code3
|
74
|
+
end
|
26
75
|
|
27
|
-
|
28
|
-
|
29
|
-
|
76
|
+
def latitude(ip)
|
77
|
+
@@geoCoderCity ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
|
78
|
+
return @@geoCoderCity.city(ip).latitude
|
79
|
+
end
|
30
80
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.bogon_type(bogon_sym=:ipv4)
|
38
|
-
bogon_sym
|
39
|
-
end
|
81
|
+
def longitude(ip)
|
82
|
+
@@geoCoderCity ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
|
83
|
+
return @@geoCoderCity.city(ip).longitude
|
84
|
+
end
|
40
85
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def self.asn_company(ip)
|
47
|
-
@@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
|
48
|
-
return @@geoASN.asn(ip).asn rescue "--"
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.cc3(ip)
|
52
|
-
@@geoCoder ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
|
53
|
-
return @@geoCoder.country(ip).country_code3
|
54
|
-
end
|
86
|
+
def reverse(ip)
|
87
|
+
@@res ||= Enricher::Resolver.new
|
88
|
+
return @@res.reverse?(ip)
|
89
|
+
end
|
55
90
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
91
|
+
def cdn?(hostname)
|
92
|
+
return Enricher::CDN.contains?(hostname)
|
93
|
+
end
|
60
94
|
|
61
|
-
def self.longitude(ip)
|
62
|
-
@@geoCoderCity ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
|
63
|
-
return @@geoCoderCity.city(ip).longitude
|
64
95
|
end
|
65
96
|
|
66
|
-
|
67
97
|
end
|
68
98
|
|
69
|
-
end
|
70
|
-
|
99
|
+
end
|
data/lib/enricher/exceptions.rb
CHANGED
@@ -0,0 +1,78 @@
|
|
1
|
+
module Enricher
|
2
|
+
#
|
3
|
+
# IPVOID ipv4 allow for dynamic checks against the list checks provided by IPVOID.
|
4
|
+
#
|
5
|
+
class IPVoid
|
6
|
+
|
7
|
+
DISABLED = true
|
8
|
+
|
9
|
+
def self.url_cache
|
10
|
+
@@url_cache
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.hash_cache
|
14
|
+
@@hash_cache
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(constructor = {})
|
18
|
+
|
19
|
+
raise DisabledClassIncluded if DISABLED
|
20
|
+
#First you need to include the correct require files
|
21
|
+
APT_KEY = "YOUR API KEY HERE"
|
22
|
+
@@hash_cache ||= Vash.new
|
23
|
+
@@url_cache ||= Vash.new
|
24
|
+
# Voliate Cache store for 43200 (12hr)
|
25
|
+
end
|
26
|
+
|
27
|
+
def junk
|
28
|
+
|
29
|
+
# RestClient scrape with Nokogiri.... (nokogiri requires libxml which is native which is not jruby compliant.. )
|
30
|
+
|
31
|
+
=begin
|
32
|
+
for ip in open(conf.iplist, "r"):
|
33
|
+
url = "http://www.ipvoid.com/scan/%s" % (ip)
|
34
|
+
emailBody = emailBody + "IP: "+ip
|
35
|
+
resp = requests.get(url)
|
36
|
+
string1 = unicodedata.normalize('NFKD', resp.text).encode('ascii','ignore')
|
37
|
+
r = string1.translate(string.maketrans("\n\t\r", " "))
|
38
|
+
blacklist = re.search(r'Blacklist Status</td><td><span.+>(\w.+)</span>', r)
|
39
|
+
if blacklist != None and blacklist.group(1) == "BLACKLISTED":
|
40
|
+
emailBody = emailBody + 'The IP is blacklisted! \n'
|
41
|
+
detection = re.search(r'Detection Ratio</td><td>(\d+ / \d+) \(<font', r)
|
42
|
+
emailBody = emailBody + 'Detection Ratio was %s \n' % detection.group(1)
|
43
|
+
detected_line = re.search(r'\s+<tr><td><img src="(.+)', r)
|
44
|
+
detected_sites = re.findall(r'Favicon" />(.+?)</td><td><img src=".+?" alt="Alert" title="Detected!".+?"nofollow" href="(.+?)" title', detected_line.group(1))
|
45
|
+
for site in detected_sites:
|
46
|
+
emailBody = emailBody + "List Name:" + site[0] + "Url: "+ site[1] + "\n\n"
|
47
|
+
else:
|
48
|
+
emailBody = emailBody + 'Not blacklisted...\n\n'
|
49
|
+
=end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def hash(hash)
|
54
|
+
#To query a hash(sha1/sha256/md5)
|
55
|
+
@@hash_cache["vt_#{hash}".to_sym] ||= Uirusu::VTFile.query_report(VT_APT_KEY, hash)
|
56
|
+
result = Uirusu::VTResult.new(hash, results)
|
57
|
+
result.to_json
|
58
|
+
end
|
59
|
+
|
60
|
+
def url(url)
|
61
|
+
|
62
|
+
# Use Base 36 for symbols
|
63
|
+
#>> "joe@momma.org".hash.to_s(36)
|
64
|
+
#=> "37zed965f04p"
|
65
|
+
#>> "http://joe@momma.org".hash.to_s(36)
|
66
|
+
#=> "vj36lppwievl"
|
67
|
+
#=> Tack on.. vt_ to url converted .hash.to_s(36)
|
68
|
+
|
69
|
+
@@url_cache["vt_#{url.hash.to_s(36)}".to_sym] ||= Uirusu::VTUrl.query_report(VT_APT_KEY, url)
|
70
|
+
|
71
|
+
result = Uirusu::VTResult.new(url, results)
|
72
|
+
result.to_json
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Enricher
|
2
|
+
#
|
3
|
+
# Bogons ipv4 allow for both static simple checks and for dynamic full Bogon list checks provided by Team Cymru.
|
4
|
+
#
|
5
|
+
# >> @@mybogon = Enricher::Bogon.new(:live)^C
|
6
|
+
# >> @@mybogon.contains?('205.166.22.1')
|
7
|
+
# => true
|
8
|
+
# >> @@mybogon = Enricher::Bogon.new(:ipv4)
|
9
|
+
# => #<Enricher::Bogon:0x00000002fb0368 @bogon=[0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4]>
|
10
|
+
# >> @@mybogon.contains?('205.166.22.1')
|
11
|
+
# => false
|
12
|
+
#
|
13
|
+
class Resolver
|
14
|
+
|
15
|
+
def initialize(nameservers = ["4.2.2.2","4.2.2.3","4.2.2.4"])
|
16
|
+
@res = Net::DNS::Resolver.new
|
17
|
+
@res.nameservers = nameservers
|
18
|
+
end
|
19
|
+
|
20
|
+
def reverse?(ip)
|
21
|
+
begin
|
22
|
+
packet = @res.search(ip)
|
23
|
+
return packet.answer[0].ptr
|
24
|
+
rescue
|
25
|
+
return ""
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/enricher/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Enricher
|
2
|
-
VERSION = '0.0.
|
3
|
-
end
|
2
|
+
VERSION = '0.0.7'
|
3
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Enricher
|
2
|
+
#
|
3
|
+
# Bogons ipv4 allow for both static simple checks and for dynamic full Bogon list checks provided by Team Cymru.
|
4
|
+
#
|
5
|
+
class VirusTotal
|
6
|
+
|
7
|
+
DISABLED = true
|
8
|
+
|
9
|
+
def self.url_cache
|
10
|
+
@@url_cache
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.hash_cache
|
14
|
+
@@hash_cache
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(constructor = {})
|
18
|
+
|
19
|
+
raise DisabledClassIncluded if DISABLED
|
20
|
+
#First you need to include the correct require files
|
21
|
+
APT_KEY = "YOUR API KEY HERE"
|
22
|
+
@@hash_cache ||= Vash.new
|
23
|
+
@@url_cache ||= Vash.new
|
24
|
+
# Voliate Cache store for 43200 (12hr)
|
25
|
+
end
|
26
|
+
|
27
|
+
def hash(hash)
|
28
|
+
#To query a hash(sha1/sha256/md5)
|
29
|
+
@@hash_cache["vt_#{hash}".to_sym] ||= Uirusu::VTFile.query_report(VT_APT_KEY, hash)
|
30
|
+
result = Uirusu::VTResult.new(hash, results)
|
31
|
+
result.to_json
|
32
|
+
end
|
33
|
+
|
34
|
+
def url(url)
|
35
|
+
|
36
|
+
# Use Base 36 for symbols
|
37
|
+
#>> "joe@momma.org".hash.to_s(36)
|
38
|
+
#=> "37zed965f04p"
|
39
|
+
#>> "http://joe@momma.org".hash.to_s(36)
|
40
|
+
#=> "vj36lppwievl"
|
41
|
+
#=> Tack on.. vt_ to url converted .hash.to_s(36)
|
42
|
+
|
43
|
+
@@url_cache["vt_#{url.hash.to_s(36)}".to_sym] ||= Uirusu::VTUrl.query_report(VT_APT_KEY, url)
|
44
|
+
|
45
|
+
result = Uirusu::VTResult.new(url, results)
|
46
|
+
result.to_json
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/vash.rb
CHANGED
metadata
CHANGED
@@ -1,83 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: enricher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- shadowbq
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: geoip
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '1.2'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '1.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: netaddr
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.5'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: net-dns
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.8'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rest-client
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- -
|
73
|
+
- - ">="
|
60
74
|
- !ruby/object:Gem::Version
|
61
75
|
version: '0'
|
62
76
|
type: :runtime
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- -
|
80
|
+
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
82
|
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: json
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
72
86
|
requirements:
|
73
|
-
- -
|
87
|
+
- - ">="
|
74
88
|
- !ruby/object:Gem::Version
|
75
89
|
version: '0'
|
76
90
|
type: :runtime
|
77
91
|
prerelease: false
|
78
92
|
version_requirements: !ruby/object:Gem::Requirement
|
79
93
|
requirements:
|
80
|
-
- -
|
94
|
+
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
83
97
|
description: Enricher, the IP and URL data enhancer
|
@@ -87,7 +101,7 @@ executables: []
|
|
87
101
|
extensions: []
|
88
102
|
extra_rdoc_files: []
|
89
103
|
files:
|
90
|
-
- .gitignore
|
104
|
+
- ".gitignore"
|
91
105
|
- Gemfile
|
92
106
|
- LICENSE
|
93
107
|
- README.md
|
@@ -96,9 +110,13 @@ files:
|
|
96
110
|
- lib/enricher.rb
|
97
111
|
- lib/enricher/bgpranking.rb
|
98
112
|
- lib/enricher/bogon.rb
|
113
|
+
- lib/enricher/cdn.rb
|
99
114
|
- lib/enricher/encoder.rb
|
100
115
|
- lib/enricher/exceptions.rb
|
116
|
+
- lib/enricher/ipvoid.rb
|
117
|
+
- lib/enricher/resolver.rb
|
101
118
|
- lib/enricher/version.rb
|
119
|
+
- lib/enricher/virustotal.rb
|
102
120
|
- lib/vash.rb
|
103
121
|
- log/enricher.log
|
104
122
|
homepage: https://github.com/shadowbq/enricher
|
@@ -111,12 +129,12 @@ require_paths:
|
|
111
129
|
- lib
|
112
130
|
required_ruby_version: !ruby/object:Gem::Requirement
|
113
131
|
requirements:
|
114
|
-
- -
|
132
|
+
- - ">="
|
115
133
|
- !ruby/object:Gem::Version
|
116
134
|
version: '0'
|
117
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
136
|
requirements:
|
119
|
-
- -
|
137
|
+
- - ">="
|
120
138
|
- !ruby/object:Gem::Version
|
121
139
|
version: '0'
|
122
140
|
requirements: []
|