
cherokee at cherokee-project
Nov 19, 2009, 3:27 AM
Post #1 of 1
(87 views)
Permalink
|
|
[3840] cherokee/trunk: Adds X-Real-IP header support to all the FastCGI, SCGI, uWSGI, and CGI
|
|
Revision: 3840 http://svn.cherokee-project.com/changeset/3840 Author: alo Date: 2009-11-19 12:27:27 +0100 (Thu, 19 Nov 2009) Log Message: ----------- Adds X-Real-IP header support to all the FastCGI, SCGI, uWSGI, and CGI handlers. A new cherokee_x_real_ip class has been refactored so both the logging subsystem and the handlers can use it. Three new QA tests have been added as well. Modified Paths: -------------- cherokee/trunk/cherokee/Makefile.am cherokee/trunk/cherokee/handler_cgi.h cherokee/trunk/cherokee/handler_cgi_base.c cherokee/trunk/cherokee/handler_cgi_base.h cherokee/trunk/cherokee/logger.c cherokee/trunk/qa/Makefile.am Added Paths: ----------- cherokee/trunk/cherokee/xrealip.c cherokee/trunk/cherokee/xrealip.h cherokee/trunk/qa/232-X-Real-IP-CGI.py cherokee/trunk/qa/233-X-Real-IP-CGI-2.py cherokee/trunk/qa/234-X-Real-IP-CGI-3.py Modified: cherokee/trunk/cherokee/Makefile.am =================================================================== --- cherokee/trunk/cherokee/Makefile.am 2009-11-18 16:34:32 UTC (rev 3839) +++ cherokee/trunk/cherokee/Makefile.am 2009-11-19 11:27:27 UTC (rev 3840) @@ -1353,7 +1353,9 @@ logger.h \ logger.c \ logger_writer.h \ -logger_writer.c +logger_writer.c \ +xrealip.h \ +xrealip.c libcherokee_client_la_SOURCES = \ Modified: cherokee/trunk/cherokee/handler_cgi.h =================================================================== --- cherokee/trunk/cherokee/handler_cgi.h 2009-11-18 16:34:32 UTC (rev 3839) +++ cherokee/trunk/cherokee/handler_cgi.h 2009-11-19 11:27:27 UTC (rev 3840) @@ -88,7 +88,6 @@ const char *name, int name_len, const char *content, int content_len); -ret_t cherokee_handler_cgi_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **props); ret_t cherokee_handler_cgi_props_free (cherokee_handler_cgi_props_t *props); #endif /* CHEROKEE_HANDLER_CGI_H */ Modified: cherokee/trunk/cherokee/handler_cgi_base.c =================================================================== --- cherokee/trunk/cherokee/handler_cgi_base.c 2009-11-18 16:34:32 UTC (rev 3839) +++ cherokee/trunk/cherokee/handler_cgi_base.c 2009-11-19 11:27:27 UTC (rev 3840) @@ -121,6 +121,7 @@ cherokee_list_t *i, *tmp; cherokee_buffer_mrproper (&props->script_alias); + cherokee_x_real_ip_mrproper (&props->x_real_ip); list_for_each_safe (i, tmp, &props->system_env) { env_item_free (i); @@ -153,6 +154,7 @@ INIT_LIST_HEAD (&props->system_env); cherokee_buffer_init (&props->script_alias); + cherokee_x_real_ip_init (&props->x_real_ip); props->is_error_handler = true; props->change_user = false; @@ -198,6 +200,11 @@ } } + ret = cherokee_x_real_ip_configure (&props->x_real_ip, conf); + if (ret != ret_ok) { + return ret_error; + } + return ret_ok; } @@ -205,8 +212,9 @@ ret_t cherokee_handler_cgi_base_free (cherokee_handler_cgi_base_t *cgi) { - if (cgi->file_handler) + if (cgi->file_handler) { cherokee_handler_free (cgi->file_handler); + } cherokee_buffer_mrproper (&cgi->data); cherokee_buffer_mrproper (&cgi->executable); @@ -239,11 +247,13 @@ cherokee_connection_t *conn, cherokee_buffer_t *tmp) { - int re; - ret_t ret; - char *p; - cuint_t p_len; - cherokee_bind_t *bind = CONN_BIND(HANDLER_CONN(cgi)); + int re; + ret_t ret; + char *p; + cuint_t p_len; + cherokee_boolean_t remote_addr_set; + cherokee_bind_t *bind = CONN_BIND(HANDLER_CONN(cgi)); + cherokee_handler_cgi_base_props_t *cgi_props = HANDLER_CGI_BASE_PROPS(cgi); char remote_ip[CHE_INET_ADDRSTRLEN+1]; CHEROKEE_TEMP(temp, 32); @@ -264,17 +274,60 @@ CONN_VSRV(conn)->root.buf, CONN_VSRV(conn)->root.len); - /* The IP address of the client sending the request to the - * server. This is not necessarily that of the user agent (such - * as if the request came through a proxy). + /* REMOTE_(ADDR/PORT): X-Real-IP */ - memset (remote_ip, 0, sizeof(remote_ip)); - cherokee_socket_ntop (&conn->socket, remote_ip, sizeof(remote_ip)-1); - set_env (cgi, "REMOTE_ADDR", remote_ip, strlen(remote_ip)); + remote_addr_set = false; - re = snprintf (temp, temp_size, "%d", SOCKET_SIN_PORT(&conn->socket)); - if (re > 0) { - set_env (cgi, "REMOTE_PORT", temp, re); + if (cgi_props->x_real_ip.enabled) + { + /* The request has a X-REAL-IP entry */ + ret = cherokee_header_get_known (&conn->header, header_x_real_ip, &p, &p_len); + if (ret == ret_ok) + { + /* The remote host is allowed to send it */ + ret = cherokee_x_real_ip_is_allowed (&cgi_props->x_real_ip, &conn->socket); + if (ret == ret_ok) { + cuint_t i; + const char *port_end = NULL; + const char *colon = NULL; + + for (i=0; i < p_len; i++) { + if (p[i] == ':') { + colon = &p[i]; + break; + } + } + + if (colon != NULL) { + port_end = colon + 1; + while ((*port_end >= '0') && (*port_end <= '9')) { + port_end++; + } + + set_env (cgi, "REMOTE_ADDR", p, colon - p); + set_env (cgi, "REMOTE_PORT", colon+1, (port_end-2) - colon+1); + } else { + set_env (cgi, "REMOTE_ADDR", p, p_len); + } + + remote_addr_set = true; + } + } + } + + /* REMOTE_(ADDR/PORT): socket origin + */ + if (! remote_addr_set) { + /* REMOTE_ADDR */ + memset (remote_ip, 0, sizeof(remote_ip)); + cherokee_socket_ntop (&conn->socket, remote_ip, sizeof(remote_ip)-1); + set_env (cgi, "REMOTE_ADDR", remote_ip, strlen(remote_ip)); + + /* REMOTE_PORT */ + re = snprintf (temp, temp_size, "%d", SOCKET_SIN_PORT(&conn->socket)); + if (re > 0) { + set_env (cgi, "REMOTE_PORT", temp, re); + } } /* HTTP_HOST and SERVER_NAME. The difference between them is that Modified: cherokee/trunk/cherokee/handler_cgi_base.h =================================================================== --- cherokee/trunk/cherokee/handler_cgi_base.h 2009-11-18 16:34:32 UTC (rev 3839) +++ cherokee/trunk/cherokee/handler_cgi_base.h 2009-11-19 11:27:27 UTC (rev 3840) @@ -31,6 +31,7 @@ #include "handler.h" #include "list.h" #include "connection.h" +#include "xrealip.h" #define SUPPORT_XSENDFILE @@ -104,6 +105,7 @@ cherokee_boolean_t allow_xsendfile; cherokee_boolean_t is_error_handler; cherokee_boolean_t pass_req_headers; + cherokee_x_real_ip_t x_real_ip; } cherokee_handler_cgi_base_props_t; #define PROP_CGI_BASE(x) ((cherokee_handler_cgi_base_props_t *)(x)) Modified: cherokee/trunk/cherokee/logger.c =================================================================== --- cherokee/trunk/cherokee/logger.c 2009-11-18 16:34:32 UTC (rev 3839) +++ cherokee/trunk/cherokee/logger.c 2009-11-19 11:27:27 UTC (rev 3840) @@ -27,6 +27,7 @@ #include "access.h" #include "header.h" #include "connection-protected.h" +#include "xrealip.h" #include <stdlib.h> #include <string.h> @@ -34,45 +35,20 @@ struct cherokee_logger_private { - CHEROKEE_MUTEX_T (mutex); - cherokee_boolean_t backup_mode; - - cherokee_boolean_t x_real_ip_enabled; - cherokee_access_t *x_real_ip_access; - cherokee_boolean_t x_real_ip_access_all; + CHEROKEE_MUTEX_T (mutex); + cherokee_boolean_t backup_mode; + cherokee_x_real_ip_t x_real_ip; }; #define PRIV(x) (LOGGER(x)->priv) -static ret_t -add_access (char *address, void *data) -{ - ret_t ret; - cherokee_logger_t *logger = LOGGER(data); - if (logger->priv->x_real_ip_access == NULL) { - ret = cherokee_access_new (&logger->priv->x_real_ip_access); - if (ret != ret_ok) { - return ret; - } - } - - ret = cherokee_access_add (logger->priv->x_real_ip_access, address); - if (ret != ret_ok) { - return ret; - } - - return ret_ok; - -} - ret_t cherokee_logger_init_base (cherokee_logger_t *logger, cherokee_plugin_info_t *info, cherokee_config_node_t *config) { - ret_t ret; - cherokee_config_node_t *subconf; + ret_t ret; CHEROKEE_NEW_TYPE(priv, struct cherokee_logger_private); /* Init the base class @@ -88,28 +64,16 @@ /* Private */ - logger->priv->backup_mode = false; - logger->priv->x_real_ip_enabled = false; - logger->priv->x_real_ip_access = NULL; - logger->priv->x_real_ip_access_all = false; + logger->priv->backup_mode = false; + + CHEROKEE_MUTEX_INIT (&PRIV(logger)->mutex, NULL); + cherokee_x_real_ip_init (&logger->priv->x_real_ip); - CHEROKEE_MUTEX_INIT (&PRIV(logger)->mutex, NULL); - /* Read the configuration */ - cherokee_config_node_read_bool (config, "x_real_ip_enabled", - &logger->priv->x_real_ip_enabled); - - cherokee_config_node_read_bool (config, "x_real_ip_access_all", - &logger->priv->x_real_ip_access_all); - - ret = cherokee_config_node_get (config, "x_real_ip_access", &subconf); - if (ret == ret_ok) { - ret = cherokee_config_node_read_list (subconf, NULL, add_access, logger); - if (ret != ret_ok) { - LOG_ERROR_S (CHEROKEE_ERROR_LOGGER_X_REAL_IP_PARSE); - return ret_error; - } + ret = cherokee_x_real_ip_configure (&logger->priv->x_real_ip, config); + if (ret != ret_ok) { + return ret_error; } return ret_ok; @@ -129,9 +93,7 @@ } if (logger->priv) { - if (logger->priv->x_real_ip_access) { - cherokee_access_free (logger->priv->x_real_ip_access); - } + cherokee_x_real_ip_mrproper (&logger->priv->x_real_ip); free (logger->priv); } @@ -208,15 +170,9 @@ /* Is the client allowed to use X-Real-IP? */ - if (! logger->priv->x_real_ip_access_all) { - if (logger->priv->x_real_ip_access == NULL) { - return ret_deny; - } - - ret = cherokee_access_ip_match (logger->priv->x_real_ip_access, &conn->socket); - if (ret != ret_ok) { - return ret_deny; - } + ret = cherokee_x_real_ip_is_allowed (&logger->priv->x_real_ip, &conn->socket); + if (ret != ret_ok) { + return ret_deny; } /* Store the X-Real-IP value @@ -242,7 +198,7 @@ /* Deal with X-Real-IP */ - if (logger->priv->x_real_ip_enabled) { + if (logger->priv->x_real_ip.enabled) { ret = parse_x_real_ip (logger, CONN(conn)); if (unlikely (ret == ret_error)) return ret_error; Added: cherokee/trunk/cherokee/xrealip.c =================================================================== --- cherokee/trunk/cherokee/xrealip.c (rev 0) +++ cherokee/trunk/cherokee/xrealip.c 2009-11-19 11:27:27 UTC (rev 3840) @@ -0,0 +1,116 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Cherokee + * + * Authors: + * Alvaro Lopez Ortega <alvaro [at] alobbs> + * + * Copyright (C) 2001-2009 Alvaro Lopez Ortega + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "common-internal.h" +#include "xrealip.h" + + +ret_t +cherokee_x_real_ip_init (cherokee_x_real_ip_t *real_ip) +{ + real_ip->enabled = false; + real_ip->access = NULL; + real_ip->access_all = false; + + return ret_ok; +} + + +ret_t +cherokee_x_real_ip_mrproper (cherokee_x_real_ip_t *real_ip) +{ + if (real_ip->access != NULL) { + cherokee_access_free (real_ip->access); + real_ip->access = NULL; + } + + return ret_ok; +} + + +static ret_t +add_access (char *address, void *data) +{ + ret_t ret; + cherokee_x_real_ip_t *real_ip = X_REAL_IP(data); + + if (real_ip->access == NULL) { + ret = cherokee_access_new (&real_ip->access); + if (ret != ret_ok) { + return ret; + } + } + + ret = cherokee_access_add (real_ip->access, address); + if (ret != ret_ok) { + return ret; + } + + return ret_ok; + +} + + +ret_t +cherokee_x_real_ip_configure (cherokee_x_real_ip_t *real_ip, + cherokee_config_node_t *config) +{ + ret_t ret; + cherokee_config_node_t *subconf; + + cherokee_config_node_read_bool (config, "x_real_ip_enabled", &real_ip->enabled); + cherokee_config_node_read_bool (config, "x_real_ip_access_all", &real_ip->access_all); + + ret = cherokee_config_node_get (config, "x_real_ip_access", &subconf); + if (ret == ret_ok) { + ret = cherokee_config_node_read_list (subconf, NULL, add_access, real_ip); + if (ret != ret_ok) { + LOG_ERROR_S (CHEROKEE_ERROR_LOGGER_X_REAL_IP_PARSE); + return ret_error; + } + } + + return ret_ok; +} + + +ret_t +cherokee_x_real_ip_is_allowed (cherokee_x_real_ip_t *real_ip, + cherokee_socket_t *sock) +{ + ret_t ret; + + if (! real_ip->access_all) { + if (real_ip->access == NULL) { + return ret_deny; + } + + ret = cherokee_access_ip_match (real_ip->access, sock); + if (ret != ret_ok) { + return ret_deny; + } + } + + return ret_ok; +} Added: cherokee/trunk/cherokee/xrealip.h =================================================================== --- cherokee/trunk/cherokee/xrealip.h (rev 0) +++ cherokee/trunk/cherokee/xrealip.h 2009-11-19 11:27:27 UTC (rev 3840) @@ -0,0 +1,56 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* Cherokee + * + * Authors: + * Alvaro Lopez Ortega <alvaro [at] alobbs> + * + * Copyright (C) 2001-2009 Alvaro Lopez Ortega + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#if !defined (CHEROKEE_INSIDE_CHEROKEE_H) && !defined (CHEROKEE_COMPILATION) +# error "Only <cherokee/cherokee.h> can be included directly, this file may disappear or change contents." +#endif + +#ifndef CHEROKEE_X_REAL_IP_H +#define CHEROKEE_X_REAL_IP_H + +#include <cherokee/common.h> +#include <cherokee/buffer.h> +#include <cherokee/config_node.h> +#include <cherokee/access.h> + +CHEROKEE_BEGIN_DECLS + +typedef struct { + cherokee_boolean_t enabled; + cherokee_access_t *access; + cherokee_boolean_t access_all; +} cherokee_x_real_ip_t; + +#define X_REAL_IP(o) ((cherokee_x_real_ip_t *)(o)) + + +ret_t cherokee_x_real_ip_init (cherokee_x_real_ip_t *real_ip); +ret_t cherokee_x_real_ip_mrproper (cherokee_x_real_ip_t *real_ip); +ret_t cherokee_x_real_ip_configure (cherokee_x_real_ip_t *real_ip, cherokee_config_node_t *conf); +ret_t cherokee_x_real_ip_is_allowed (cherokee_x_real_ip_t *real_ip, cherokee_socket_t *sock); + +CHEROKEE_END_DECLS + +#endif /* CHEROKEE_X_REAL_IP_H */ Added: cherokee/trunk/qa/232-X-Real-IP-CGI.py =================================================================== --- cherokee/trunk/qa/232-X-Real-IP-CGI.py (rev 0) +++ cherokee/trunk/qa/232-X-Real-IP-CGI.py 2009-11-19 11:27:27 UTC (rev 3840) @@ -0,0 +1,44 @@ +from base import * + +DIR = "x_real_ip_cgi_1" +REMOTE_IP = "1.2.3.4" + +CONF = """ +vserver!1!rule!2320!match = directory +vserver!1!rule!2320!match!directory = /%s +vserver!1!rule!2320!handler = cgi +vserver!1!rule!2320!handler!x_real_ip_enabled = 1 +vserver!1!rule!2320!handler!x_real_ip_access_all = 0 +vserver!1!rule!2320!handler!x_real_ip_access = ::1,127.0.0.1 +""" % (DIR) + +CGI_CODE = """#!/bin/sh + +echo "Content-Type: text/plain" +echo + +echo "REMOTE_ADDR ->${REMOTE_ADDR}<-" +echo +""" + +class Test (TestBase): + def __init__ (self): + TestBase.__init__ (self, __file__) + self.name = "X-Real-IP to REMOTE_ADDR: CGI" + + self.request = "GET /%s/test HTTP/1.0\r\n" % (DIR) + \ + "X-Real-IP: %s\r\n" % (REMOTE_IP) + self.expected_error = 200 + self.conf = CONF + + def CustomTest (self): + body = self.reply.split ("\r\n\r\n")[1] + + if "REMOTE_ADDR ->%s<-" %(REMOTE_IP) in body: + return 0 + + return -1 + + def Prepare (self, www): + d = self.Mkdir (www, DIR, 0777) + self.WriteFile (d, "test", 0555, CGI_CODE) Added: cherokee/trunk/qa/233-X-Real-IP-CGI-2.py =================================================================== --- cherokee/trunk/qa/233-X-Real-IP-CGI-2.py (rev 0) +++ cherokee/trunk/qa/233-X-Real-IP-CGI-2.py 2009-11-19 11:27:27 UTC (rev 3840) @@ -0,0 +1,47 @@ +from base import * + +DIR = "x_real_ip_cgi_2" +REMOTE_IP = "2.3.4.5" +REMOTE_PORT = "987" + +CONF = """ +vserver!1!rule!2330!match = directory +vserver!1!rule!2330!match!directory = /%s +vserver!1!rule!2330!handler = cgi +vserver!1!rule!2330!handler!x_real_ip_enabled = 1 +vserver!1!rule!2330!handler!x_real_ip_access_all = 0 +vserver!1!rule!2330!handler!x_real_ip_access = ::1,127.0.0.1 +""" % (DIR) + +CGI_CODE = """#!/bin/sh + +echo "Content-Type: text/plain" +echo + +echo "REMOTE_ADDR ->${REMOTE_ADDR}<-" +echo "REMOTE_PORT ->${REMOTE_PORT}<-" +echo +""" + +class Test (TestBase): + def __init__ (self): + TestBase.__init__ (self, __file__) + self.name = "X-Real-IP to REMOTE_(ADDR,PORT): CGI" + + self.request = "GET /%s/test HTTP/1.0\r\n" % (DIR) + \ + "X-Real-IP: %s:%s\r\n" % (REMOTE_IP, REMOTE_PORT) + self.expected_error = 200 + self.conf = CONF + + def CustomTest (self): + body = self.reply.split ("\r\n\r\n")[1] + + if ("REMOTE_ADDR ->%s<-" %(REMOTE_IP) in body and + "REMOTE_PORT ->%s<-" %(REMOTE_PORT) in body): + return 0 + + return -1 + + def Prepare (self, www): + d = self.Mkdir (www, DIR, 0777) + self.WriteFile (d, "test", 0555, CGI_CODE) Added: cherokee/trunk/qa/234-X-Real-IP-CGI-3.py =================================================================== --- cherokee/trunk/qa/234-X-Real-IP-CGI-3.py (rev 0) +++ cherokee/trunk/qa/234-X-Real-IP-CGI-3.py 2009-11-19 11:27:27 UTC (rev 3840) @@ -0,0 +1,46 @@ +from base import * + +DIR = "x_real_ip_cgi_3" + +CONF = """ +vserver!1!rule!2340!match = directory +vserver!1!rule!2340!match!directory = /%s +vserver!1!rule!2340!handler = cgi +vserver!1!rule!2340!handler!x_real_ip_enabled = 1 +vserver!1!rule!2340!handler!x_real_ip_access_all = 0 +vserver!1!rule!2340!handler!x_real_ip_access = 9.9.9.9 +""" % (DIR) + +CGI_CODE = """#!/bin/sh + +echo "Content-Type: text/plain" +echo + +echo "REMOTE_ADDR ->${REMOTE_ADDR}<-" +echo +""" + +class Test (TestBase): + def __init__ (self): + TestBase.__init__ (self, __file__) + self.name = "X-Real-IP denied: CGI" + + self.request = "GET /%s/test HTTP/1.0\r\n" % (DIR) + \ + "X-Real-IP: 1.1.1.1\r\n" + self.expected_error = 200 + self.conf = CONF + + def CustomTest (self): + body = self.reply.split ("\r\n\r\n")[1] + + if "REMOTE_ADDR ->127.0.0.1<-" in body: + return 0 + + if "REMOTE_ADDR ->::1<-" in body: + return 0 + + return -1 + + def Prepare (self, www): + d = self.Mkdir (www, DIR, 0777) + self.WriteFile (d, "test", 0555, CGI_CODE) Modified: cherokee/trunk/qa/Makefile.am =================================================================== --- cherokee/trunk/qa/Makefile.am 2009-11-18 16:34:32 UTC (rev 3839) +++ cherokee/trunk/qa/Makefile.am 2009-11-19 11:27:27 UTC (rev 3840) @@ -236,7 +236,11 @@ 228-Redir-Paths2.py \ 229-Fullpath.py \ 230-Fullpath2.py \ -231-POST-4extra.py +231-POST-4extra.py \ +232-X-Real-IP-CGI.py \ +233-X-Real-IP-CGI-2.py \ +234-X-Real-IP-CGI-3.py + test: ./run-tests.py
|