icaprb-filter 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0837e275231b622dabdb5b873dc7e241bad263ee
4
+ data.tar.gz: 29a4e6006735b354efdd595ba16957323248451b
5
+ SHA512:
6
+ metadata.gz: 3623f5d18b8c7d5699cb0f45e9cadd76b0fde8e4a5fbd08bfc151766151a5f91078136108fa465eb9eb3bb63d82ed70d1440911e93dc6d91852634f1367780b4
7
+ data.tar.gz: 5877b36f5a61248bc9a9aa4486d5b4df86a57b00cee9fabb0f5092cc44e8e81e1f793b4875325d58c40cc86fb3168751d1e70b19e34f57b2e0cd404b3eb317f2
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /html/
11
+ /.idea/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in icaprb-filter.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2016, Fabian Franz
2
+ Copyright (c) 2016, Markus Petz
3
+ Copyright (c) 2016, Fabian Mayer
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without modification,
7
+ are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice,
10
+ this list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation and/or
14
+ other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
17
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
19
+ SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
23
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
@@ -0,0 +1,68 @@
1
+ # ICAPrb::Filter
2
+
3
+ ICAPrb::Filter is a content filter based on ICAPrb::Server. The goal is
4
+ to develop a framework which allows to create any custom filtering of
5
+ any content you would not like to have in your network. This could be
6
+ ads, trackers, malware, adult content and so on.
7
+
8
+ The way to defile rules should feel like configuring a firewall ruleset.
9
+
10
+ Plug ins are automatically detected when they reside in the correct
11
+ namespace and are available to use.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'icaprb-filter'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install icaprb-filter
28
+
29
+ ## Usage
30
+
31
+ First of all, you will need a server which is serving your content
32
+ filter.
33
+
34
+ ```ruby
35
+ require "icaprb/server"
36
+ require "icaprb/filter"
37
+
38
+ s = ICAPServer.new
39
+ # url: echo ist der Service - rechts ist der zu verwendende Service
40
+ s.services['filter'] = ICAPrb::Server::FilterService.new('/path/to/filterconfig')
41
+ s.run
42
+ ```
43
+ You will need to replace the path by the path you use on your local
44
+ machine.
45
+
46
+ Next you will have to write your ruleset:
47
+
48
+ ```ruby
49
+ request_filter do
50
+ end
51
+
52
+ response_filter do
53
+ block 'Block pages may contain samples',content_includes: ['sample']
54
+ block 'Block invalid domains', url_contains: ['.invalid']
55
+ block 'Block hashes of bad file', :check_hashes => ['~/hashes']
56
+ end
57
+ ```
58
+
59
+ ## Development
60
+
61
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
62
+
63
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
64
+
65
+ ## Contributing
66
+
67
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fabianfrz/icaprb-filter.
68
+
@@ -0,0 +1,22 @@
1
+ +ICAPrb::Filter+ is the filter component of +ICAPrb+.
2
+ It aims to be able to filter content based on some matches as well as being able to use plug ins to modify content.
3
+
4
+ Modify Content
5
+
6
+ This feature is useful to remove some specific parts of your traffic.
7
+ So you can remove some scripts (for example trackers and ads) based on theire content instead of the url as an URL can simply be changed.
8
+ So the blocket content can be removed cleanly instead of having a whitespace somewhere on websites.
9
+ The filter framework also supports actions like passing or blocking content.
10
+
11
+ The supported methods are
12
+ * pass:: passes the current state to the client
13
+ (in case the client supports 204 responses and the traffic has not been modified - it will be generated, otherwise the full data
14
+ is sent to the client).
15
+ * block:: sends a message that the content has been blocked
16
+ * modify:: calls a plug in to modify the content depending on the return value the modified flag may be set which makes it impossible to
17
+ create a 204 response. For large files it is a good idea to have a pass rule generating 204 responses before any rule of this
18
+ type to reduce network traffic (and increase performance).
19
+ * custom_action:: reserved for plug ins which should interact like a rule type (for example writing files out of the service for
20
+ analysis. For example put it into a queue to test it inside a sandbox to detect malware)
21
+
22
+
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require 'rdoc/task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
8
+
9
+ RDoc::Task.new do |rdoc|
10
+ rdoc.main = 'README.rdoc'
11
+ rdoc.rdoc_files.include('README.rdoc', 'lib/**/*.rb')
12
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "icaprb/filter"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,40 @@
1
+ #
2
+ require "bundler/setup"
3
+ require "icaprb/server"
4
+ require "icaprb/filter"
5
+ require 'logger'
6
+ include ICAPrb::Server
7
+
8
+ trap('SIGINT') { exit! 0 }
9
+ ########################################################################
10
+ # DIFFERENT WAYS TO RUN THE SERVER #
11
+ ########################################################################
12
+
13
+ # normal socket
14
+ s = ICAPServer.new
15
+ # puts 'Server is running on port 1344. Press CTRL+C to exit...'
16
+
17
+ # squid v4 variant
18
+ #options = {secure: true,
19
+ # certificate: '../cert.pem',
20
+ # key: '../key.pem',
21
+ # tls_socket: true}
22
+ #s = ICAPServer.new('localhost',11344,options)
23
+ # puts 'Server is running on port 11344. Press CTRL+C to exit...'
24
+
25
+ # rfc 3507 variant
26
+ #options = {secure: true,
27
+ # certificate: '../cert.pem',
28
+ # key: '../key.pem',
29
+ # tls_socket: false}
30
+ #s = ICAPServer.new('localhost',1344,options)
31
+ puts 'Server is running on port 1344. Press CTRL+C to exit...'
32
+
33
+ ########################################################################
34
+ s.logger.level = Logger::DEBUG
35
+ # TIMEOUT:
36
+ # timeout_in_seconds = 10
37
+ # s.services['filter'] = ICAPrb::Server::FilterService.new('~/conf/conf.conf',timeout_in_seconds)
38
+ s.services['filter'] = ICAPrb::Server::FilterService.new('~/conf/conf.conf')
39
+
40
+ s.run
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'icaprb/filter/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'icaprb-filter'
8
+ spec.version = ICAPrb::Filter::VERSION
9
+ spec.authors = ['Fabian Franz']
10
+ spec.email = ['fabian.franz@students.fh-hagenberg.at']
11
+
12
+ spec.summary = %q{Filter framework for ICAPrb-server. Does not work standalone. This gem includes
13
+ a framework to create a content filter which allows to filter content instead of only the
14
+ urls. It is extensible by plug ins. For example it can be used to enforce your companies
15
+ network usage policies at the proxy.}
16
+ spec.homepage = 'https://github.com/fabianfrz/ICAPrb-Filter'
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = 'exe'
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_dependency 'nokogiri', '~> 1.6', '>= 1.6.7'
24
+ spec.add_dependency 'uirusu' # Virustotal public api
25
+ spec.add_dependency 'pdf-reader', '~> 1.4'
26
+ spec.add_dependency 'chunky_png'
27
+ spec.add_dependency 'icaprb-server'
28
+ spec.add_dependency 'rest-client'
29
+ # spec.add_dependency 'ruby-filemagic', '~> 0.7.1'
30
+ spec.add_development_dependency 'bundler', '~> 1.11'
31
+ spec.add_development_dependency 'rake'
32
+ spec.add_development_dependency 'rspec', '~> 3.0'
33
+ end
@@ -0,0 +1,189 @@
1
+ require "icaprb/filter/version"
2
+ # All filter types
3
+ require "icaprb/filter/solution"
4
+ require "icaprb/filter/service"
5
+ require 'logger'
6
+
7
+ # ICAPrb
8
+ module ICAPrb
9
+ # Filter module
10
+ module Filter
11
+ # Exception which is thrown when the configuration file is invalid
12
+ class ConfigurationLoadError < StandardError
13
+ end
14
+ # Response mod filters+plugins
15
+ @resp_mod = nil
16
+ # Temporary during reading
17
+ @temp_reps_mod = nil
18
+ # Request mod filters+plugins
19
+ @req_mod = nil
20
+ # Temporary during reading
21
+ @temp_req_mod = nil
22
+
23
+ # set the configuration mode to request filter so the rules will know that they are request filter rules.
24
+ # It takes a block which is executed while the filter_type is set up.
25
+ def self.request_filter
26
+ @filter_type = :request_mod
27
+ yield
28
+ @filter_type = nil
29
+ end
30
+
31
+ # set the configuration mode to response filter so the rules will know that they are response filter rules.
32
+ # It takes a block which is executed while the filter_type is set up.
33
+ def self.response_filter
34
+ @filter_type = :response_mod
35
+ yield
36
+ @filter_type = nil
37
+ end
38
+
39
+ # returns the filters
40
+ def self.get_filters
41
+ return @filters
42
+ end
43
+
44
+ # creates a new block rule with the parameters
45
+ # +description+:: description of the rule, so it can be logged and the admin can troubleshoot the ruleset.
46
+ # +action+:: do something
47
+ #
48
+ # raises a ConfigurationLoadError if it is called outside of request_filter or response_filter
49
+ def self.block(description, action)
50
+ puts "============================="
51
+ puts "BLOCK: #{description}, ACTION NAME: #{action.keys.first}"
52
+ if @filter_type == :request_mod
53
+ puts "TYPE: REQUEST"
54
+ elsif @filter_type == :response_mod
55
+ puts "TYPE: RESPONSE"
56
+ else
57
+ raise ConfigurationLoadError, "used param 'block' without a filter type"
58
+ end
59
+ # Check if action name exists and create it
60
+ found_name = false
61
+ @valid_filters.each { |filter|
62
+ if filter[:name].to_s == action.keys.first.to_s
63
+ found_name = true
64
+ new_filter = {:name => action.keys.first,
65
+ :object => filter[:class].new(@filter_type, action[action.keys.first]),
66
+ :description => description}
67
+ if @filter_type == :request_mod
68
+ @temp_req_mod << new_filter
69
+ elsif @filter_type == :response_mod
70
+ @temp_resp_mod << new_filter
71
+ end
72
+ break
73
+ end
74
+ }
75
+ unless found_name
76
+ raise ConfigurationLoadError, "Unknown filter type '" + action.keys.first.to_s + "' "
77
+ end
78
+ end
79
+ # Load a modifiying rule
80
+ # +description+:: Description of the rule
81
+ # +action+:: Name of the plugin to use
82
+ # +match+:: Parameters for the plugin
83
+ def self.modify(description, action, match={})
84
+ puts "============================="
85
+ puts "MODIFY/CUSTOM: #{description}, ACTION NAME: #{action.to_s}"
86
+ if @filter_type == :request_mod
87
+ puts "TYPE: REQUEST"
88
+ elsif @filter_type == :response_mod
89
+ puts "TYPE: RESPONSE"
90
+ else
91
+ raise ConfigurationLoadError, "used param 'block' without a filter type"
92
+ end
93
+ # Check if action name exists and create it
94
+ found_name = false
95
+ @valid_plugins.each { |plugin|
96
+ if plugin[:name].to_s == action.to_s
97
+ found_name = true
98
+ # Check if given plugin supports filter type
99
+ unless plugin[:class]::MODES.include? @filter_type
100
+ raise ConfigurationLoadError, 'Plugin ' + action.to_s + ' does not support filter type'
101
+ end
102
+ new_plugin = {:name => action,
103
+ :object => plugin[:class].new(@filter_type, match[match.keys.first]),
104
+ :description => description}
105
+ if @filter_type == :request_mod
106
+ @temp_req_mod << new_plugin
107
+ elsif @filter_type == :response_mod
108
+ @temp_resp_mod << new_plugin
109
+ end
110
+ end
111
+ }
112
+ unless found_name
113
+ raise ConfigurationLoadError, 'Unknown plugin type'
114
+ end
115
+ end
116
+ # Custom action, alias for modify
117
+ # The reason for it being a simple alias is that it may not modify
118
+ # its content, for example a virustotal scan takes too long
119
+ # so we pass it through anyway, but the scan results is saved in a log file
120
+ # May modify the content, but default behaviour should be that it doesn't
121
+ # +description+:: Description of the function
122
+ # +action+:: Name of the action in the configuration file
123
+ # +match+:: Attributes
124
+ def self.custom_action(description, action, match={})
125
+ self.modify(description, action, match)
126
+ end
127
+
128
+ # Placeholder if user wants to write pass, doesn't do anything
129
+ # For future expansion: Add conditionals to the rules ==> rewrite pass
130
+ def self.pass()
131
+ end
132
+ # Delete current filters
133
+ # Simple reset for tests of configuration files
134
+ def self.delete_filters()
135
+ @req_mod = nil
136
+ @resp_mod = nil
137
+ @temp_req_mod = nil
138
+ @temp_resp_mod = nil
139
+ @filter_type = nil
140
+ end
141
+
142
+ # Try to load the configureation file from path.
143
+ # If everything works as expected, the new filter rules are set,
144
+ # otherwise an error is raised if the configuration file is invalid and no previous configuration is available
145
+ # which would lead into an empty config or the loading will fail with an error on the log.
146
+ # +path+:: Path to the configuration file
147
+ def self.load_filters(path)
148
+ # puts are required because no logger is given when the service is created
149
+ # Setup objects to be written into
150
+ puts 'Trying to read new configuration'
151
+ # Set valid plugins and filters, has to done for each reload
152
+ @valid_filters = ICAPrb::Filters.get_filters
153
+ @valid_plugins = ICAPrb::Filters.get_plugins
154
+ # Execute file (we trust the user blindly, assuming that the configuration file is protected sufficiently)
155
+ @temp_resp_mod = []
156
+ @temp_req_mod = []
157
+ begin
158
+ eval(File.read File.expand_path(path))
159
+ rescue StandardError => error
160
+ error_info = "#{error.message} #{error.backtrace}"
161
+ # Initial info couldn't be loaded, shutting down filter framework
162
+ if @resp_mod == nil or @req_mod == nil
163
+ puts "Initial configuration couldn't be loaded: #{error_info}"
164
+ # Non recoverable
165
+ raise ConfigurationLoadError, "Initial configuration couldn't be loaded: #{error_info}"
166
+ else
167
+ puts "Error when reloading the configuration, configuration wasn't changed: #{error_info}"
168
+ # Don't throw an error, we still retain the old configuration
169
+ @temp_resp_mod = nil
170
+ @temp_req_mod = nil
171
+ @filter_type = nil
172
+ return
173
+ end
174
+ end
175
+ # Write data into variables (writing it beforehand is dangerous because the incomplete object may be used
176
+ # for new requests, this allows to reload the configuration during runtime)
177
+ @req_mod = @temp_req_mod
178
+ @resp_mod = @temp_resp_mod
179
+ puts 'Finished reading filter configuration'
180
+ return @req_mod, @resp_mod
181
+ end
182
+
183
+ # Set logger for filter
184
+ # +logger+:: Logger object
185
+ def self.set_logger(logger)
186
+ @logger = logger
187
+ end
188
+ end
189
+ end