Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.19.2 ]​[ nginx-1.18.0 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 #define NGX_HTTP_REALIP_XREALIP  0
0014 #define NGX_HTTP_REALIP_XFWD     1
0015 #define NGX_HTTP_REALIP_HEADER   2
0016 #define NGX_HTTP_REALIP_PROXY    3
0017 
0018 
0019 typedef struct {
0020     ngx_array_t       *from;     /* array of ngx_cidr_t */
0021     ngx_uint_t         type;
0022     ngx_uint_t         hash;
0023     ngx_str_t          header;
0024     ngx_flag_t         recursive;
0025 } ngx_http_realip_loc_conf_t;
0026 
0027 
0028 typedef struct {
0029     ngx_connection_t  *connection;
0030     struct sockaddr   *sockaddr;
0031     socklen_t          socklen;
0032     ngx_str_t          addr_text;
0033 } ngx_http_realip_ctx_t;
0034 
0035 
0036 static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
0037 static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r,
0038     ngx_addr_t *addr);
0039 static void ngx_http_realip_cleanup(void *data);
0040 static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
0041     void *conf);
0042 static char *ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
0043 static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf);
0044 static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf,
0045     void *parent, void *child);
0046 static ngx_int_t ngx_http_realip_add_variables(ngx_conf_t *cf);
0047 static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf);
0048 static ngx_http_realip_ctx_t *ngx_http_realip_get_module_ctx(
0049     ngx_http_request_t *r);
0050 
0051 
0052 static ngx_int_t ngx_http_realip_remote_addr_variable(ngx_http_request_t *r,
0053     ngx_http_variable_value_t *v, uintptr_t data);
0054 static ngx_int_t ngx_http_realip_remote_port_variable(ngx_http_request_t *r,
0055     ngx_http_variable_value_t *v, uintptr_t data);
0056 
0057 
0058 static ngx_command_t  ngx_http_realip_commands[] = {
0059 
0060     { ngx_string("set_real_ip_from"),
0061       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0062       ngx_http_realip_from,
0063       NGX_HTTP_LOC_CONF_OFFSET,
0064       0,
0065       NULL },
0066 
0067     { ngx_string("real_ip_header"),
0068       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0069       ngx_http_realip,
0070       NGX_HTTP_LOC_CONF_OFFSET,
0071       0,
0072       NULL },
0073 
0074     { ngx_string("real_ip_recursive"),
0075       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
0076       ngx_conf_set_flag_slot,
0077       NGX_HTTP_LOC_CONF_OFFSET,
0078       offsetof(ngx_http_realip_loc_conf_t, recursive),
0079       NULL },
0080 
0081       ngx_null_command
0082 };
0083 
0084 
0085 
0086 static ngx_http_module_t  ngx_http_realip_module_ctx = {
0087     ngx_http_realip_add_variables,         /* preconfiguration */
0088     ngx_http_realip_init,                  /* postconfiguration */
0089 
0090     NULL,                                  /* create main configuration */
0091     NULL,                                  /* init main configuration */
0092 
0093     NULL,                                  /* create server configuration */
0094     NULL,                                  /* merge server configuration */
0095 
0096     ngx_http_realip_create_loc_conf,       /* create location configuration */
0097     ngx_http_realip_merge_loc_conf         /* merge location configuration */
0098 };
0099 
0100 
0101 ngx_module_t  ngx_http_realip_module = {
0102     NGX_MODULE_V1,
0103     &ngx_http_realip_module_ctx,           /* module context */
0104     ngx_http_realip_commands,              /* module directives */
0105     NGX_HTTP_MODULE,                       /* module type */
0106     NULL,                                  /* init master */
0107     NULL,                                  /* init module */
0108     NULL,                                  /* init process */
0109     NULL,                                  /* init thread */
0110     NULL,                                  /* exit thread */
0111     NULL,                                  /* exit process */
0112     NULL,                                  /* exit master */
0113     NGX_MODULE_V1_PADDING
0114 };
0115 
0116 
0117 static ngx_http_variable_t  ngx_http_realip_vars[] = {
0118 
0119     { ngx_string("realip_remote_addr"), NULL,
0120       ngx_http_realip_remote_addr_variable, 0, 0, 0 },
0121 
0122     { ngx_string("realip_remote_port"), NULL,
0123       ngx_http_realip_remote_port_variable, 0, 0, 0 },
0124 
0125       ngx_http_null_variable
0126 };
0127 
0128 
0129 static ngx_int_t
0130 ngx_http_realip_handler(ngx_http_request_t *r)
0131 {
0132     u_char                      *p;
0133     size_t                       len;
0134     ngx_str_t                   *value;
0135     ngx_uint_t                   i, hash;
0136     ngx_addr_t                   addr;
0137     ngx_array_t                 *xfwd;
0138     ngx_list_part_t             *part;
0139     ngx_table_elt_t             *header;
0140     ngx_connection_t            *c;
0141     ngx_http_realip_ctx_t       *ctx;
0142     ngx_http_realip_loc_conf_t  *rlcf;
0143 
0144     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
0145 
0146     if (rlcf->from == NULL) {
0147         return NGX_DECLINED;
0148     }
0149 
0150     ctx = ngx_http_realip_get_module_ctx(r);
0151 
0152     if (ctx) {
0153         return NGX_DECLINED;
0154     }
0155 
0156     switch (rlcf->type) {
0157 
0158     case NGX_HTTP_REALIP_XREALIP:
0159 
0160         if (r->headers_in.x_real_ip == NULL) {
0161             return NGX_DECLINED;
0162         }
0163 
0164         value = &r->headers_in.x_real_ip->value;
0165         xfwd = NULL;
0166 
0167         break;
0168 
0169     case NGX_HTTP_REALIP_XFWD:
0170 
0171         xfwd = &r->headers_in.x_forwarded_for;
0172 
0173         if (xfwd->elts == NULL) {
0174             return NGX_DECLINED;
0175         }
0176 
0177         value = NULL;
0178 
0179         break;
0180 
0181     case NGX_HTTP_REALIP_PROXY:
0182 
0183         if (r->connection->proxy_protocol == NULL) {
0184             return NGX_DECLINED;
0185         }
0186 
0187         value = &r->connection->proxy_protocol->src_addr;
0188         xfwd = NULL;
0189 
0190         break;
0191 
0192     default: /* NGX_HTTP_REALIP_HEADER */
0193 
0194         part = &r->headers_in.headers.part;
0195         header = part->elts;
0196 
0197         hash = rlcf->hash;
0198         len = rlcf->header.len;
0199         p = rlcf->header.data;
0200 
0201         for (i = 0; /* void */ ; i++) {
0202 
0203             if (i >= part->nelts) {
0204                 if (part->next == NULL) {
0205                     break;
0206                 }
0207 
0208                 part = part->next;
0209                 header = part->elts;
0210                 i = 0;
0211             }
0212 
0213             if (hash == header[i].hash
0214                 && len == header[i].key.len
0215                 && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
0216             {
0217                 value = &header[i].value;
0218                 xfwd = NULL;
0219 
0220                 goto found;
0221             }
0222         }
0223 
0224         return NGX_DECLINED;
0225     }
0226 
0227 found:
0228 
0229     c = r->connection;
0230 
0231     addr.sockaddr = c->sockaddr;
0232     addr.socklen = c->socklen;
0233     /* addr.name = c->addr_text; */
0234 
0235     if (ngx_http_get_forwarded_addr(r, &addr, xfwd, value, rlcf->from,
0236                                     rlcf->recursive)
0237         != NGX_DECLINED)
0238     {
0239         if (rlcf->type == NGX_HTTP_REALIP_PROXY) {
0240             ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port);
0241         }
0242 
0243         return ngx_http_realip_set_addr(r, &addr);
0244     }
0245 
0246     return NGX_DECLINED;
0247 }
0248 
0249 
0250 static ngx_int_t
0251 ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr)
0252 {
0253     size_t                  len;
0254     u_char                 *p;
0255     u_char                  text[NGX_SOCKADDR_STRLEN];
0256     ngx_connection_t       *c;
0257     ngx_pool_cleanup_t     *cln;
0258     ngx_http_realip_ctx_t  *ctx;
0259 
0260     cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
0261     if (cln == NULL) {
0262         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0263     }
0264 
0265     ctx = cln->data;
0266 
0267     c = r->connection;
0268 
0269     len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text,
0270                         NGX_SOCKADDR_STRLEN, 0);
0271     if (len == 0) {
0272         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0273     }
0274 
0275     p = ngx_pnalloc(c->pool, len);
0276     if (p == NULL) {
0277         return NGX_HTTP_INTERNAL_SERVER_ERROR;
0278     }
0279 
0280     ngx_memcpy(p, text, len);
0281 
0282     cln->handler = ngx_http_realip_cleanup;
0283     ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
0284 
0285     ctx->connection = c;
0286     ctx->sockaddr = c->sockaddr;
0287     ctx->socklen = c->socklen;
0288     ctx->addr_text = c->addr_text;
0289 
0290     c->sockaddr = addr->sockaddr;
0291     c->socklen = addr->socklen;
0292     c->addr_text.len = len;
0293     c->addr_text.data = p;
0294 
0295     return NGX_DECLINED;
0296 }
0297 
0298 
0299 static void
0300 ngx_http_realip_cleanup(void *data)
0301 {
0302     ngx_http_realip_ctx_t *ctx = data;
0303 
0304     ngx_connection_t  *c;
0305 
0306     c = ctx->connection;
0307 
0308     c->sockaddr = ctx->sockaddr;
0309     c->socklen = ctx->socklen;
0310     c->addr_text = ctx->addr_text;
0311 }
0312 
0313 
0314 static char *
0315 ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0316 {
0317     ngx_http_realip_loc_conf_t *rlcf = conf;
0318 
0319     ngx_int_t             rc;
0320     ngx_str_t            *value;
0321     ngx_url_t             u;
0322     ngx_cidr_t            c, *cidr;
0323     ngx_uint_t            i;
0324     struct sockaddr_in   *sin;
0325 #if (NGX_HAVE_INET6)
0326     struct sockaddr_in6  *sin6;
0327 #endif
0328 
0329     value = cf->args->elts;
0330 
0331     if (rlcf->from == NULL) {
0332         rlcf->from = ngx_array_create(cf->pool, 2,
0333                                       sizeof(ngx_cidr_t));
0334         if (rlcf->from == NULL) {
0335             return NGX_CONF_ERROR;
0336         }
0337     }
0338 
0339 #if (NGX_HAVE_UNIX_DOMAIN)
0340 
0341     if (ngx_strcmp(value[1].data, "unix:") == 0) {
0342         cidr = ngx_array_push(rlcf->from);
0343         if (cidr == NULL) {
0344             return NGX_CONF_ERROR;
0345         }
0346 
0347         cidr->family = AF_UNIX;
0348         return NGX_CONF_OK;
0349     }
0350 
0351 #endif
0352 
0353     rc = ngx_ptocidr(&value[1], &c);
0354 
0355     if (rc != NGX_ERROR) {
0356         if (rc == NGX_DONE) {
0357             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
0358                                "low address bits of %V are meaningless",
0359                                &value[1]);
0360         }
0361 
0362         cidr = ngx_array_push(rlcf->from);
0363         if (cidr == NULL) {
0364             return NGX_CONF_ERROR;
0365         }
0366 
0367         *cidr = c;
0368 
0369         return NGX_CONF_OK;
0370     }
0371 
0372     ngx_memzero(&u, sizeof(ngx_url_t));
0373     u.host = value[1];
0374 
0375     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
0376         if (u.err) {
0377             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0378                                "%s in set_real_ip_from \"%V\"",
0379                                u.err, &u.host);
0380         }
0381 
0382         return NGX_CONF_ERROR;
0383     }
0384 
0385     cidr = ngx_array_push_n(rlcf->from, u.naddrs);
0386     if (cidr == NULL) {
0387         return NGX_CONF_ERROR;
0388     }
0389 
0390     ngx_memzero(cidr, u.naddrs * sizeof(ngx_cidr_t));
0391 
0392     for (i = 0; i < u.naddrs; i++) {
0393         cidr[i].family = u.addrs[i].sockaddr->sa_family;
0394 
0395         switch (cidr[i].family) {
0396 
0397 #if (NGX_HAVE_INET6)
0398         case AF_INET6:
0399             sin6 = (struct sockaddr_in6 *) u.addrs[i].sockaddr;
0400             cidr[i].u.in6.addr = sin6->sin6_addr;
0401             ngx_memset(cidr[i].u.in6.mask.s6_addr, 0xff, 16);
0402             break;
0403 #endif
0404 
0405         default: /* AF_INET */
0406             sin = (struct sockaddr_in *) u.addrs[i].sockaddr;
0407             cidr[i].u.in.addr = sin->sin_addr.s_addr;
0408             cidr[i].u.in.mask = 0xffffffff;
0409             break;
0410         }
0411     }
0412 
0413     return NGX_CONF_OK;
0414 }
0415 
0416 
0417 static char *
0418 ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0419 {
0420     ngx_http_realip_loc_conf_t *rlcf = conf;
0421 
0422     ngx_str_t  *value;
0423 
0424     if (rlcf->type != NGX_CONF_UNSET_UINT) {
0425         return "is duplicate";
0426     }
0427 
0428     value = cf->args->elts;
0429 
0430     if (ngx_strcmp(value[1].data, "X-Real-IP") == 0) {
0431         rlcf->type = NGX_HTTP_REALIP_XREALIP;
0432         return NGX_CONF_OK;
0433     }
0434 
0435     if (ngx_strcmp(value[1].data, "X-Forwarded-For") == 0) {
0436         rlcf->type = NGX_HTTP_REALIP_XFWD;
0437         return NGX_CONF_OK;
0438     }
0439 
0440     if (ngx_strcmp(value[1].data, "proxy_protocol") == 0) {
0441         rlcf->type = NGX_HTTP_REALIP_PROXY;
0442         return NGX_CONF_OK;
0443     }
0444 
0445     rlcf->type = NGX_HTTP_REALIP_HEADER;
0446     rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len);
0447     rlcf->header = value[1];
0448 
0449     return NGX_CONF_OK;
0450 }
0451 
0452 
0453 static void *
0454 ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
0455 {
0456     ngx_http_realip_loc_conf_t  *conf;
0457 
0458     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
0459     if (conf == NULL) {
0460         return NULL;
0461     }
0462 
0463     /*
0464      * set by ngx_pcalloc():
0465      *
0466      *     conf->from = NULL;
0467      *     conf->hash = 0;
0468      *     conf->header = { 0, NULL };
0469      */
0470 
0471     conf->type = NGX_CONF_UNSET_UINT;
0472     conf->recursive = NGX_CONF_UNSET;
0473 
0474     return conf;
0475 }
0476 
0477 
0478 static char *
0479 ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
0480 {
0481     ngx_http_realip_loc_conf_t  *prev = parent;
0482     ngx_http_realip_loc_conf_t  *conf = child;
0483 
0484     if (conf->from == NULL) {
0485         conf->from = prev->from;
0486     }
0487 
0488     ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
0489     ngx_conf_merge_value(conf->recursive, prev->recursive, 0);
0490 
0491     if (conf->header.len == 0) {
0492         conf->hash = prev->hash;
0493         conf->header = prev->header;
0494     }
0495 
0496     return NGX_CONF_OK;
0497 }
0498 
0499 
0500 static ngx_int_t
0501 ngx_http_realip_add_variables(ngx_conf_t *cf)
0502 {
0503     ngx_http_variable_t  *var, *v;
0504 
0505     for (v = ngx_http_realip_vars; v->name.len; v++) {
0506         var = ngx_http_add_variable(cf, &v->name, v->flags);
0507         if (var == NULL) {
0508             return NGX_ERROR;
0509         }
0510 
0511         var->get_handler = v->get_handler;
0512         var->data = v->data;
0513     }
0514 
0515     return NGX_OK;
0516 }
0517 
0518 
0519 static ngx_int_t
0520 ngx_http_realip_init(ngx_conf_t *cf)
0521 {
0522     ngx_http_handler_pt        *h;
0523     ngx_http_core_main_conf_t  *cmcf;
0524 
0525     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
0526 
0527     h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
0528     if (h == NULL) {
0529         return NGX_ERROR;
0530     }
0531 
0532     *h = ngx_http_realip_handler;
0533 
0534     h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
0535     if (h == NULL) {
0536         return NGX_ERROR;
0537     }
0538 
0539     *h = ngx_http_realip_handler;
0540 
0541     return NGX_OK;
0542 }
0543 
0544 
0545 static ngx_http_realip_ctx_t *
0546 ngx_http_realip_get_module_ctx(ngx_http_request_t *r)
0547 {
0548     ngx_pool_cleanup_t     *cln;
0549     ngx_http_realip_ctx_t  *ctx;
0550 
0551     ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);
0552 
0553     if (ctx == NULL && (r->internal || r->filter_finalize)) {
0554 
0555         /*
0556          * if module context was reset, the original address
0557          * can still be found in the cleanup handler
0558          */
0559 
0560         for (cln = r->pool->cleanup; cln; cln = cln->next) {
0561             if (cln->handler == ngx_http_realip_cleanup) {
0562                 ctx = cln->data;
0563                 break;
0564             }
0565         }
0566     }
0567 
0568     return ctx;
0569 }
0570 
0571 
0572 static ngx_int_t
0573 ngx_http_realip_remote_addr_variable(ngx_http_request_t *r,
0574     ngx_http_variable_value_t *v, uintptr_t data)
0575 {
0576     ngx_str_t              *addr_text;
0577     ngx_http_realip_ctx_t  *ctx;
0578 
0579     ctx = ngx_http_realip_get_module_ctx(r);
0580 
0581     addr_text = ctx ? &ctx->addr_text : &r->connection->addr_text;
0582 
0583     v->len = addr_text->len;
0584     v->valid = 1;
0585     v->no_cacheable = 0;
0586     v->not_found = 0;
0587     v->data = addr_text->data;
0588 
0589     return NGX_OK;
0590 }
0591 
0592 
0593 static ngx_int_t
0594 ngx_http_realip_remote_port_variable(ngx_http_request_t *r,
0595     ngx_http_variable_value_t *v, uintptr_t data)
0596 {
0597     ngx_uint_t              port;
0598     struct sockaddr        *sa;
0599     ngx_http_realip_ctx_t  *ctx;
0600 
0601     ctx = ngx_http_realip_get_module_ctx(r);
0602 
0603     sa = ctx ? ctx->sockaddr : r->connection->sockaddr;
0604 
0605     v->len = 0;
0606     v->valid = 1;
0607     v->no_cacheable = 0;
0608     v->not_found = 0;
0609 
0610     v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
0611     if (v->data == NULL) {
0612         return NGX_ERROR;
0613     }
0614 
0615     port = ngx_inet_get_port(sa);
0616 
0617     if (port > 0 && port < 65536) {
0618         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
0619     }
0620 
0621     return NGX_OK;
0622 }