unxf 1.0.0 → 2.0.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.
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +0 -5
- data/README +41 -6
- data/lib/unxf.rb +37 -16
- data/test/test_unxf.rb +30 -5
- data/unxf.gemspec +1 -1
- metadata +7 -8
data/GIT-VERSION-GEN
CHANGED
data/GNUmakefile
CHANGED
data/README
CHANGED
@@ -1,14 +1,49 @@
|
|
1
1
|
= UnXF - Un-X-Forward* the Rack environment
|
2
2
|
|
3
|
-
|
4
|
-
with the
|
5
|
-
|
3
|
+
Rack middleware to remove "HTTP_X_FORWARDED_FOR" in the Rack environment and
|
4
|
+
replace "REMOTE_ADDR" with the value of the original client address.
|
5
|
+
|
6
|
+
This uses the "rpatricia" RubyGem to filter out spoofed requests from
|
7
|
+
clients outside your LAN. The list of trusted address defaults to
|
8
|
+
private LAN addresses defined RFC 1918 and those belonging to localhost.
|
9
|
+
|
10
|
+
This will also read "HTTP_X_FORWARDED_PROTO" and set "rack.url_scheme"
|
11
|
+
to "https" if the "X-Forwarded-Proto" header is set properly and sent
|
12
|
+
from a trusted address chain.
|
13
|
+
|
14
|
+
== Install
|
15
|
+
|
16
|
+
If you use RubyGems:
|
17
|
+
|
18
|
+
gem install unxf
|
19
|
+
|
20
|
+
You will need a C compiler and Ruby development headers to install the
|
21
|
+
"rpatricia" RubyGem if it is not already installed.
|
6
22
|
|
7
23
|
=== Hacking
|
8
24
|
|
25
|
+
You can get the latest source via git from the following locations:
|
26
|
+
|
9
27
|
* git clone git://bogomips.org/unxf.git
|
28
|
+
* git clone git://repo.or.cz/unxf.git (mirror)
|
29
|
+
|
30
|
+
You may browse the code from the web and download the latest snapshot
|
31
|
+
tarballs here:
|
32
|
+
|
33
|
+
* http://bogomips.org/unxf.git (cgit)
|
34
|
+
* http://repo.or.cz/w/unxf.git (gitweb)
|
35
|
+
|
36
|
+
Inline patches (from "git format-patch") to the
|
37
|
+
{mailing list}[mailto:unxf@librelist.org] are
|
38
|
+
preferred because they allow code review and comments in the reply to
|
39
|
+
the patch.
|
40
|
+
|
41
|
+
We will adhere to mostly the same conventions for patch submissions as
|
42
|
+
git itself. See the Documentation/SubmittingPatches document
|
43
|
+
distributed with git on on patch submission guidelines to follow. Just
|
44
|
+
don't email the git mailing list or maintainer with unxf patches.
|
10
45
|
|
11
|
-
|
46
|
+
== Contact
|
12
47
|
|
13
|
-
|
14
|
-
|
48
|
+
All feedback (bug reports, user/development discussion, patches, pull
|
49
|
+
requests) go to the mailing list: mailto:unxf@librelist.org
|
data/lib/unxf.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
require 'rpatricia'
|
3
3
|
|
4
|
+
# Rack middleware to remove "HTTP_X_FORWARDED_FOR" in the Rack environment and
|
5
|
+
# replace "REMOTE_ADDR" with the value of the original client address.
|
4
6
|
class UnXF
|
5
7
|
# :stopdoc:
|
6
8
|
# reduce garbage overhead by using constant strings
|
@@ -17,6 +19,19 @@ class UnXF
|
|
17
19
|
# localhost addresses (127.0.0.0/8)
|
18
20
|
LOCALHOST = %w(127.0.0.0/8)
|
19
21
|
|
22
|
+
# In your Rack config.ru:
|
23
|
+
#
|
24
|
+
# use UnXF
|
25
|
+
#
|
26
|
+
# If you do not want to trust any hosts other than "0.6.6.6",
|
27
|
+
# you may only specify one host to trust:
|
28
|
+
#
|
29
|
+
# use UnXF, "0.6.6.6"
|
30
|
+
#
|
31
|
+
# If you want to trust "0.6.6.6" in addition to the default set of hosts:
|
32
|
+
#
|
33
|
+
# use UnXF, [ :RFC_1918, :LOCALHOST, "0.6.6.6" ]
|
34
|
+
#
|
20
35
|
def initialize(app, trusted = [:RFC_1918, :LOCALHOST])
|
21
36
|
@app = app
|
22
37
|
@trusted = Patricia.new
|
@@ -26,7 +41,15 @@ class UnXF
|
|
26
41
|
end
|
27
42
|
end
|
28
43
|
|
29
|
-
|
44
|
+
# Rack entry point
|
45
|
+
def call(env) # :nodoc:
|
46
|
+
unxf!(env) || @app.call(env)
|
47
|
+
end
|
48
|
+
|
49
|
+
# returns +nil+ on success and a Rack response triplet on failure
|
50
|
+
# This allows existing applications to use UnXF without putting it
|
51
|
+
# into the middleware stack (to avoid increasing stack depth and GC time)
|
52
|
+
def unxf!(env)
|
30
53
|
if xff_str = env.delete(HTTP_X_FORWARDED_FOR)
|
31
54
|
xff = xff_str.split(/\s*,\s*/)
|
32
55
|
addr = env[REMOTE_ADDR]
|
@@ -35,33 +58,31 @@ class UnXF
|
|
35
58
|
addr = tmp
|
36
59
|
end
|
37
60
|
rescue ArgumentError
|
38
|
-
return
|
61
|
+
return on_broken_addr(env, xff_str)
|
39
62
|
end
|
40
63
|
|
41
|
-
env[REMOTE_ADDR] = addr
|
42
|
-
|
43
64
|
# it's stupid to have https at any point other than the first
|
44
65
|
# proxy in the chain, so we don't support that
|
45
66
|
if xff.empty?
|
67
|
+
env[REMOTE_ADDR] = addr
|
46
68
|
env.delete(HTTP_X_FORWARDED_PROTO) =~ /\Ahttps\b/ and
|
47
69
|
env[RACK_URL_SCHEME] = HTTPS
|
48
70
|
else
|
49
|
-
return
|
71
|
+
return on_untrusted_addr(env, xff_str)
|
50
72
|
end
|
51
73
|
end
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
|
77
|
+
# Our default action on a broken address is to just fall back to calling
|
78
|
+
# the app without modifying the env
|
79
|
+
def on_broken_addr(env, xff_str)
|
52
80
|
@app.call(env)
|
53
81
|
end
|
54
82
|
|
55
|
-
# Our default action on
|
56
|
-
# the
|
57
|
-
|
58
|
-
|
59
|
-
# be sure to inspect xff_str to escape it, control characters may be
|
60
|
-
# present in the HTTP headers may appear in the header value and
|
61
|
-
# used to exploit anyone who opens the log file. nginx doesn't
|
62
|
-
# filter/reject control characters, nor does Mongrel...
|
63
|
-
env["rack.logger"].error(
|
64
|
-
"bad XFF #{xff_str.inspect} from #{env[REMOTE_ADDR]}")
|
65
|
-
[ 400, [ %w(Content-Length 0), %w(Content-Type text/html) ], [] ]
|
83
|
+
# Our default action on an untrusted address is to just fall back to calling
|
84
|
+
# the app without modifying the env
|
85
|
+
def on_untrusted_addr(env, xff_str)
|
86
|
+
@app.call(env)
|
66
87
|
end
|
67
88
|
end
|
data/test/test_unxf.rb
CHANGED
@@ -46,7 +46,8 @@ class TestUnXF < Test::Unit::TestCase
|
|
46
46
|
"REMOTE_ADDR" => "227.0.0.1",
|
47
47
|
}
|
48
48
|
r = req.get("http://example.com/", @req.merge(env))
|
49
|
-
assert_equal
|
49
|
+
assert_equal "227.0.0.1", @env["REMOTE_ADDR"]
|
50
|
+
assert_equal r.status.to_i, 200
|
50
51
|
end
|
51
52
|
|
52
53
|
def test_trusted_chain
|
@@ -68,8 +69,8 @@ class TestUnXF < Test::Unit::TestCase
|
|
68
69
|
"REMOTE_ADDR" => "127.0.0.1",
|
69
70
|
}
|
70
71
|
r = req.get("http://example.com/", @req.merge(env))
|
71
|
-
assert_equal
|
72
|
-
|
72
|
+
assert_equal "127.0.0.1", @env["REMOTE_ADDR"]
|
73
|
+
assert_equal r.status.to_i, 200
|
73
74
|
end
|
74
75
|
|
75
76
|
def test_spoofed_null_safe
|
@@ -79,7 +80,31 @@ class TestUnXF < Test::Unit::TestCase
|
|
79
80
|
"REMOTE_ADDR" => "127.0.0.1",
|
80
81
|
}
|
81
82
|
r = req.get("http://example.com/", @req.merge(env))
|
82
|
-
assert_equal
|
83
|
-
|
83
|
+
assert_equal "127.0.0.1", @env["REMOTE_ADDR"]
|
84
|
+
assert_equal r.status.to_i, 200
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_more_trust
|
88
|
+
req = Rack::MockRequest.new(UnXF.new(@app, [ :LOCALHOST, "0.6.6.6" ]))
|
89
|
+
env = {
|
90
|
+
"HTTP_X_FORWARDED_FOR" => "1.6.6.6,0.6.6.6",
|
91
|
+
"REMOTE_ADDR" => "127.0.0.1",
|
92
|
+
}
|
93
|
+
r = req.get("http://example.com/", @req.merge(env))
|
94
|
+
assert_equal r.status.to_i, 200
|
95
|
+
assert_equal "1.6.6.6", @env["REMOTE_ADDR"]
|
96
|
+
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_one_trusted
|
100
|
+
req = Rack::MockRequest.new(UnXF.new(@app, "0.6.6.6"))
|
101
|
+
env = {
|
102
|
+
"HTTP_X_FORWARDED_FOR" => "1.6.6.6",
|
103
|
+
"REMOTE_ADDR" => "0.6.6.6",
|
104
|
+
}
|
105
|
+
r = req.get("http://example.com/", @req.merge(env))
|
106
|
+
assert_equal r.status.to_i, 200
|
107
|
+
assert_equal "1.6.6.6", @env["REMOTE_ADDR"]
|
108
|
+
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
84
109
|
end
|
85
110
|
end
|
data/unxf.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.test_files = test_files
|
22
22
|
s.add_dependency('rack', '~> 1.1')
|
23
23
|
s.add_development_dependency('wrongdoc', '~> 1.5')
|
24
|
-
s.
|
24
|
+
s.add_dependency('rpatricia', '~> 0.07')
|
25
25
|
|
26
26
|
# s.license = %w(GPL) # disabled for compatibility with older RubyGems
|
27
27
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unxf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
7
|
+
- 2
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
version:
|
10
|
+
version: 2.0.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- UnXF hackers
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-26 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rack
|
@@ -60,12 +60,11 @@ dependencies:
|
|
60
60
|
- 0
|
61
61
|
- 7
|
62
62
|
version: "0.07"
|
63
|
-
type: :
|
63
|
+
type: :runtime
|
64
64
|
version_requirements: *id003
|
65
65
|
description: |-
|
66
|
-
|
67
|
-
with the
|
68
|
-
chain is provided).
|
66
|
+
Rack middleware to remove "HTTP_X_FORWARDED_FOR" in the Rack environment and
|
67
|
+
replace "REMOTE_ADDR" with the value of the original client address.
|
69
68
|
email: unxf@librelist.org
|
70
69
|
executables: []
|
71
70
|
|