enricher 0.0.2 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba7623f738d308075b0b07cf6365f83f3f11053b
4
- data.tar.gz: 040c1a1349e741d87da53fa7c435841ef8995c34
3
+ metadata.gz: 7f87c647a272e4dd0b39b45b5e3691fdf3f8fa0e
4
+ data.tar.gz: 6fc0c075c318729355ee93f56c9982714d39bfad
5
5
  SHA512:
6
- metadata.gz: 36748a53b45b8ba519090621481ebbeb078d098f42a1fc39dd1bc45483cbab4bfe7a8be3e7360ed531717e51f750f6cf49d347e8b61d7f49b94e52e4b876d33b
7
- data.tar.gz: 81e992ba9f680437405ee6369a3c6ae171660684454351c4464133487306c4f678e855efdbaeaffe937bc39ff13a114b98e8a0a98279b40ed571ec51351ceed4
6
+ metadata.gz: d883c35af6c5d1542aaade6b622f82b5c3044a78633fba1abc250a00c4851c53b2e6aef4c895b84fca7044657c1e7c16dbac34843d17b11bea9ebdb9c685510a
7
+ data.tar.gz: d88bca4c18a7c68e74490492a8763d5e5b83f300c257d6cf421e289152ed98d161a28e243bff86d2e2084cbca3c63f1df4afbdb4443f150b14e3624a886d6f9b
data/enricher.gemspec CHANGED
@@ -18,5 +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 "rest-client"
22
+ gem.add_dependency "json"
21
23
 
22
24
  end
data/lib/enricher.rb CHANGED
@@ -4,20 +4,28 @@ require 'ipaddr'
4
4
  require 'logger'
5
5
  require 'rubygems'
6
6
  require 'tempfile'
7
+ require 'net/http'
8
+ require 'date'
7
9
 
8
10
  # RubyGems
9
11
 
10
12
  require 'json'
11
13
  require 'geoip'
12
14
  require 'netaddr'
15
+ require 'rest-client'
16
+
13
17
 
14
18
  # Internal
15
19
  module Enricher
16
20
  $:.unshift(File.dirname(__FILE__))
21
+
22
+ require 'vash'
17
23
  require 'enricher/version'
24
+ require 'enricher/exceptions'
18
25
  require 'enricher/bogon'
26
+ require 'enricher/bgpranking'
19
27
  require 'enricher/encoder'
20
-
28
+
21
29
  DEBUG=false
22
30
  LOGGING=false
23
31
 
@@ -0,0 +1,41 @@
1
+ module Enricher
2
+ #
3
+ # BGP dynamic ASN ranking checks provided by circl.lu.
4
+ #
5
+ # Results cached locally for 12hr.
6
+ #
7
+ # > r = RestClient.post "http://bgpranking.circl.lu/json", { 'method' => 'cached_daily_rank', 'asn' => 198540, 'date' => '2014-02-23' }.to_json, :content_type => :json, :accept => :json
8
+ # => "[198540, "ELAN-AS Przedsiebiorstwo Uslug Specjalistycznych ELAN mgr inz. Andrzej Niechcial", "2014-02-23", "global", 1.0496093750000002]"
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
+ # => "[198540, "ELAN-AS Przedsiebiorstwo Uslug Specjalistycznych ELAN mgr inz. Andrzej Niechcial", "2014-02-24", "global", 1.09609375]"
11
+ # >> a = JSON.parse(r)
12
+
13
+ class BGPRanking
14
+
15
+ BGP_RANK_URL = "http://bgpranking.circl.lu/json"
16
+
17
+ def self.rank?(addr)
18
+ asn = addr.strip[/[0-9]+/]
19
+ if asn =~ /[0-9]+/
20
+ @@cache ||= Vash.new
21
+ # Voliate Cache store for 43200 (12hr)
22
+ @@cache["asn#{asn}".to_sym] ||= self.onlinerank?(asn)
23
+ else
24
+ return "0.0"
25
+ end
26
+ end
27
+
28
+ def self.cache
29
+ @@cache
30
+ end
31
+
32
+ private
33
+
34
+ def self.onlinerank?(addr)
35
+ 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
36
+ return "%.6f" % JSON.parse(resp)[4]
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -1,4 +1,15 @@
1
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
+ #
2
13
  class Bogon
3
14
 
4
15
  BOGONIPV4 = ['0.0.0.0/8',
@@ -16,22 +27,36 @@ module Enricher
16
27
  '224.0.0.0/4',
17
28
  '240.0.0.0/4']
18
29
 
