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.
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