unxf 2.0.0 → 2.0.0.2.g32d0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/unxf.rb +18 -6
  2. data/test/test_unxf.rb +38 -0
  3. metadata +16 -9
@@ -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 { |m| @trusted.add(m, true) }
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) && tmp = xff.pop
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) =~ /\Ahttps\b/ and
69
- env[RACK_URL_SCHEME] = HTTPS
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
@@ -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: 15
5
- prerelease:
4
+ hash: 2091
5
+ prerelease: 8
6
6
  segments:
7
7
  - 2
8
8
  - 0
9
9
  - 0
10
- version: 2.0.0
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-05-26 00:00:00 Z
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: 3
129
+ hash: 25
125
130
  segments:
126
- - 0
127
- version: "0"
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.2
138
+ rubygems_version: 1.8.5
132
139
  signing_key:
133
140
  specification_version: 3
134
141
  summary: Un-X-Forward* the Rack environment