30
+ LIST_URL = "http://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt"
31
+
19
32
  def initialize(bogon)
20
- if bogon == :bogonipv4
33
+ if bogon == :ipv4
21
34
  @bogon = BOGONIPV4.collect do |cidr|
22
35
  NetAddr::CIDR.create(cidr)
23
36
  end
37
+ elsif bogon == :live
38
+ @bogon = []
39
+ Net::HTTP.get(URI.parse(LIST_URL)).each_line do |line|
40
+ if line !~ /^#/
41
+ @bogon << NetAddr::CIDR.create(line.strip)
42
+ end
43
+ end
24
44
  else
25
- raise BogonSetUndefined, "Only the :bogonipv4 aggregated set is defined at this time"
45
+ raise BogonSetUndefined, "Only the :ipv4 aggregated set, and :live via http is defined at this time. illegal use of #{bogon}"
26
46
  end
47
+
48
+ @bogon
27
49
  end
28
50
 
29
51
  def contains?(ip)
30
- @bogon.each do |net|
31
- return true if net.contains?(ip)
32
- end
52
+ @bogon.each { |net| return true if net.contains?(ip) }
33
53
  return false
34
54
  end
35
-
55
+
56
+ def addresses
57
+ @bogon ||= self.initialize
58
+ end
59
+
36
60
  end
61
+
37
62
  end
@@ -1,6 +1,20 @@
1
1
  module Enricher
2
2
 
3
3
  class Encoder
4
+
5
+ def self.encode(ip)
6
+
7
+ @@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
8
+ @@geoCoder ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
9
+ @@geoCoderCity ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoLiteCity.dat")
10
+
11
+ @@bogon_type ||= self.bogon_type
12
+ @@bogon ||= Bogon.new(@@bogon_type)
13
+
14
+ asn = @@geoASN.asn(ip).number rescue "--"
15
+
16
+ {:ip => IPAddr.new(ip).to_i, :asn => asn, :asn_rank => Enricher::BGPRanking.rank?(asn), :geoip => @@geoCoder.country(ip).country_code3, :bogon => @@bogon.contains?(ip)}
17
+ end
4
18
 
5
19
  def self.aton(a)
6
20
  IPAddr.new(a).to_i
@@ -9,21 +23,21 @@ module Enricher
9
23
  def self.ntoa(a)
10
24
  IPAddr.new(a, Socket::AF_INET).to_s
11
25
  end
12
-
13
- def self.encode(ip)
14
- @@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
15
- @@geoCoder ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIP.dat")
16
- @@geoCoderCity ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoLiteCity.dat")
17
- @@bogon ||= Bogon.new(:bogonipv4)
18
- asn = @@geoASN.asn(ip).number rescue "--"
19
- {:ip => IPAddr.new(ip).to_i, :asn => asn, :geoip => @@geoCoder.country(ip).country_code3, :bogon => @@bogon.contains?(ip)}
26
+
27
+ def self.rank?(asn)
28
+ Enricher::BGPRanking.rank?(asn)
20
29
  end
21
-
30
+
22
31
  def self.bogon?(ip)
23
- @@bogon ||= Bogon.new(:bogonipv4)
32
+ @@bogon_type ||= self.bogon_type
33
+ @@bogon ||= Bogon.new(@@bogon_type)
24
34
  return @@bogon.contains?(ip)
25
35
  end
26
36
 
37
+ def self.bogon_type(bogon_sym=:ipv4)
38
+ bogon_sym
39
+ end
40
+
27
41
  def self.asn(ip)
28
42
  @@geoASN ||= GeoIP.new("#{Enricher::DATA_PATH}/GeoIPASNum.dat")
29
43
  return @@geoASN.asn(ip).number rescue "--"
@@ -0,0 +1,5 @@
1
+ module Enricher
2
+
3
+ class BogonSetUndefined < StandardError; end
4
+
5
+ end
@@ -1,3 +1,3 @@
1
1
  module Enricher
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.4'
3
3
  end
