about summary refs log tree commit homepage
path: root/ext
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-12-20 22:05:50 +0000
committerEric Wong <normalperson@yhbt.net>2010-12-20 22:05:50 +0000
commitbf64b9aa855cf3590a4d5b4eca853aef33ba90cc (patch)
tree0867d533bd3f79ebf336d0fda2667bb8f787e875 /ext
parent8be3668c11cf721960581e325b481c105e8f3c89 (diff)
downloadunicorn-bf64b9aa855cf3590a4d5b4eca853aef33ba90cc.tar.gz
Evil clients may be exposed to the Unicorn parser via
Rainbows!, so we'll allow people to turn off blindly
trusting certain X-Forwarded* headers for "rack.url_scheme"
and rely on middleware to handle it.
Diffstat (limited to 'ext')
-rw-r--r--ext/unicorn_http/unicorn_http.rl63
1 files changed, 50 insertions, 13 deletions
diff --git a/ext/unicorn_http/unicorn_http.rl b/ext/unicorn_http/unicorn_http.rl
index 510f456..cee0e0b 100644
--- a/ext/unicorn_http/unicorn_http.rl
+++ b/ext/unicorn_http/unicorn_http.rl
@@ -26,6 +26,12 @@
 /* all of these flags need to be set for keepalive to be supported */
 #define UH_FL_KEEPALIVE (UH_FL_KAVERSION | UH_FL_REQEOF | UH_FL_HASHEADER)
 
+/*
+ * whether or not to trust X-Forwarded-Proto and X-Forwarded-SSL when
+ * setting rack.url_scheme
+ */
+static VALUE x_forwarded_trust = Qtrue;
+
 static unsigned long keepalive_requests = 100; /* same as nginx */
 
 /*
@@ -49,6 +55,31 @@ static VALUE set_ka_req(VALUE self, VALUE val)
   return ka_req(self);
 }
 
+/*
+ * Sets whether or not the parser will trust X-Forwarded-Proto and
+ * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly.
+ * Rainbows!/Zbatery installations facing untrusted clients directly
+ * should set this to +false+
+ */
+static VALUE set_xftrust(VALUE self, VALUE val)
+{
+  if (Qtrue == val || Qfalse == val)
+    x_forwarded_trust = val;
+  else
+    rb_raise(rb_eTypeError, "must be true or false");
+
+  return val;
+}
+
+/*
+ * returns whether or not the parser will trust X-Forwarded-Proto and
+ * X-Forwarded-SSL headers and set "rack.url_scheme" to "https" accordingly
+ */
+static VALUE xftrust(VALUE self)
+{
+  return x_forwarded_trust;
+}
+
 /* keep this small for Rainbows! since every client has one */
 struct http_parser {
   int cs; /* Ragel internal state */
@@ -426,22 +457,26 @@ static void set_url_scheme(VALUE env, VALUE *server_port)
   VALUE scheme = rb_hash_aref(env, g_rack_url_scheme);
 
   if (NIL_P(scheme)) {
-    scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
-    if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
-      *server_port = g_port_443;
-      scheme = g_https;
+    if (x_forwarded_trust == Qfalse) {
+      scheme = g_http;
     } else {
-      scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
-      if (NIL_P(scheme)) {
-        scheme = g_http;
+      scheme = rb_hash_aref(env, g_http_x_forwarded_ssl);
+      if (!NIL_P(scheme) && STR_CSTR_EQ(scheme, "on")) {
+        *server_port = g_port_443;
+        scheme = g_https;
       } else {
-        long len = RSTRING_LEN(scheme);
-        if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
-          if (len != 5)
-            scheme = g_https;
-          *server_port = g_port_443;
-        } else {
+        scheme = rb_hash_aref(env, g_http_x_forwarded_proto);
+        if (NIL_P(scheme)) {
           scheme = g_http;
+        } else {
+          long len = RSTRING_LEN(scheme);
+          if (len >= 5 && !memcmp(RSTRING_PTR(scheme), "https", 5)) {
+            if (len != 5)
+              scheme = g_https;
+            *server_port = g_port_443;
+          } else {
+            scheme = g_http;
+          }
         }
       }
     }
@@ -853,6 +888,8 @@ void Init_unicorn_http(void)
 
   rb_define_singleton_method(cHttpParser, "keepalive_requests", ka_req, 0);
   rb_define_singleton_method(cHttpParser, "keepalive_requests=", set_ka_req, 1);
+  rb_define_singleton_method(cHttpParser, "x_forwarded_trust=", set_xftrust, 1);
+  rb_define_singleton_method(cHttpParser, "x_forwarded_trust?", xftrust, 0);
 
   init_common_fields();
   SET_GLOBAL(g_http_host, "HOST");