src/http/modules/ngx_http_realip_module.c - nginx-1.7.10

Global variables defined

Data types defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>


  8. #define NGX_HTTP_REALIP_XREALIP  0
  9. #define NGX_HTTP_REALIP_XFWD     1
  10. #define NGX_HTTP_REALIP_HEADER   2
  11. #define NGX_HTTP_REALIP_PROXY    3


  12. typedef struct {
  13.     ngx_array_t       *from;     /* array of ngx_cidr_t */
  14.     ngx_uint_t         type;
  15.     ngx_uint_t         hash;
  16.     ngx_str_t          header;
  17.     ngx_flag_t         recursive;
  18. } ngx_http_realip_loc_conf_t;


  19. typedef struct {
  20.     ngx_connection_t  *connection;
  21.     struct sockaddr   *sockaddr;
  22.     socklen_t          socklen;
  23.     ngx_str_t          addr_text;
  24. } ngx_http_realip_ctx_t;


  25. static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
  26. static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r,
  27.     ngx_addr_t *addr);
  28. static void ngx_http_realip_cleanup(void *data);
  29. static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
  30.     void *conf);
  31. static char *ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
  32. static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf);
  33. static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf,
  34.     void *parent, void *child);
  35. static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf);


  36. static ngx_command_t  ngx_http_realip_commands[] = {

  37.     { ngx_string("set_real_ip_from"),
  38.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  39.       ngx_http_realip_from,
  40.       NGX_HTTP_LOC_CONF_OFFSET,
  41.       0,
  42.       NULL },

  43.     { ngx_string("real_ip_header"),
  44.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
  45.       ngx_http_realip,
  46.       NGX_HTTP_LOC_CONF_OFFSET,
  47.       0,
  48.       NULL },

  49.     { ngx_string("real_ip_recursive"),
  50.       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
  51.       ngx_conf_set_flag_slot,
  52.       NGX_HTTP_LOC_CONF_OFFSET,
  53.       offsetof(ngx_http_realip_loc_conf_t, recursive),
  54.       NULL },

  55.       ngx_null_command
  56. };



  57. static ngx_http_module_t  ngx_http_realip_module_ctx = {
  58.     NULL,                                  /* preconfiguration */
  59.     ngx_http_realip_init,                  /* postconfiguration */

  60.     NULL,                                  /* create main configuration */
  61.     NULL,                                  /* init main configuration */

  62.     NULL,                                  /* create server configuration */
  63.     NULL,                                  /* merge server configuration */

  64.     ngx_http_realip_create_loc_conf,       /* create location configuration */
  65.     ngx_http_realip_merge_loc_conf         /* merge location configuration */
  66. };


  67. ngx_module_t  ngx_http_realip_module = {
  68.     NGX_MODULE_V1,
  69.     &ngx_http_realip_module_ctx,           /* module context */
  70.     ngx_http_realip_commands,              /* module directives */
  71.     NGX_HTTP_MODULE,                       /* module type */
  72.     NULL,                                  /* init master */
  73.     NULL,                                  /* init module */
  74.     NULL,                                  /* init process */
  75.     NULL,                                  /* init thread */
  76.     NULL,                                  /* exit thread */
  77.     NULL,                                  /* exit process */
  78.     NULL,                                  /* exit master */
  79.     NGX_MODULE_V1_PADDING
  80. };


  81. static ngx_int_t
  82. ngx_http_realip_handler(ngx_http_request_t *r)
  83. {
  84.     u_char                      *p;
  85.     size_t                       len;
  86.     ngx_str_t                   *value;
  87.     ngx_uint_t                   i, hash;
  88.     ngx_addr_t                   addr;
  89.     ngx_array_t                 *xfwd;
  90.     ngx_list_part_t             *part;
  91.     ngx_table_elt_t             *header;
  92.     ngx_connection_t            *c;
  93.     ngx_http_realip_ctx_t       *ctx;
  94.     ngx_http_realip_loc_conf_t  *rlcf;

  95.     ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);

  96.     if (ctx) {
  97.         return NGX_DECLINED;
  98.     }

  99.     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);

  100.     if (rlcf->from == NULL) {
  101.         return NGX_DECLINED;
  102.     }

  103.     switch (rlcf->type) {

  104.     case NGX_HTTP_REALIP_XREALIP:

  105.         if (r->headers_in.x_real_ip == NULL) {
  106.             return NGX_DECLINED;
  107.         }

  108.         value = &r->headers_in.x_real_ip->value;
  109.         xfwd = NULL;

  110.         break;

  111.     case NGX_HTTP_REALIP_XFWD:

  112.         xfwd = &r->headers_in.x_forwarded_for;

  113.         if (xfwd->elts == NULL) {
  114.             return NGX_DECLINED;
  115.         }

  116.         value = NULL;

  117.         break;

  118.     case NGX_HTTP_REALIP_PROXY:

  119.         value = &r->connection->proxy_protocol_addr;

  120.         if (value->len == 0) {
  121.             return NGX_DECLINED;
  122.         }

  123.         xfwd = NULL;

  124.         break;

  125.     default: /* NGX_HTTP_REALIP_HEADER */

  126.         part = &r->headers_in.headers.part;
  127.         header = part->elts;

  128.         hash = rlcf->hash;
  129.         len = rlcf->header.len;
  130.         p = rlcf->header.data;

  131.         for (i = 0; /* void */ ; i++) {

  132.             if (i >= part->nelts) {
  133.                 if (part->next == NULL) {
  134.                     break;
  135.                 }

  136.                 part = part->next;
  137.                 header = part->elts;
  138.                 i = 0;
  139.             }

  140.             if (hash == header[i].hash
  141.                 && len == header[i].key.len
  142.                 && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
  143.             {
  144.                 value = &header[i].value;
  145.                 xfwd = NULL;

  146.                 goto found;
  147.             }
  148.         }

  149.         return NGX_DECLINED;
  150.     }

  151. found:

  152.     c = r->connection;

  153.     addr.sockaddr = c->sockaddr;
  154.     addr.socklen = c->socklen;
  155.     /* addr.name = c->addr_text; */

  156.     if (ngx_http_get_forwarded_addr(r, &addr, xfwd, value, rlcf->from,
  157.                                     rlcf->recursive)
  158.         != NGX_DECLINED)
  159.     {
  160.         return ngx_http_realip_set_addr(r, &addr);
  161.     }

  162.     return NGX_DECLINED;
  163. }


  164. static ngx_int_t
  165. ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr)
  166. {
  167.     size_t                  len;
  168.     u_char                 *p;
  169.     u_char                  text[NGX_SOCKADDR_STRLEN];
  170.     ngx_connection_t       *c;
  171.     ngx_pool_cleanup_t     *cln;
  172.     ngx_http_realip_ctx_t  *ctx;

  173.     cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
  174.     if (cln == NULL) {
  175.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  176.     }

  177.     ctx = cln->data;
  178.     ngx_http_set_ctx(r, ctx, ngx_http_realip_module);

  179.     c = r->connection;

  180.     len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text,
  181.                         NGX_SOCKADDR_STRLEN, 0);
  182.     if (len == 0) {
  183.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  184.     }

  185.     p = ngx_pnalloc(c->pool, len);
  186.     if (p == NULL) {
  187.         return NGX_HTTP_INTERNAL_SERVER_ERROR;
  188.     }

  189.     ngx_memcpy(p, text, len);

  190.     cln->handler = ngx_http_realip_cleanup;

  191.     ctx->connection = c;
  192.     ctx->sockaddr = c->sockaddr;
  193.     ctx->socklen = c->socklen;
  194.     ctx->addr_text = c->addr_text;

  195.     c->sockaddr = addr->sockaddr;
  196.     c->socklen = addr->socklen;
  197.     c->addr_text.len = len;
  198.     c->addr_text.data = p;

  199.     return NGX_DECLINED;
  200. }


  201. static void
  202. ngx_http_realip_cleanup(void *data)
  203. {
  204.     ngx_http_realip_ctx_t *ctx = data;

  205.     ngx_connection_t  *c;

  206.     c = ctx->connection;

  207.     c->sockaddr = ctx->sockaddr;
  208.     c->socklen = ctx->socklen;
  209.     c->addr_text = ctx->addr_text;
  210. }


  211. static char *
  212. ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  213. {
  214.     ngx_http_realip_loc_conf_t *rlcf = conf;

  215.     ngx_int_t                rc;
  216.     ngx_str_t               *value;
  217.     ngx_cidr_t              *cidr;

  218.     value = cf->args->elts;

  219.     if (rlcf->from == NULL) {
  220.         rlcf->from = ngx_array_create(cf->pool, 2,
  221.                                       sizeof(ngx_cidr_t));
  222.         if (rlcf->from == NULL) {
  223.             return NGX_CONF_ERROR;
  224.         }
  225.     }

  226.     cidr = ngx_array_push(rlcf->from);
  227.     if (cidr == NULL) {
  228.         return NGX_CONF_ERROR;
  229.     }

  230. #if (NGX_HAVE_UNIX_DOMAIN)

  231.     if (ngx_strcmp(value[1].data, "unix:") == 0) {
  232.          cidr->family = AF_UNIX;
  233.          return NGX_CONF_OK;
  234.     }

  235. #endif

  236.     rc = ngx_ptocidr(&value[1], cidr);

  237.     if (rc == NGX_ERROR) {
  238.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
  239.                            &value[1]);
  240.         return NGX_CONF_ERROR;
  241.     }

  242.     if (rc == NGX_DONE) {
  243.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  244.                            "low address bits of %V are meaningless", &value[1]);
  245.     }

  246.     return NGX_CONF_OK;
  247. }


  248. static char *
  249. ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  250. {
  251.     ngx_http_realip_loc_conf_t *rlcf = conf;

  252.     ngx_str_t  *value;

  253.     value = cf->args->elts;

  254.     if (ngx_strcmp(value[1].data, "X-Real-IP") == 0) {
  255.         rlcf->type = NGX_HTTP_REALIP_XREALIP;
  256.         return NGX_CONF_OK;
  257.     }

  258.     if (ngx_strcmp(value[1].data, "X-Forwarded-For") == 0) {
  259.         rlcf->type = NGX_HTTP_REALIP_XFWD;
  260.         return NGX_CONF_OK;
  261.     }

  262.     if (ngx_strcmp(value[1].data, "proxy_protocol") == 0) {
  263.         rlcf->type = NGX_HTTP_REALIP_PROXY;
  264.         return NGX_CONF_OK;
  265.     }

  266.     rlcf->type = NGX_HTTP_REALIP_HEADER;
  267.     rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len);
  268.     rlcf->header = value[1];

  269.     return NGX_CONF_OK;
  270. }


  271. static void *
  272. ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
  273. {
  274.     ngx_http_realip_loc_conf_t  *conf;

  275.     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
  276.     if (conf == NULL) {
  277.         return NULL;
  278.     }

  279.     /*
  280.      * set by ngx_pcalloc():
  281.      *
  282.      *     conf->from = NULL;
  283.      *     conf->hash = 0;
  284.      *     conf->header = { 0, NULL };
  285.      */

  286.     conf->type = NGX_CONF_UNSET_UINT;
  287.     conf->recursive = NGX_CONF_UNSET;

  288.     return conf;
  289. }


  290. static char *
  291. ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
  292. {
  293.     ngx_http_realip_loc_conf_t  *prev = parent;
  294.     ngx_http_realip_loc_conf_t  *conf = child;

  295.     if (conf->from == NULL) {
  296.         conf->from = prev->from;
  297.     }

  298.     ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
  299.     ngx_conf_merge_value(conf->recursive, prev->recursive, 0);

  300.     if (conf->header.len == 0) {
  301.         conf->hash = prev->hash;
  302.         conf->header = prev->header;
  303.     }

  304.     return NGX_CONF_OK;
  305. }


  306. static ngx_int_t
  307. ngx_http_realip_init(ngx_conf_t *cf)
  308. {
  309.     ngx_http_handler_pt        *h;
  310.     ngx_http_core_main_conf_t  *cmcf;

  311.     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);

  312.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
  313.     if (h == NULL) {
  314.         return NGX_ERROR;
  315.     }

  316.     *h = ngx_http_realip_handler;

  317.     h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
  318.     if (h == NULL) {
  319.         return NGX_ERROR;
  320.     }

  321.     *h = ngx_http_realip_handler;

  322.     return NGX_OK;
  323. }