diff src/http/modules/ngx_http_realip_module.c @ 122:d25a1d6034f1 NGINX_0_3_8

nginx 0.3.8 *) Security: nginx now checks URI got from a backend in "X-Accel-Redirect" header line or in SSI file for the "/../" paths and zeroes. *) Change: nginx now does not treat the empty user name in the "Authorization" header line as valid one. *) Feature: the "ssl_session_timeout" directives of the ngx_http_ssl_module and ngx_imap_ssl_module. *) Feature: the "auth_http_header" directive of the ngx_imap_auth_http_module. *) Feature: the "add_header" directive. *) Feature: the ngx_http_realip_module. *) Feature: the new variables to use in the "log_format" directive: $bytes_sent, $apache_bytes_sent, $status, $time_gmt, $uri, $request_time, $request_length, $upstream_status, $upstream_response_time, $gzip_ratio, $uid_got, $uid_set, $connection, $pipe, and $msec. The parameters in the "%name" form will be canceled soon. *) Change: now the false variable values in the "if" directive are the empty string "" and string starting with "0". *) Bugfix: while using proxied or FastCGI-server nginx may leave connections and temporary files with client requests in open state. *) Bugfix: the worker processes did not flush the buffered logs on graceful exit. *) Bugfix: if the request URI was changes by the "rewrite" directive and the request was proxied in location given by regular expression, then the incorrect request was transferred to backend; bug appeared in 0.2.6. *) Bugfix: the "expires" directive did not remove the previous "Expires" header. *) Bugfix: nginx may stop to accept requests if the "rtsig" method and several worker processes were used. *) Bugfix: the "\"" and "\'" escape symbols were incorrectly handled in SSI commands. *) Bugfix: if the response was ended just after the SSI command and gzipping was used, then the response did not transferred complete or did not transferred at all.
author Igor Sysoev <http://sysoev.ru>
date Wed, 09 Nov 2005 00:00:00 +0300
parents
children 82d695e3d662
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -0,0 +1,275 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+/* AF_INET only */
+
+typedef struct {
+    in_addr_t     mask;
+    in_addr_t     addr;
+} ngx_http_realip_from_t;
+
+
+typedef struct {
+    ngx_array_t  *from;     /* array of ngx_http_realip_from_t */
+
+    ngx_uint_t    xfwd;
+} ngx_http_realip_loc_conf_t;
+
+
+static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
+static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf,
+    void *parent, void *child);
+static ngx_int_t ngx_http_realip_init(ngx_cycle_t *cycle);
+
+
+static ngx_conf_enum_t  ngx_http_realip_header[] = {
+    { ngx_string("X-Forwarded-For"), 1 },
+    { ngx_string("X-Real-IP"), 0 },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_command_t  ngx_http_realip_commands[] = {
+
+    { ngx_string("set_real_ip_from"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_realip_from,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
+    { ngx_string("real_ip_header"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_realip_loc_conf_t, xfwd),
+      &ngx_http_realip_header },
+
+      ngx_null_command
+};
+
+
+
+ngx_http_module_t  ngx_http_realip_module_ctx = {
+    NULL,                                  /* preconfiguration */
+    NULL,                                  /* postconfiguration */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+
+    ngx_http_realip_create_loc_conf,       /* create location configuration */
+    ngx_http_realip_merge_loc_conf         /* merge location configuration */
+};
+
+
+ngx_module_t  ngx_http_realip_module = {
+    NGX_MODULE_V1,
+    &ngx_http_realip_module_ctx,           /* module context */
+    ngx_http_realip_commands,              /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    ngx_http_realip_init,                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_realip_handler(ngx_http_request_t *r)
+{
+    u_char                      *ip, *p;
+    size_t                       len;
+    ngx_uint_t                   i;
+    struct sockaddr_in          *sin;
+    ngx_http_realip_from_t      *from;
+    ngx_http_realip_loc_conf_t  *rlcf;
+
+    if (r->realip_set) {
+        return NGX_OK;
+    }
+
+    rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
+
+    if (rlcf->from == NULL) {
+        return NGX_OK;
+    }
+
+    if (rlcf->xfwd == 0) {
+        if (r->headers_in.x_real_ip == NULL) {
+            return NGX_OK;
+        }
+
+        len = r->headers_in.x_real_ip->value.len;
+        ip = r->headers_in.x_real_ip->value.data;
+
+    } else {
+        if (r->headers_in.x_forwarded_for == NULL) {
+            return NGX_OK;
+        }
+
+        len = r->headers_in.x_forwarded_for->value.len;
+        ip = r->headers_in.x_forwarded_for->value.data;
+
+        for (p = ip + len; p > ip; p--) {
+            if (*p == ' ' || *p == ',') {
+               p++;
+               len -= p - ip;
+               ip = p;
+               break;
+            }
+        }
+    }
+
+    /* AF_INET only */
+
+    sin = (struct sockaddr_in *) r->connection->sockaddr;
+
+    from = rlcf->from->elts;
+    for (i = 0; i < rlcf->from->nelts; i++) {
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "realip: %08XD %08XD %08XD",
+                       sin->sin_addr.s_addr, from[i].mask, from[i].addr);
+
+        if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) {
+
+            r->connection->addr_text.len = len;
+            r->connection->addr_text.data = ip;
+
+            sin->sin_addr.s_addr = inet_addr((char *) ip);
+
+            r->realip_set = 1;
+
+            return NGX_OK;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+static char *
+ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_realip_loc_conf_t *rlcf = conf;
+
+    ngx_str_t                *value;
+    ngx_inet_cidr_t           in_cidr;
+    ngx_http_realip_from_t   *from;
+
+    if (rlcf->from == NULL) {
+        rlcf->from = ngx_array_create(cf->pool, 2,
+                                      sizeof(ngx_http_realip_from_t));
+        if (rlcf->from == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    from = ngx_array_push(rlcf->from);
+    if (from == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    from->addr = inet_addr((char *) value[1].data);
+
+    if (from->addr != INADDR_NONE) {
+        from->mask = 0xffffffff;
+
+        return NGX_CONF_OK;
+    }
+
+    if (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
+                           &value[1]);
+        return NGX_CONF_ERROR;
+    }
+
+    from->mask = in_cidr.mask;
+    from->addr = in_cidr.addr;
+
+    return NGX_CONF_OK;
+}
+
+
+static void *
+ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_realip_loc_conf_t  *conf;
+
+    conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
+    if (conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     conf->from = NULL;
+     */
+
+    conf->xfwd = NGX_CONF_UNSET_UINT;
+
+    return conf;
+}
+
+
+static char *
+ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_realip_loc_conf_t  *prev = parent;
+    ngx_http_realip_loc_conf_t  *conf = child;
+
+    if (conf->from == NULL) {
+        conf->from = prev->from;
+    }
+
+    ngx_conf_merge_unsigned_value(conf->xfwd, prev->xfwd, 0);
+
+    return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_realip_init(ngx_cycle_t *cycle)
+{
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module);
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_realip_handler;
+
+    h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_realip_handler;
+
+    return NGX_OK;
+}