unxf 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v1.0.0.GIT
4
+ DEF_VER=v2.0.0.GIT
5
5
 
6
6
  LF='
7
7
  '
@@ -4,8 +4,3 @@ RSYNC_DEST := bogomips.org:/srv/bogomips/unxf
4
4
  rfproject := rainbows
5
5
  rfpackage := unxf
6
6
  include pkg.mk
7
- ifneq ($(VERSION),)
8
- release::
9
- $(RAKE) raa_update VERSION=$(VERSION)
10
- $(RAKE) publish_news VERSION=$(VERSION)
11
- endif
data/README CHANGED
@@ -1,14 +1,49 @@
1
1
  = UnXF - Un-X-Forward* the Rack environment
2
2
 
3
- Removes X-Forwarded-For in the Rack environment and replaces REMOTE_ADDR
4
- with the correct value (assuming REMOTE_ADDR and the X-Forwarded-For
5
- chain is provided).
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
- === Contact
46
+ == Contact
12
47
 
13
- * Email our mailing list for all support questions, patches, bug reports, pull
14
- requests: mailto:unxf@librelist.org
48
+ All feedback (bug reports, user/development discussion, patches, pull
49
+ requests) go to the mailing list: mailto:unxf@librelist.org
@@ -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
- def call(env)
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 on_bad_addr(env, xff_str)
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 on_bad_addr(env, xff_str)
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 a bad address is to just continue dispatching
56
- # the application with the existing environment
57
- # You may extend this object to override this error
58
- def on_bad_addr(env, xff_str)
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
@@ -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 r.status.to_i, 400
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 r.status.to_i, 400
72
- assert_match /0\.6\.6\.6,8\.8\.8\.8/, @io.string
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 r.status.to_i, 400
83
- assert_match /\\x00\.6\.6\.6,8\.8\.8\.8/, @io.string
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
@@ -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.add_development_dependency('rpatricia', '~> 0.07')
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: 23
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
- - 1
7
+ - 2
8
8
  - 0
9
9
  - 0
10
- version: 1.0.0
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-24 00:00:00 Z
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: :development
63
+ type: :runtime
64
64
  version_requirements: *id003
65
65
  description: |-
66
- Removes X-Forwarded-For in the Rack environment and replaces REMOTE_ADDR
67
- with the correct value (assuming REMOTE_ADDR and the X-Forwarded-For
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