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