unxf 2.0.0 → 2.0.0.2.g32d0
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/lib/unxf.rb +18 -6
- data/test/test_unxf.rb +38 -0
- metadata +16 -9
data/lib/unxf.rb
CHANGED
|
@@ -10,15 +10,20 @@ class UnXF
|
|
|
10
10
|
HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
|
|
11
11
|
HTTP_X_FORWARDED_PROTO = "HTTP_X_FORWARDED_PROTO"
|
|
12
12
|
RACK_URL_SCHEME = "rack.url_scheme".freeze
|
|
13
|
+
UNXF_FOR = "unxf.for".freeze
|
|
14
|
+
UNXF_PROTO = "unxf.proto".freeze
|
|
13
15
|
HTTPS = "https"
|
|
14
16
|
# :startdoc:
|
|
15
17
|
|
|
16
18
|
# local LAN addresses described in RFC 1918
|
|
17
19
|
RFC_1918 = %w(10.0.0.0/8 172.16.0.0/12 192.168.0.0/16)
|
|
18
20
|
|
|
19
|
-
# localhost addresses (127.0.0.0/8)
|
|
21
|
+
# IPv4 localhost addresses (127.0.0.0/8)
|
|
20
22
|
LOCALHOST = %w(127.0.0.0/8)
|
|
21
23
|
|
|
24
|
+
# IPv6 localhost address (::1/128)
|
|
25
|
+
LOCALHOST6 = %w(::1/128)
|
|
26
|
+
|
|
22
27
|
# In your Rack config.ru:
|
|
23
28
|
#
|
|
24
29
|
# use UnXF
|
|
@@ -32,12 +37,15 @@ class UnXF
|
|
|
32
37
|
#
|
|
33
38
|
# use UnXF, [ :RFC_1918, :LOCALHOST, "0.6.6.6" ]
|
|
34
39
|
#
|
|
35
|
-
def initialize(app, trusted = [:RFC_1918, :LOCALHOST])
|
|
40
|
+
def initialize(app, trusted = [:RFC_1918, :LOCALHOST, :LOCALHOST6])
|
|
36
41
|
@app = app
|
|
37
42
|
@trusted = Patricia.new
|
|
43
|
+
@trusted6 = Patricia.new(:AF_INET6)
|
|
38
44
|
Array(trusted).each do |mask|
|
|
39
45
|
mask = UnXF.const_get(mask) if Symbol === mask
|
|
40
|
-
Array(mask).each
|
|
46
|
+
Array(mask).each do |prefix|
|
|
47
|
+
(/:/ =~ prefix ? @trusted6 : @trusted).add(prefix, true)
|
|
48
|
+
end
|
|
41
49
|
end
|
|
42
50
|
end
|
|
43
51
|
|
|
@@ -51,10 +59,12 @@ class UnXF
|
|
|
51
59
|
# into the middleware stack (to avoid increasing stack depth and GC time)
|
|
52
60
|
def unxf!(env)
|
|
53
61
|
if xff_str = env.delete(HTTP_X_FORWARDED_FOR)
|
|
62
|
+
env[UNXF_FOR] = xff_str
|
|
54
63
|
xff = xff_str.split(/\s*,\s*/)
|
|
55
64
|
addr = env[REMOTE_ADDR]
|
|
56
65
|
begin
|
|
57
|
-
while @trusted.include?(addr) &&
|
|
66
|
+
while (/:/ =~ addr ? @trusted6 : @trusted).include?(addr) &&
|
|
67
|
+
tmp = xff.pop
|
|
58
68
|
addr = tmp
|
|
59
69
|
end
|
|
60
70
|
rescue ArgumentError
|
|
@@ -65,8 +75,10 @@ class UnXF
|
|
|
65
75
|
# proxy in the chain, so we don't support that
|
|
66
76
|
if xff.empty?
|
|
67
77
|
env[REMOTE_ADDR] = addr
|
|
68
|
-
env.delete(HTTP_X_FORWARDED_PROTO)
|
|
69
|
-
|
|
78
|
+
if xfp = env.delete(HTTP_X_FORWARDED_PROTO)
|
|
79
|
+
env[UNXF_PROTO] = xfp
|
|
80
|
+
/\Ahttps\b/ =~ xfp and env[RACK_URL_SCHEME] = HTTPS
|
|
81
|
+
end
|
|
70
82
|
else
|
|
71
83
|
return on_untrusted_addr(env, xff_str)
|
|
72
84
|
end
|
data/test/test_unxf.rb
CHANGED
|
@@ -25,6 +25,36 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
25
25
|
assert_equal 200, r.status.to_i
|
|
26
26
|
assert_equal "0.6.6.6", @env["REMOTE_ADDR"]
|
|
27
27
|
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
|
28
|
+
assert_equal "0.6.6.6", @env["unxf.for"]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_single_proxy_https
|
|
32
|
+
req = Rack::MockRequest.new(UnXF.new(@app))
|
|
33
|
+
env = {
|
|
34
|
+
"HTTP_X_FORWARDED_FOR" => "0.6.6.6",
|
|
35
|
+
"HTTP_X_FORWARDED_PROTO" => "https",
|
|
36
|
+
"REMOTE_ADDR" => "127.0.0.1",
|
|
37
|
+
}
|
|
38
|
+
r = req.get("http://example.com/", @req.merge(env))
|
|
39
|
+
assert_equal 200, r.status.to_i
|
|
40
|
+
assert_equal "0.6.6.6", @env["REMOTE_ADDR"]
|
|
41
|
+
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
|
42
|
+
assert_equal "0.6.6.6", @env["unxf.for"]
|
|
43
|
+
assert_equal "https", @env["unxf.proto"]
|
|
44
|
+
assert_equal "https", @env["rack.url_scheme"]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_ipv6_localhost
|
|
48
|
+
req = Rack::MockRequest.new(UnXF.new(@app))
|
|
49
|
+
env = {
|
|
50
|
+
"HTTP_X_FORWARDED_FOR" => "2600:3c01::f03c:91ff:fe96:f5d6",
|
|
51
|
+
"REMOTE_ADDR" => "::1",
|
|
52
|
+
}
|
|
53
|
+
r = req.get("http://example.com/", @req.merge(env))
|
|
54
|
+
assert_equal 200, r.status.to_i
|
|
55
|
+
assert_equal "2600:3c01::f03c:91ff:fe96:f5d6", @env["REMOTE_ADDR"]
|
|
56
|
+
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
|
57
|
+
assert_equal "2600:3c01::f03c:91ff:fe96:f5d6", @env["unxf.for"]
|
|
28
58
|
end
|
|
29
59
|
|
|
30
60
|
def test_multiple_proxies
|
|
@@ -37,6 +67,7 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
37
67
|
assert_equal "0.6.6.6", @env["REMOTE_ADDR"]
|
|
38
68
|
assert_equal 200, r.status.to_i
|
|
39
69
|
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
|
70
|
+
assert_equal "0.6.6.6,192.168.1.1", @env["unxf.for"]
|
|
40
71
|
end
|
|
41
72
|
|
|
42
73
|
def test_spoofed
|
|
@@ -48,6 +79,7 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
48
79
|
r = req.get("http://example.com/", @req.merge(env))
|
|
49
80
|
assert_equal "227.0.0.1", @env["REMOTE_ADDR"]
|
|
50
81
|
assert_equal r.status.to_i, 200
|
|
82
|
+
assert_equal "0.6.6.6", @env["unxf.for"]
|
|
51
83
|
end
|
|
52
84
|
|
|
53
85
|
def test_trusted_chain
|
|
@@ -60,6 +92,7 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
60
92
|
assert_equal 200, r.status.to_i
|
|
61
93
|
assert_equal "0.6.6.6", @env["REMOTE_ADDR"]
|
|
62
94
|
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
|
95
|
+
assert_equal "0.6.6.6,192.168.0.1", @env["unxf.for"]
|
|
63
96
|
end
|
|
64
97
|
|
|
65
98
|
def test_spoofed_in_chain
|
|
@@ -71,6 +104,7 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
71
104
|
r = req.get("http://example.com/", @req.merge(env))
|
|
72
105
|
assert_equal "127.0.0.1", @env["REMOTE_ADDR"]
|
|
73
106
|
assert_equal r.status.to_i, 200
|
|
107
|
+
assert_equal "0.6.6.6,8.8.8.8", @env["unxf.for"]
|
|
74
108
|
end
|
|
75
109
|
|
|
76
110
|
def test_spoofed_null_safe
|
|
@@ -82,6 +116,7 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
82
116
|
r = req.get("http://example.com/", @req.merge(env))
|
|
83
117
|
assert_equal "127.0.0.1", @env["REMOTE_ADDR"]
|
|
84
118
|
assert_equal r.status.to_i, 200
|
|
119
|
+
assert_equal "\0.6.6.6,8.8.8.8", @env["unxf.for"]
|
|
85
120
|
end
|
|
86
121
|
|
|
87
122
|
def test_more_trust
|
|
@@ -94,6 +129,7 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
94
129
|
assert_equal r.status.to_i, 200
|
|
95
130
|
assert_equal "1.6.6.6", @env["REMOTE_ADDR"]
|
|
96
131
|
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
|
132
|
+
assert_equal "1.6.6.6,0.6.6.6", @env["unxf.for"]
|
|
97
133
|
end
|
|
98
134
|
|
|
99
135
|
def test_one_trusted
|
|
@@ -106,5 +142,7 @@ class TestUnXF < Test::Unit::TestCase
|
|
|
106
142
|
assert_equal r.status.to_i, 200
|
|
107
143
|
assert_equal "1.6.6.6", @env["REMOTE_ADDR"]
|
|
108
144
|
assert ! @env.key?("HTTP_X_FORWARDED_FOR")
|
|
145
|
+
assert_equal "1.6.6.6", @env["unxf.for"]
|
|
146
|
+
assert_nil @env["unxf.proto"]
|
|
109
147
|
end
|
|
110
148
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: unxf
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
5
|
-
prerelease:
|
|
4
|
+
hash: 2091
|
|
5
|
+
prerelease: 8
|
|
6
6
|
segments:
|
|
7
7
|
- 2
|
|
8
8
|
- 0
|
|
9
9
|
- 0
|
|
10
|
-
|
|
10
|
+
- 2
|
|
11
|
+
- g
|
|
12
|
+
- 32
|
|
13
|
+
- d
|
|
14
|
+
- 0
|
|
15
|
+
version: 2.0.0.2.g32d0
|
|
11
16
|
platform: ruby
|
|
12
17
|
authors:
|
|
13
18
|
- UnXF hackers
|
|
@@ -15,7 +20,7 @@ autorequire:
|
|
|
15
20
|
bindir: bin
|
|
16
21
|
cert_chain: []
|
|
17
22
|
|
|
18
|
-
date: 2011-
|
|
23
|
+
date: 2011-08-09 00:00:00 Z
|
|
19
24
|
dependencies:
|
|
20
25
|
- !ruby/object:Gem::Dependency
|
|
21
26
|
name: rack
|
|
@@ -119,16 +124,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
119
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
120
125
|
none: false
|
|
121
126
|
requirements:
|
|
122
|
-
- - "
|
|
127
|
+
- - ">"
|
|
123
128
|
- !ruby/object:Gem::Version
|
|
124
|
-
hash:
|
|
129
|
+
hash: 25
|
|
125
130
|
segments:
|
|
126
|
-
-
|
|
127
|
-
|
|
131
|
+
- 1
|
|
132
|
+
- 3
|
|
133
|
+
- 1
|
|
134
|
+
version: 1.3.1
|
|
128
135
|
requirements: []
|
|
129
136
|
|
|
130
137
|
rubyforge_project: rainbows
|
|
131
|
-
rubygems_version: 1.8.
|
|
138
|
+
rubygems_version: 1.8.5
|
|
132
139
|
signing_key:
|
|
133
140
|
specification_version: 3
|
|
134
141
|
summary: Un-X-Forward* the Rack environment
|