data/lib/vash.rb ADDED
@@ -0,0 +1,110 @@
1
+ #############################################################################
2
+ # Class: Vash (Ruby Volatile Hash)
3
+ # Hash that returns values only for a short time. This is useful as a cache
4
+ # where I/O is involved. The primary goal of this object is to reduce I/O
5
+ # access and due to the nature of I/O being slower then memory, you should also
6
+ # see a gain in quicker response times.
7
+ #
8
+ # For example, if Person.first found the first person from the database & cache
9
+ # was an instance of Vash then the following would only contact the database for
10
+ # the first iteration:
11
+ #
12
+ # > cache = Vash.new
13
+ # > 1000.times {cache[:person] ||= Person.first}
14
+ #
15
+ # However if you did the following immediately following that command it would
16
+ # hit the database again:
17
+ #
18
+ # > sleep 43201
19
+ # > cache[:person] ||= Person.first
20
+ #
21
+ # The reason is that there is a default Time-To-Live of 43200 seconds. You can
22
+ # also set a custom TTL of 10 seconds like so:
23
+ #
24
+ # > cache[:person, 10] = Person.first
25
+ #
26
+ # The Vash object will forget any answer that is requested after the specified
27
+ # TTL. It is a good idea to manually clean things up from time to time because
28
+ # it is possible that you'll cache data but never again access it and therefor
29
+ # it will stay in memory after the TTL has expired. To clean up the Vash object,
30
+ # call the method: cleanup!
31
+ #
32
+ # > sleep 11 # At this point the prior person ttl will be expired
33
+ # # but the person key and value will still exist.
34
+ # > cache # This will still show the the entire set of keys
35
+ # # regardless of the TTL, the :person will still exist
36
+ # > cache.cleanup! # All of the TTL's will be inspected and the expired
37
+ # # :person key will be deleted.
38
+ #
39
+ # The cleanup must be manually called because the purpose of the Vash is to
40
+ # lessen needless I/O calls and gain speed not to slow it down with regular
41
+ # maintenance.
42
+ class Vash < Hash
43
+ def initialize(constructor = {})
44
+ @register ||= {} # remembers expiration time of every key
45
+ if constructor.is_a?(Hash)
46
+ super()
47
+ merge(constructor)
48
+ else
49
+ super(constructor)
50
+ end
51
+ end
52
+
53
+ alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
54
+ alias_method :regular_reader, :[] unless method_defined?(:regular_reader)
55
+
56
+ def [](key)
57
+ sterilize(key)
58
+ clear(key) if expired?(key)
59
+ regular_reader(key)
60
+ end
61
+
62
+ def []=(key, *args)
63
+ # a little bit o variable hacking to support (h[key, ttl] = value), which will come
64
+ # accross as (key, [ttl, value]) whereas (h[key]=value) comes accross as (key, [value])
65
+ if args.length == 2
66
+ value, ttl = args[1], args[0]
67
+ elsif args.length == 1
68
+ value, ttl = args[0], 43200
69
+ else
70
+ raise ArgumentError, "Wrong number of arguments, expected 2 or 3, received: #{args.length+1}\n"+
71
+ "Example Usage: volatile_hash[:key]=value OR volatile_hash[:key, ttl]=value"
72
+ end
73
+ sterilize(key)
74
+ ttl(key, ttl)
75
+ regular_writer(key, value)
76
+ end
77
+
78
+ def merge(hsh)
79
+ hsh.map {|key,value| self[sterile(key)] = hsh[key]}
80
+ self
81
+ end
82
+
83
+ def cleanup!
84
+ now = Time.now.to_i
85
+ @register.map {|k,v| clear(k) if v < now}
86
+ end
87
+
88
+ def clear(key)
89
+ sterilize(key)
90
+ @register.delete key
91
+ self.delete key
92
+ end
93
+
94
+ private
95
+ def expired?(key)
96
+ Time.now.to_i > @register[key].to_i
97
+ end
98
+
99
+ def ttl(key, secs=43200)
100
+ @register[key] = Time.now.to_i + secs.to_i
101
+ end
102
+
103
+ def sterile(key)
104
+ String === key ? key.chomp('!').chomp('=') : key.to_s.chomp('!').chomp('=').to_sym
105
+ end
106
+
107
+ def sterilize(key)
108
+ key = sterile(key)
109
+ end
110
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enricher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - shadowbq
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-24 00:00:00.000000000 Z
11
+ date: 2014-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rest-client
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  description: Enricher, the IP and URL data enhancer
56
84
  email:
57
85
  - shadowbq@gmail.com
@@ -66,9 +94,12 @@ files:
66
94
  - Rakefile
67
95
  - enricher.gemspec
68
96
  - lib/enricher.rb
97
+ - lib/enricher/bgpranking.rb
69
98
  - lib/enricher/bogon.rb
70
99
  - lib/enricher/encoder.rb
100
+ - lib/enricher/exceptions.rb
71
101
  - lib/enricher/version.rb
102
+ - lib/vash.rb
72
103
  - log/enricher.log
73
104
  homepage: https://github.com/shadowbq/enricher
74
105
  licenses: