project_honeypot 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ tmp
4
+
5
+ .*.swp
6
+ *~
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in project-honeypot.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 Charles Max Wood chuck@teachmetocode.com
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,87 @@
1
+ = Project Honeypot
2
+
3
+ Project Honeypot is a programmatic interface to the Project Honeypot HTTP:BL service for identifying suspicious ip addresses.
4
+
5
+ It is a handy thing to be able to identify spammers, harvesters, and other suspicious IP addresses if you're worried about who might be abusing your service.
6
+
7
+ == Requirements
8
+
9
+ This Gem requires that you have an Http:BL API key from Project Honeypot. You can get one at http://projecthhoneypot.org
10
+
11
+ == Configuration
12
+
13
+ ProjectHoneypot.configure do
14
+ @api_key = 'api_key'
15
+ @score = 42
16
+ @last_activity = 10
17
+ @offenses = [:comment_spammer, :suspicious, :harvester]
18
+ end
19
+
20
+ == Usage
21
+
22
+ require 'project_honeypot'
23
+
24
+ HTTP:BL lookups through Project Honeypot result in a Url object that gives you the risk score, last activity, and types of offenses the ip address is listed for.
25
+
26
+ The score is worse the higher it is and the last_activity is in days.
27
+
28
+
29
+ === Example #1: Suspicious IP Address
30
+
31
+ @listing = ProjectHoneypot.lookup("<ip_address>", "<api_key>")
32
+ @listing.safe?
33
+ # => false
34
+
35
+ @listing.safe?(score: 64, last_activity: 10, offenses: [:comment_spammer])
36
+ # => true
37
+
38
+ @listing.ip_address
39
+ # => "192.168.1.1"
40
+
41
+ @listing.score
42
+ # => 63
43
+
44
+ @listing.last_activity
45
+ # => 1
46
+
47
+ @listing.offenses
48
+ # => [:comment_spammer, :suspicious]
49
+
50
+ @listing.comment_spammer?
51
+ # => true
52
+
53
+ @listing.suspicious?
54
+ # => true
55
+
56
+ @listing.harvester?
57
+ # => false
58
+
59
+ @listing.search_engine?
60
+ # => false
61
+
62
+ === Example #2: Safe IP Address
63
+
64
+ @listing = ProjectHoneypot.lookup("<ip_address>")
65
+ @listing.safe?
66
+ # => true
67
+
68
+ @listing.ip_address
69
+ # => "192.168.1.1"
70
+
71
+ @listing.score
72
+ # => 0
73
+
74
+ @listing.last_activity
75
+ # => nil
76
+
77
+ @listing.offenses
78
+ # => []
79
+
80
+ @listing.comment_spammer?
81
+ # => false
82
+
83
+ @listing.suspicious?
84
+ # => false
85
+
86
+ @listing.harvester?
87
+ # => false
@@ -0,0 +1,29 @@
1
+ require 'net/dns'
2
+ require "project_honeypot/url"
3
+ require "project_honeypot/base"
4
+ require "project_honeypot/rack/header"
5
+ require "project_honeypot/rack/forbidden"
6
+
7
+ module ProjectHoneypot
8
+ class << self
9
+ attr_accessor :api_key, :score, :last_activity, :offenses
10
+
11
+ def api_key
12
+ raise "ProjectHoneypot really needs its api_key set to work" unless @api_key
13
+ @api_key
14
+ end
15
+
16
+ def configure(&block)
17
+ class_eval(&block)
18
+ end
19
+ end
20
+
21
+ def self.lookup(url, api_key=nil)
22
+ api_key ||= ProjectHoneypot.api_key
23
+
24
+ raise ArgumentError, 'Must specify an API key' unless api_key
25
+
26
+ searcher = Base.new(api_key)
27
+ searcher.lookup(url)
28
+ end
29
+ end
@@ -0,0 +1,25 @@
1
+ module ProjectHoneypot
2
+ class Base
3
+ def initialize(api_key)
4
+ @api_key = api_key
5
+ end
6
+
7
+ def lookup(ip_address)
8
+ ip_address = url_to_ip(ip_address)
9
+ reversed_ip = ip_address.split(".").reverse.join(".")
10
+ honeypot_score = extract_ip_address(Net::DNS::Resolver.start("#{@api_key}.#{reversed_ip}.dnsbl.httpbl.org"))
11
+ Url.new(ip_address, honeypot_score)
12
+ end
13
+
14
+ private
15
+
16
+ def url_to_ip(url)
17
+ return url if url.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/)
18
+ extract_ip_address(Net::DNS::Resolver.start(url))
19
+ end
20
+
21
+ def extract_ip_address(dns_response)
22
+ dns_response.answer.first.to_s.split.last
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ module ProjectHoneypot::Rack
2
+ class Forbidden
3
+ def initialize(app, options={})
4
+ @app = app
5
+
6
+ raise ArgumentError, 'Must specify an API key' unless options[:api_key]
7
+ ProjectHoneypot.api_key = options[:api_key]
8
+ end
9
+
10
+ def call(env)
11
+ request = ::Rack::Request.new(env)
12
+ url = ProjectHoneypot.lookup(request.ip)
13
+
14
+ if url.safe?
15
+ @app.call(request.env)
16
+ else
17
+ [403, {"Content-Type" => "text/html"}, ["Forbidden"]]
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ module ProjectHoneypot::Rack
2
+ class Header
3
+ def initialize(app, options={})
4
+ @app = app
5
+
6
+ raise ArgumentError, 'Must specify an API key' unless options[:api_key]
7
+ ProjectHoneypot.api_key = options[:api_key]
8
+ end
9
+
10
+ def call(env)
11
+ request = ::Rack::Request.new(env)
12
+ url = ProjectHoneypot.lookup(request.ip)
13
+
14
+ env['PROJECT_HONEYPOT_SAFE'] = url.safe?
15
+
16
+ @app.call(request.env)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,98 @@
1
+ module ProjectHoneypot
2
+ class Url
3
+ SEARCH_ENGINES = %w(
4
+ Undocumented
5
+ AltaVista
6
+ Ask
7
+ Baidu
8
+ Excite
9
+ Google
10
+ Looksmart
11
+ Lycos
12
+ MSN
13
+ Yahoo
14
+ Cuil
15
+ InfoSeek
16
+ Miscellaneous
17
+ )
18
+
19
+ attr_reader :ip_address, :last_activity, :score, :offenses, :search_engine
20
+ def initialize(ip_address, honeypot_response)
21
+ @ip_address = ip_address
22
+ @safe = honeypot_response.nil?
23
+ process_score(honeypot_response)
24
+ end
25
+
26
+ def safe?(hash = {})
27
+ score = hash[:score] || ProjectHoneypot.score
28
+ last_activity = hash[:last_activity] || ProjectHoneypot.last_activity
29
+
30
+ forbidden_offenses = hash[:offenses] ||
31
+ ProjectHoneypot.offenses ||
32
+ [:comment_spammer, :harvester, :suspicious]
33
+
34
+ detected_offenses = forbidden_offenses & @offenses
35
+
36
+ @safe ||
37
+ detected_offenses.length == 0 ||
38
+ !(
39
+ last_activity.nil? && score.nil? ||
40
+ !score.nil? && self.score >= score ||
41
+ !last_activity.nil? && self.last_activity >= last_activity
42
+ )
43
+ end
44
+
45
+ def search_engine?
46
+ @offenses.include?(:search_engine)
47
+ end
48
+
49
+ def comment_spammer?
50
+ @offenses.include?(:comment_spammer)
51
+ end
52
+
53
+ def harvester?
54
+ @offenses.include?(:harvester)
55
+ end
56
+
57
+ def suspicious?
58
+ @offenses.include?(:suspicious)
59
+ end
60
+
61
+ private
62
+
63
+ def process_score(honeypot_response)
64
+ if honeypot_response.nil?
65
+ @last_activity = nil
66
+ @score = 0
67
+ @offenses = []
68
+ else
69
+ hp_array = honeypot_response.split(".")
70
+
71
+ if hp_array[3].to_i == 0
72
+ # search engine
73
+ @last_activity = nil
74
+ @score = 0
75
+ @offenses = [:search_engine]
76
+ @search_engine = (hp_array[2].to_i < SEARCH_ENGINES.length ?
77
+ SEARCH_ENGINES[hp_array[2].to_i] :
78
+ SEARCH_ENGINES[0])
79
+ else
80
+ @last_activity = hp_array[1].to_i
81
+ @score = hp_array[2].to_i
82
+ @offenses = set_offenses(hp_array[3])
83
+ end
84
+ end
85
+ end
86
+
87
+ def set_offenses(offense_code)
88
+ offense_code = offense_code.to_i
89
+ offenses = []
90
+ offenses << :comment_spammer if offense_code/4 == 1
91
+ offense_code = offense_code % 4
92
+ offenses << :harvester if offense_code/2 == 1
93
+ offense_code = offense_code % 2
94
+ offenses << :suspicious if offense_code == 1
95
+ offenses
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,3 @@
1
+ module ProjectHoneypot
2
+ VERSION = "0.3.1"
3
+ end
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'project_honeypot/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{project_honeypot}
8
+ s.version = ProjectHoneypot::VERSION
9
+ s.authors = ["Charles Max Wood", "Guillaume DOTT"]
10
+ s.email = ["chuck@teachmetocode.com", "guillaume+github@dott.fr"]
11
+ s.summary = %q{Project-Honeypot provides a programatic interface to the Project Honeypot services.}
12
+ s.description = %q{Project-Honeypot provides a programatic interface to the Project Honeypot services. It can be used to identify spammers, bogus commenters, and harvesters. You will need a FREE api key from http://projecthoneypot.org}
13
+ s.homepage = "https://github.com/gdott9/project_honeypot"
14
+
15
+ s.files = `git ls-files`.split($/)
16
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ s.add_development_dependency 'rspec'
20
+ s.add_development_dependency 'flexmock'
21
+
22
+ s.add_runtime_dependency 'net-dns', '~> 0.7.1'
23
+ end
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ describe ProjectHoneypot::Base do
4
+ describe "with honeypot response" do
5
+ let(:base) { ProjectHoneypot::Base.new("abcdefghijklmnop") }
6
+ before(:each) do
7
+ flexmock(Net::DNS::Resolver, :start => flexmock("answer", :answer => ["somedomain.httpbl.org A Name 127.1.63.5"]))
8
+ end
9
+
10
+ it "returns a Url object" do
11
+ url = base.lookup("127.10.10.5")
12
+ url.should be_a ProjectHoneypot::Url
13
+ url.last_activity.should == 1
14
+ url.score.should == 63
15
+ end
16
+
17
+ it "looks up non-ip addresses" do
18
+ url = base.lookup("iamspam.com")
19
+ Net::DNS::Resolver.should_receive(:start).with("iamspam.com")
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,9 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "rspec"
4
+ require "flexmock"
5
+ require File.dirname(__FILE__) + "/../lib/project_honeypot"
6
+
7
+ RSpec.configure do |config|
8
+ config.mock_with :flexmock
9
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ describe ProjectHoneypot::Url do
4
+ describe "with honeypot response" do
5
+ let(:url) { ProjectHoneypot::Url.new("127.0.0.1", "127.1.63.3") }
6
+
7
+ it "is safe" do
8
+ url.should_not be_safe
9
+
10
+ url.safe?(score: 63).should be_false
11
+ url.safe?(score: 64).should be_true
12
+
13
+ url.safe?(last_activity: 1).should be_false
14
+ url.safe?(last_activity: 2).should be_true
15
+
16
+ url.safe?(last_activity: 2, score: 64).should be_true
17
+ url.safe?(last_activity: 1, score: 64).should be_false
18
+ url.safe?(last_activity: 2, score: 63).should be_false
19
+
20
+ url.safe?(offenses: [:comment_spammer]).should be_true
21
+ url.safe?(offenses: [:suspicious, :comment_spammer]).should be_false
22
+ end
23
+
24
+ it "has the correct latest activity" do
25
+ url.last_activity.should == 1
26
+ end
27
+
28
+ it "has the correct score" do
29
+ url.score.should == 63
30
+ end
31
+
32
+ it "has the correct offenses" do
33
+ url.offenses.should include(:suspicious)
34
+ url.offenses.should include(:harvester)
35
+ url.offenses.should_not include(:comment_spammer)
36
+ url.should be_suspicious
37
+ url.should be_harvester
38
+ url.should_not be_comment_spammer
39
+ end
40
+ end
41
+
42
+ describe "with search engine honeypot response" do
43
+ subject { ProjectHoneypot::Url.new("127.0.0.1", "127.0.9.0") }
44
+ it { should be_safe }
45
+ it { should be_search_engine }
46
+ end
47
+
48
+ describe "with nil honeypot response" do
49
+ subject { ProjectHoneypot::Url.new("127.0.0.1", nil) }
50
+ it { should be_safe }
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: project_honeypot
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Charles Max Wood
9
+ - Guillaume DOTT
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-01-20 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: flexmock
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: net-dns
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.7.1
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 0.7.1
63
+ description: Project-Honeypot provides a programatic interface to the Project Honeypot
64
+ services. It can be used to identify spammers, bogus commenters, and harvesters.
65
+ You will need a FREE api key from http://projecthoneypot.org
66
+ email:
67
+ - chuck@teachmetocode.com
68
+ - guillaume+github@dott.fr
69
+ executables: []
70
+ extensions: []
71
+ extra_rdoc_files: []
72
+ files:
73
+ - .gitignore
74
+ - Gemfile
75
+ - MIT-LICENSE
76
+ - README.rdoc
77
+ - lib/project_honeypot.rb
78
+ - lib/project_honeypot/base.rb
79
+ - lib/project_honeypot/rack/forbidden.rb
80
+ - lib/project_honeypot/rack/header.rb
81
+ - lib/project_honeypot/url.rb
82
+ - lib/project_honeypot/version.rb
83
+ - project_honeypot.gemspec
84
+ - spec/base_spec.rb
85
+ - spec/spec_helper.rb
86
+ - spec/url_spec.rb
87
+ homepage: https://github.com/gdott9/project_honeypot
88
+ licenses: []
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 1.8.24
108
+ signing_key:
109
+ specification_version: 3
110
+ summary: Project-Honeypot provides a programatic interface to the Project Honeypot
111
+ services.
112
+ test_files:
113
+ - spec/base_spec.rb
114
+ - spec/spec_helper.rb
115
+ - spec/url_spec.rb