rack-dedos 0.5.1 → 0.7.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/CHANGELOG.md +18 -0
- data/README.md +37 -3
- data/lib/rack/dedos/filters/base.rb +27 -8
- data/lib/rack/dedos/filters/country.rb +5 -5
- data/lib/rack/dedos/filters/user_agent.rb +2 -2
- data/lib/rack/dedos/version.rb +1 -1
- metadata +6 -62
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d666dc81c74730f8c69f0cbf84a171aa39b0f94f393b4538cf8c81c244dd8fe1
|
|
4
|
+
data.tar.gz: 6b22c751e94241988408cc38c63606204180c2f212c3416292c273b95dcdc2bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e211d5dcbb8a2d3422e24638317080db89e54367e8e542ecd720e87dec6a0fca95ae1ff332a2e15d72e1b2bf0f2fa72456aadc895078d1121de2cffd5661e24c
|
|
7
|
+
data.tar.gz: dc1dce126f9177c30174edcb3d232435c8ad5c40142af5bc708c391380f0313cd94c8dcea7cab5cb41d2f5e24574357112ce6be04f2771420cb0ce24ce3d183f
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
Nothing so far
|
|
4
4
|
|
|
5
|
+
## 0.7.0
|
|
6
|
+
|
|
7
|
+
### Breaking changes
|
|
8
|
+
* Change format of country code details in log
|
|
9
|
+
|
|
10
|
+
### Fixes
|
|
11
|
+
* Drop keyword arguments for Rack compatibility
|
|
12
|
+
* Fix collision with Rack::Logger
|
|
13
|
+
|
|
14
|
+
## 0.6.0 (yanked)
|
|
15
|
+
|
|
16
|
+
### Breaking changes
|
|
17
|
+
* Log to STDOUT (instead of STDERR) by default
|
|
18
|
+
|
|
19
|
+
### Additions
|
|
20
|
+
* Suppport custom loggers
|
|
21
|
+
* Optionally log request headers
|
|
22
|
+
|
|
5
23
|
## 0.5.1
|
|
6
24
|
|
|
7
25
|
### Fixes
|
data/README.md
CHANGED
|
@@ -122,6 +122,33 @@ use Rack::Dedos,
|
|
|
122
122
|
text: "Temporary Server Error"
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
### Log
|
|
126
|
+
|
|
127
|
+
By default, blocked request are logged as info to `$stdout` such as:
|
|
128
|
+
|
|
129
|
+
> rack-dedos: request /foobar from 1.2.3.4 blocked by Rack::Dedos::Filters::Country: CN
|
|
130
|
+
|
|
131
|
+
The level of details may differ by filter, however, if you want to drill down and log additional request headers, you can configure which headers to include as follows:
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
use Rack::Dedos,
|
|
135
|
+
headers: ['HTTP_USER_AGENT', 'HTTP_REFERER']
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
You can direct the log stream to any logger object you wish:
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
use Rack::Dedos,
|
|
142
|
+
logger: Logger.new('/var/log/rack-dedos.log')
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Or disable logging entirely:
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
use Rack::Dedos,
|
|
149
|
+
logger: Logger.new(nil)
|
|
150
|
+
```
|
|
151
|
+
|
|
125
152
|
## Filters
|
|
126
153
|
|
|
127
154
|
By default, all filters described below are applied. You can exclude certain filters:
|
|
@@ -199,12 +226,19 @@ cd rack-dedos
|
|
|
199
226
|
git submodule update --init
|
|
200
227
|
```
|
|
201
228
|
|
|
202
|
-
To install the development dependencies
|
|
229
|
+
To install only the development dependencies:
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
bundle install
|
|
233
|
+
bundle exec rake # run the tests once
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
To install the development dependencies and development tools (such as guard):
|
|
203
237
|
|
|
204
238
|
```
|
|
239
|
+
bundle config set --local with toolbox
|
|
205
240
|
bundle install
|
|
206
|
-
bundle exec
|
|
207
|
-
bundle exec guard # run tests whenever files are modified
|
|
241
|
+
bundle exec guard # run the tests whenever files are modified
|
|
208
242
|
```
|
|
209
243
|
|
|
210
244
|
You're welcome to [submit issues](https://github.com/svoop/rack-dedos/issues) and contribute code by [forking the project and submitting pull requests](https://docs.github.com/en/get-started/quickstart/fork-a-repo).
|
|
@@ -1,27 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'logger'
|
|
4
|
+
|
|
3
5
|
module Rack
|
|
4
6
|
module Dedos
|
|
5
7
|
module Filters
|
|
6
8
|
class Base
|
|
7
9
|
|
|
8
10
|
DEFAULT_OPTIONS = {
|
|
11
|
+
logger: nil,
|
|
9
12
|
only_paths: [],
|
|
10
13
|
except_paths: [],
|
|
11
14
|
status: 403,
|
|
12
|
-
text: 'Forbidden (Temporarily Blocked by Rules)'
|
|
15
|
+
text: 'Forbidden (Temporarily Blocked by Rules)',
|
|
16
|
+
headers: []
|
|
13
17
|
}.freeze
|
|
14
18
|
|
|
15
|
-
attr_reader :app
|
|
16
|
-
attr_reader :options
|
|
17
|
-
attr_reader :details
|
|
19
|
+
attr_reader :app, :options, :details
|
|
18
20
|
|
|
19
21
|
# @param app [#call]
|
|
20
22
|
# @param options [Hash{Symbol => Object}]
|
|
21
|
-
def initialize(app, options
|
|
23
|
+
def initialize(app, options={})
|
|
22
24
|
@app = app
|
|
23
25
|
@options = DEFAULT_OPTIONS.merge(options)
|
|
24
|
-
@details =
|
|
26
|
+
@details = {}
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def call(env)
|
|
@@ -30,8 +32,10 @@ module Rack
|
|
|
30
32
|
if !apply?(request) || allowed?(request, ip)
|
|
31
33
|
app.call(env)
|
|
32
34
|
else
|
|
33
|
-
message = "
|
|
34
|
-
|
|
35
|
+
message = ["request #{request.path} from #{ip} blocked by #{name}"]
|
|
36
|
+
message += details_list
|
|
37
|
+
message += headers_list(request)
|
|
38
|
+
logger.info(message.join(' '))
|
|
35
39
|
[options[:status], { 'Content-Type' => 'text/plain' }, [options[:text]]]
|
|
36
40
|
end
|
|
37
41
|
end
|
|
@@ -42,6 +46,10 @@ module Rack
|
|
|
42
46
|
Rack::Dedos.config
|
|
43
47
|
end
|
|
44
48
|
|
|
49
|
+
def logger
|
|
50
|
+
@logger ||= options[:logger] || ::Logger.new($stdout, progname: 'rack-dedos')
|
|
51
|
+
end
|
|
52
|
+
|
|
45
53
|
def apply?(request)
|
|
46
54
|
return false if @options[:except_paths].any? { request.path.match? _1 }
|
|
47
55
|
return true if @options[:only_paths].none?
|
|
@@ -71,6 +79,17 @@ module Rack
|
|
|
71
79
|
end
|
|
72
80
|
end
|
|
73
81
|
|
|
82
|
+
def details_list
|
|
83
|
+
details.map do |key, value|
|
|
84
|
+
"#{key.upcase}=#{value.inspect}"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def headers_list(request)
|
|
89
|
+
options[:headers].map do |header|
|
|
90
|
+
"#{header.upcase}=#{request.get_header(header).inspect}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
74
93
|
end
|
|
75
94
|
end
|
|
76
95
|
end
|
|
@@ -14,7 +14,7 @@ module Rack
|
|
|
14
14
|
# @option options [String] :maxmind_db_file MaxMind database file
|
|
15
15
|
# @option options [Symbol, Array<Symbol>] :allowed_countries ISO 3166-1 alpha 2
|
|
16
16
|
# @option options [Symbol, Array<Symbol>] :denied_countries ISO 3166-1 alpha 2
|
|
17
|
-
def initialize(
|
|
17
|
+
def initialize(...)
|
|
18
18
|
super
|
|
19
19
|
@maxmind_db_file = options[:maxmind_db_file] or fail "MaxMind database file not set"
|
|
20
20
|
@allowed = case
|
|
@@ -26,14 +26,14 @@ module Rack
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def allowed?(request, ip)
|
|
29
|
-
if
|
|
30
|
-
country_code =
|
|
31
|
-
@countries.include?(country_code) ? @allowed : !@allowed
|
|
29
|
+
if db = maxmind_db&.get(ip)
|
|
30
|
+
details[:country_code] = db.dig('country', 'iso_code').to_sym
|
|
31
|
+
@countries.include?(details[:country_code]) ? @allowed : !@allowed
|
|
32
32
|
else # not found in database
|
|
33
33
|
true
|
|
34
34
|
end
|
|
35
35
|
rescue => error
|
|
36
|
-
|
|
36
|
+
logger.error("request from #{ip} allowed due to error: #{error.message}")
|
|
37
37
|
true
|
|
38
38
|
end
|
|
39
39
|
|
|
@@ -12,7 +12,7 @@ module Rack
|
|
|
12
12
|
# @option options [String] :cache_url URL of the cache backend
|
|
13
13
|
# @option options [Integer] :cache_period how long to retain cached IP
|
|
14
14
|
# addresses in seconds (default: 900)
|
|
15
|
-
def initialize(
|
|
15
|
+
def initialize(...)
|
|
16
16
|
super
|
|
17
17
|
@cache_url = options[:cache_url] or fail "cache URL not set"
|
|
18
18
|
@cache_period = options[:cache_period] || 900
|
|
@@ -34,7 +34,7 @@ module Rack
|
|
|
34
34
|
false
|
|
35
35
|
end
|
|
36
36
|
rescue => error
|
|
37
|
-
|
|
37
|
+
logger.error("request from #{ip} allowed due to error: #{error.message}")
|
|
38
38
|
true
|
|
39
39
|
end
|
|
40
40
|
|
data/lib/rack/dedos/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack-dedos
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sven Schwyn
|
|
@@ -24,13 +24,13 @@ dependencies:
|
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: 2.2.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
|
-
name:
|
|
27
|
+
name: logger
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '0'
|
|
33
|
-
type: :
|
|
33
|
+
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
@@ -38,7 +38,7 @@ dependencies:
|
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '0'
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
|
-
name:
|
|
41
|
+
name: rake
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - ">="
|
|
@@ -52,7 +52,7 @@ dependencies:
|
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '0'
|
|
54
54
|
- !ruby/object:Gem::Dependency
|
|
55
|
-
name:
|
|
55
|
+
name: redis
|
|
56
56
|
requirement: !ruby/object:Gem::Requirement
|
|
57
57
|
requirements:
|
|
58
58
|
- - ">="
|
|
@@ -66,7 +66,7 @@ dependencies:
|
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '0'
|
|
68
68
|
- !ruby/object:Gem::Dependency
|
|
69
|
-
name:
|
|
69
|
+
name: maxmind-db
|
|
70
70
|
requirement: !ruby/object:Gem::Requirement
|
|
71
71
|
requirements:
|
|
72
72
|
- - ">="
|
|
@@ -107,62 +107,6 @@ dependencies:
|
|
|
107
107
|
- - ">="
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
109
|
version: '0'
|
|
110
|
-
- !ruby/object:Gem::Dependency
|
|
111
|
-
name: minitest-flash
|
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
|
113
|
-
requirements:
|
|
114
|
-
- - ">="
|
|
115
|
-
- !ruby/object:Gem::Version
|
|
116
|
-
version: '0'
|
|
117
|
-
type: :development
|
|
118
|
-
prerelease: false
|
|
119
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
-
requirements:
|
|
121
|
-
- - ">="
|
|
122
|
-
- !ruby/object:Gem::Version
|
|
123
|
-
version: '0'
|
|
124
|
-
- !ruby/object:Gem::Dependency
|
|
125
|
-
name: guard
|
|
126
|
-
requirement: !ruby/object:Gem::Requirement
|
|
127
|
-
requirements:
|
|
128
|
-
- - ">="
|
|
129
|
-
- !ruby/object:Gem::Version
|
|
130
|
-
version: '0'
|
|
131
|
-
type: :development
|
|
132
|
-
prerelease: false
|
|
133
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
-
requirements:
|
|
135
|
-
- - ">="
|
|
136
|
-
- !ruby/object:Gem::Version
|
|
137
|
-
version: '0'
|
|
138
|
-
- !ruby/object:Gem::Dependency
|
|
139
|
-
name: guard-minitest
|
|
140
|
-
requirement: !ruby/object:Gem::Requirement
|
|
141
|
-
requirements:
|
|
142
|
-
- - ">="
|
|
143
|
-
- !ruby/object:Gem::Version
|
|
144
|
-
version: '0'
|
|
145
|
-
type: :development
|
|
146
|
-
prerelease: false
|
|
147
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
-
requirements:
|
|
149
|
-
- - ">="
|
|
150
|
-
- !ruby/object:Gem::Version
|
|
151
|
-
version: '0'
|
|
152
|
-
- !ruby/object:Gem::Dependency
|
|
153
|
-
name: yard
|
|
154
|
-
requirement: !ruby/object:Gem::Requirement
|
|
155
|
-
requirements:
|
|
156
|
-
- - ">="
|
|
157
|
-
- !ruby/object:Gem::Version
|
|
158
|
-
version: '0'
|
|
159
|
-
type: :development
|
|
160
|
-
prerelease: false
|
|
161
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
162
|
-
requirements:
|
|
163
|
-
- - ">="
|
|
164
|
-
- !ruby/object:Gem::Version
|
|
165
|
-
version: '0'
|
|
166
110
|
description: |
|
|
167
111
|
Somewhat more radical filters designed to decimate malicious requests during
|
|
168
112
|
a denial-of-service (DoS) attack by chopping their connection well before
|