1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 #define NGX_HTTP_REALIP_XREALIP  0
14 #define NGX_HTTP_REALIP_XFWD     1
15 #define NGX_HTTP_REALIP_HEADER   2
16 #define NGX_HTTP_REALIP_PROXY    3
17 
18 
19 typedef struct {
20     ngx_array_t       *from;     /* array of ngx_cidr_t */
21     ngx_uint_t         type;
22     ngx_uint_t         hash;
23     ngx_str_t          header;
24     ngx_flag_t         recursive;
25 } ngx_http_realip_loc_conf_t;
26 
27 
28 typedef struct {
29     ngx_connection_t  *connection;
30     struct sockaddr   *sockaddr;
31     socklen_t          socklen;
32     ngx_str_t          addr_text;
33 } ngx_http_realip_ctx_t;
34 
35 
36 static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
37 static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r,
38     ngx_addr_t *addr);
39 static void ngx_http_realip_cleanup(void *data);
40 static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
41     void *conf);
42 static char *ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
43 static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf);
44 static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf,
45     void *parent, void *child);
46 static ngx_int_t ngx_http_realip_add_variables(ngx_conf_t *cf);
47 static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf);
48 static ngx_http_realip_ctx_t *ngx_http_realip_get_module_ctx(
49     ngx_http_request_t *r);
50 
51 
52 static ngx_int_t ngx_http_realip_remote_addr_variable(ngx_http_request_t *r,
53     ngx_http_variable_value_t *v, uintptr_t data);
54 static ngx_int_t ngx_http_realip_remote_port_variable(ngx_http_request_t *r,
55     ngx_http_variable_value_t *v, uintptr_t data);
56 
57 
58 static ngx_command_t  ngx_http_realip_commands[] = {
59 
60     { ngx_string("set_real_ip_from"),
61       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
62       ngx_http_realip_from,
63       NGX_HTTP_LOC_CONF_OFFSET,
64       0,
65       NULL },
66 
67     { ngx_string("real_ip_header"),
68       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
69       ngx_http_realip,
70       NGX_HTTP_LOC_CONF_OFFSET,
71       0,
72       NULL },
73 
74     { ngx_string("real_ip_recursive"),
75       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
76       ngx_conf_set_flag_slot,
77       NGX_HTTP_LOC_CONF_OFFSET,
78       offsetof(ngx_http_realip_loc_conf_t, recursive),
79       NULL },
80 
81       ngx_null_command
82 };
83 
84 
85 
86 static ngx_http_module_t  ngx_http_realip_module_ctx = {
87     ngx_http_realip_add_variables,         /* preconfiguration */
88     ngx_http_realip_init,                  /* postconfiguration */
89 
90     NULL,                                  /* create main configuration */
91     NULL,                                  /* init main configuration */
92 
93     NULL,                                  /* create server configuration */
94     NULL,                                  /* merge server configuration */
95 
96     ngx_http_realip_create_loc_conf,       /* create location configuration */
97     ngx_http_realip_merge_loc_conf         /* merge location configuration */
98 };
99 
100 
101 ngx_module_t  ngx_http_realip_module = {
102     NGX_MODULE_V1,
103     &ngx_http_realip_module_ctx,           /* module context */
104     ngx_http_realip_commands,              /* module directives */
105     NGX_HTTP_MODULE,                       /* module type */
106     NULL,                                  /* init master */
107     NULL,                                  /* init module */
108     NULL,                                  /* init process */
109     NULL,                                  /* init thread */
110     NULL,                                  /* exit thread */
111     NULL,                                  /* exit process */
112     NULL,                                  /* exit master */
113     NGX_MODULE_V1_PADDING
114 };
115 
116 
117 static ngx_http_variable_t  ngx_http_realip_vars[] = {
118 
119     { ngx_string("realip_remote_addr"), NULL,
120       ngx_http_realip_remote_addr_variable, 0, 0, 0 },
121 
122     { ngx_string("realip_remote_port"), NULL,
123       ngx_http_realip_remote_port_variable, 0, 0, 0 },
124 
125       ngx_http_null_variable
126 };
127 
128 
129 static ngx_int_t
ngx_http_realip_handler(ngx_http_request_t * r)130 ngx_http_realip_handler(ngx_http_request_t *r)
131 {
132     u_char                      *p;
133     size_t                       len;
134     ngx_str_t                   *value;
135     ngx_uint_t                   i, hash;
136     ngx_addr_t                   addr;
137     ngx_array_t                 *xfwd;
138     ngx_list_part_t             *part;
139     ngx_table_elt_t             *header;
140     ngx_connection_t            *c;
141     ngx_http_realip_ctx_t       *ctx;
142     ngx_http_realip_loc_conf_t  *rlcf;
143 
144     rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
145 
146     if (rlcf->from == NULL) {
147         return NGX_DECLINED;
148     }
149 
150     ctx = ngx_http_realip_get_module_ctx(r);
151 
152     if (ctx) {
153         return NGX_DECLINED;
154     }
155 
156     switch (rlcf->type) {
157 
158     case NGX_HTTP_REALIP_XREALIP:
159 
160         if (r->headers_in.x_real_ip == NULL) {
161             return NGX_DECLINED;
162         }
163 
164         value = &r->headers_in.x_real_ip->value;
165         xfwd = NULL;
166 
167         break;
168 
169     case NGX_HTTP_REALIP_XFWD:
170 
171         xfwd = &r->headers_in.x_forwarded_for;
172 
173         if (xfwd->elts == NULL) {
174             return NGX_DECLINED;
175         }
176 
177         value = NULL;
178 
179         break;
180 
181     case NGX_HTTP_REALIP_PROXY:
182 
183         value = &r->connection->proxy_protocol_addr;
184 
185         if (value->len == 0) {
186             return NGX_DECLINED;
187         }
188 
189         xfwd = NULL;
190 
191         break;
192 
193     default: /* NGX_HTTP_REALIP_HEADER */
194 
195         part = &r->headers_in.headers.part;
196         header = part->elts;
197 
198         hash = rlcf->hash;
199         len = rlcf->header.len;
200         p = rlcf->header.data;
201 
202         for (i = 0; /* void */ ; i++) {
203 
204             if (i >= part->nelts) {
205                 if (part->next == NULL) {
206                     break;
207                 }
208 
209                 part = part->next;
210                 header = part->elts;
211                 i = 0;
212             }
213 
214             if (hash == header[i].hash
215                 && len == header[i].key.len
216                 && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
217             {
218                 value = &header[i].value;
219                 xfwd = NULL;
220 
221                 goto found;
222             }
223         }
224 
225         return NGX_DECLINED;
226     }
227 
228 found:
229 
230     c = r->connection;
231 
232     addr.sockaddr = c->sockaddr;
233     addr.socklen = c->socklen;
234     /* addr.name = c->addr_text; */
235 
236     if (ngx_http_get_forwarded_addr(r, &addr, xfwd, value, rlcf->from,
237                                     rlcf->recursive)
238         != NGX_DECLINED)
239     {
240         if (rlcf->type == NGX_HTTP_REALIP_PROXY) {
241             ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port);
242         }
243 
244         return ngx_http_realip_set_addr(r, &addr);
245     }
246 
247     return NGX_DECLINED;
248 }
249 
250 
251 static ngx_int_t
ngx_http_realip_set_addr(ngx_http_request_t * r,ngx_addr_t * addr)252 ngx_http_realip_set_addr(ngx_http_request_t *r, ngx_addr_t *addr)
253 {
254     size_t                  len;
255     u_char                 *p;
256     u_char                  text[NGX_SOCKADDR_STRLEN];
257     ngx_connection_t       *c;
258     ngx_pool_cleanup_t     *cln;
259     ngx_http_realip_ctx_t  *ctx;
260 
261     cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
262     if (cln == NULL) {
263         return NGX_HTTP_INTERNAL_SERVER_ERROR;
264     }
265 
266     ctx = cln->data;
267 
268     c = r->connection;
269 
270     len = ngx_sock_ntop(addr->sockaddr, addr->socklen, text,
271                         NGX_SOCKADDR_STRLEN, 0);
272     if (len == 0) {
273         return NGX_HTTP_INTERNAL_SERVER_ERROR;
274     }
275 
276     p = ngx_pnalloc(c->pool, len);
277     if (p == NULL) {
278         return NGX_HTTP_INTERNAL_SERVER_ERROR;
279     }
280 
281     ngx_memcpy(p, text, len);
282 
283     cln->handler = ngx_http_realip_cleanup;
284     ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
285 
286     ctx->connection = c;
287     ctx->sockaddr = c->sockaddr;
288     ctx->socklen = c->socklen;
289     ctx->addr_text = c->addr_text;
290 
291     c->sockaddr = addr->sockaddr;
292     c->socklen = addr->socklen;
293     c->addr_text.len = len;
294     c->addr_text.data = p;
295 
296     return NGX_DECLINED;
297 }
298 
299 
300 static void
ngx_http_realip_cleanup(void * data)301 ngx_http_realip_cleanup(void *data)
302 {
303     ngx_http_realip_ctx_t *ctx = data;
304 
305     ngx_connection_t  *c;
306 
307     c = ctx->connection;
308 
309     c->sockaddr = ctx->sockaddr;
310     c->socklen = ctx->socklen;
311     c->addr_text = ctx->addr_text;
312 }
313 
314 
315 static char *
ngx_http_realip_from(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)316 ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
317 {
318     ngx_http_realip_loc_conf_t *rlcf = conf;
319 
320     ngx_int_t             rc;
321     ngx_str_t            *value;
322     ngx_url_t             u;
323     ngx_cidr_t            c, *cidr;
324     ngx_uint_t            i;
325     struct sockaddr_in   *sin;
326 #if (NGX_HAVE_INET6)
327     struct sockaddr_in6  *sin6;
328 #endif
329 
330     value = cf->args->elts;
331 
332     if (rlcf->from == NULL) {
333         rlcf->from = ngx_array_create(cf->pool, 2,
334                                       sizeof(ngx_cidr_t));
335         if (rlcf->from == NULL) {
336             return NGX_CONF_ERROR;
337         }
338     }
339 
340 #if (NGX_HAVE_UNIX_DOMAIN)
341 
342     if (ngx_strcmp(value[1].data, "unix:") == 0) {
343         cidr = ngx_array_push(rlcf->from);
344         if (cidr == NULL) {
345             return NGX_CONF_ERROR;
346         }
347 
348         cidr->family = AF_UNIX;
349         return NGX_CONF_OK;
350     }
351 
352 #endif
353 
354     rc = ngx_ptocidr(&value[1], &c);
355 
356     if (rc != NGX_ERROR) {
357         if (rc == NGX_DONE) {
358             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
359                                "low address bits of %V are meaningless",
360                                &value[1]);
361         }
362 
363         cidr = ngx_array_push(rlcf->from);
364         if (cidr == NULL) {
365             return NGX_CONF_ERROR;
366         }
367 
368         *cidr = c;
369 
370         return NGX_CONF_OK;
371     }
372 
373     ngx_memzero(&u, sizeof(ngx_url_t));
374     u.host = value[1];
375 
376     if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
377         if (u.err) {
378             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
379                                "%s in set_real_ip_from \"%V\"",
380                                u.err, &u.host);
381         }
382 
383         return NGX_CONF_ERROR;
384     }
385 
386     cidr = ngx_array_push_n(rlcf->from, u.naddrs);
387     if (cidr == NULL) {
388         return NGX_CONF_ERROR;
389     }
390 
391     ngx_memzero(cidr, u.naddrs * sizeof(ngx_cidr_t));
392 
393     for (i = 0; i < u.naddrs; i++) {
394         cidr[i].family = u.addrs[i].sockaddr->sa_family;
395 
396         switch (cidr[i].family) {
397 
398 #if (NGX_HAVE_INET6)
399         case AF_INET6:
400             sin6 = (struct sockaddr_in6 *) u.addrs[i].sockaddr;
401             cidr[i].u.in6.addr = sin6->sin6_addr;
402             ngx_memset(cidr[i].u.in6.mask.s6_addr, 0xff, 16);
403             break;
404 #endif
405 
406         default: /* AF_INET */
407             sin = (struct sockaddr_in *) u.addrs[i].sockaddr;
408             cidr[i].u.in.addr = sin->sin_addr.s_addr;
409             cidr[i].u.in.mask = 0xffffffff;
410             break;
411         }
412     }
413 
414     return NGX_CONF_OK;
415 }
416 
417 
418 static char *
ngx_http_realip(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)419 ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
420 {
421     ngx_http_realip_loc_conf_t *rlcf = conf;
422 
423     ngx_str_t  *value;
424 
425     if (rlcf->type != NGX_CONF_UNSET_UINT) {
426         return "is duplicate";
427     }
428 
429     value = cf->args->elts;
430 
431     if (ngx_strcmp(value[1].data, "X-Real-IP") == 0) {
432         rlcf->type = NGX_HTTP_REALIP_XREALIP;
433         return NGX_CONF_OK;
434     }
435 
436     if (ngx_strcmp(value[1].data, "X-Forwarded-For") == 0) {
437         rlcf->type = NGX_HTTP_REALIP_XFWD;
438         return NGX_CONF_OK;
439     }
440 
441     if (ngx_strcmp(value[1].data, "proxy_protocol") == 0) {
442         rlcf->type = NGX_HTTP_REALIP_PROXY;
443         return NGX_CONF_OK;
444     }
445 
446     rlcf->type = NGX_HTTP_REALIP_HEADER;
447     rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len);
448     rlcf->header = value[1];
449 
450     return NGX_CONF_OK;
451 }
452 
453 
454 static void *
ngx_http_realip_create_loc_conf(ngx_conf_t * cf)455 ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
456 {
457     ngx_http_realip_loc_conf_t  *conf;
458 
459     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
460     if (conf == NULL) {
461         return NULL;
462     }
463 
464     /*
465      * set by ngx_pcalloc():
466      *
467      *     conf->from = NULL;
468      *     conf->hash = 0;
469      *     conf->header = { 0, NULL };
470      */
471 
472     conf->type = NGX_CONF_UNSET_UINT;
473     conf->recursive = NGX_CONF_UNSET;
474 
475     return conf;
476 }
477 
478 
479 static char *
ngx_http_realip_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)480 ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
481 {
482     ngx_http_realip_loc_conf_t  *prev = parent;
483     ngx_http_realip_loc_conf_t  *conf = child;
484 
485     if (conf->from == NULL) {
486         conf->from = prev->from;
487     }
488 
489     ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
490     ngx_conf_merge_value(conf->recursive, prev->recursive, 0);
491 
492     if (conf->header.len == 0) {
493         conf->hash = prev->hash;
494         conf->header = prev->header;
495     }
496 
497     return NGX_CONF_OK;
498 }
499 
500 
501 static ngx_int_t
ngx_http_realip_add_variables(ngx_conf_t * cf)502 ngx_http_realip_add_variables(ngx_conf_t *cf)
503 {
504     ngx_http_variable_t  *var, *v;
505 
506     for (v = ngx_http_realip_vars; v->name.len; v++) {
507         var = ngx_http_add_variable(cf, &v->name, v->flags);
508         if (var == NULL) {
509             return NGX_ERROR;
510         }
511 
512         var->get_handler = v->get_handler;
513         var->data = v->data;
514     }
515 
516     return NGX_OK;
517 }
518 
519 
520 static ngx_int_t
ngx_http_realip_init(ngx_conf_t * cf)521 ngx_http_realip_init(ngx_conf_t *cf)
522 {
523     ngx_http_handler_pt        *h;
524     ngx_http_core_main_conf_t  *cmcf;
525 
526     cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
527 
528     h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
529     if (h == NULL) {
530         return NGX_ERROR;
531     }
532 
533     *h = ngx_http_realip_handler;
534 
535     h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
536     if (h == NULL) {
537         return NGX_ERROR;
538     }
539 
540     *h = ngx_http_realip_handler;
541 
542     return NGX_OK;
543 }
544 
545 
546 static ngx_http_realip_ctx_t *
ngx_http_realip_get_module_ctx(ngx_http_request_t * r)547 ngx_http_realip_get_module_ctx(ngx_http_request_t *r)
548 {
549     ngx_pool_cleanup_t     *cln;
550     ngx_http_realip_ctx_t  *ctx;
551 
552     ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);
553 
554     if (ctx == NULL && (r->internal || r->filter_finalize)) {
555 
556         /*
557          * if module context was reset, the original address
558          * can still be found in the cleanup handler
559          */
560 
561         for (cln = r->pool->cleanup; cln; cln = cln->next) {
562             if (cln->handler == ngx_http_realip_cleanup) {
563                 ctx = cln->data;
564                 break;
565             }
566         }
567     }
568 
569     return ctx;
570 }
571 
572 
573 static ngx_int_t
ngx_http_realip_remote_addr_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)574 ngx_http_realip_remote_addr_variable(ngx_http_request_t *r,
575     ngx_http_variable_value_t *v, uintptr_t data)
576 {
577     ngx_str_t              *addr_text;
578     ngx_http_realip_ctx_t  *ctx;
579 
580     ctx = ngx_http_realip_get_module_ctx(r);
581 
582     addr_text = ctx ? &ctx->addr_text : &r->connection->addr_text;
583 
584     v->len = addr_text->len;
585     v->valid = 1;
586     v->no_cacheable = 0;
587     v->not_found = 0;
588     v->data = addr_text->data;
589 
590     return NGX_OK;
591 }
592 
593 
594 static ngx_int_t
ngx_http_realip_remote_port_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)595 ngx_http_realip_remote_port_variable(ngx_http_request_t *r,
596     ngx_http_variable_value_t *v, uintptr_t data)
597 {
598     ngx_uint_t              port;
599     struct sockaddr        *sa;
600     ngx_http_realip_ctx_t  *ctx;
601 
602     ctx = ngx_http_realip_get_module_ctx(r);
603 
604     sa = ctx ? ctx->sockaddr : r->connection->sockaddr;
605 
606     v->len = 0;
607     v->valid = 1;
608     v->no_cacheable = 0;
609     v->not_found = 0;
610 
611     v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1);
612     if (v->data == NULL) {
613         return NGX_ERROR;
614     }
615 
616     port = ngx_inet_get_port(sa);
617 
618     if (port > 0 && port < 65536) {
619         v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
620     }
621 
622     return NGX_OK;
623 }
624