3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
13 #define NGX_HTTP_REALIP_XREALIP 0
14 #define NGX_HTTP_REALIP_XFWD 1
15 #define NGX_HTTP_REALIP_HEADER 2
19 ngx_array_t
*from
; /* array of ngx_cidr_t */
24 } ngx_http_realip_loc_conf_t
;
28 ngx_connection_t
*connection
;
29 struct sockaddr
*sockaddr
;
32 } ngx_http_realip_ctx_t
;
35 static ngx_int_t
ngx_http_realip_handler(ngx_http_request_t
*r
);
36 static ngx_int_t
ngx_http_realip_set_addr(ngx_http_request_t
*r
,
38 static void ngx_http_realip_cleanup(void *data
);
39 static char *ngx_http_realip_from(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
41 static char *ngx_http_realip(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
);
42 static void *ngx_http_realip_create_loc_conf(ngx_conf_t
*cf
);
43 static char *ngx_http_realip_merge_loc_conf(ngx_conf_t
*cf
,
44 void *parent
, void *child
);
45 static ngx_int_t
ngx_http_realip_init(ngx_conf_t
*cf
);
48 static ngx_command_t ngx_http_realip_commands
[] = {
50 { ngx_string("set_real_ip_from"),
51 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
53 NGX_HTTP_LOC_CONF_OFFSET
,
57 { ngx_string("real_ip_header"),
58 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_TAKE1
,
60 NGX_HTTP_LOC_CONF_OFFSET
,
64 { ngx_string("real_ip_recursive"),
65 NGX_HTTP_MAIN_CONF
|NGX_HTTP_SRV_CONF
|NGX_HTTP_LOC_CONF
|NGX_CONF_FLAG
,
66 ngx_conf_set_flag_slot
,
67 NGX_HTTP_LOC_CONF_OFFSET
,
68 offsetof(ngx_http_realip_loc_conf_t
, recursive
),
76 static ngx_http_module_t ngx_http_realip_module_ctx
= {
77 NULL
, /* preconfiguration */
78 ngx_http_realip_init
, /* postconfiguration */
80 NULL
, /* create main configuration */
81 NULL
, /* init main configuration */
83 NULL
, /* create server configuration */
84 NULL
, /* merge server configuration */
86 ngx_http_realip_create_loc_conf
, /* create location configuration */
87 ngx_http_realip_merge_loc_conf
/* merge location configuration */
91 ngx_module_t ngx_http_realip_module
= {
93 &ngx_http_realip_module_ctx
, /* module context */
94 ngx_http_realip_commands
, /* module directives */
95 NGX_HTTP_MODULE
, /* module type */
96 NULL
, /* init master */
97 NULL
, /* init module */
98 NULL
, /* init process */
99 NULL
, /* init thread */
100 NULL
, /* exit thread */
101 NULL
, /* exit process */
102 NULL
, /* exit master */
103 NGX_MODULE_V1_PADDING
108 ngx_http_realip_handler(ngx_http_request_t
*r
)
116 ngx_list_part_t
*part
;
117 ngx_table_elt_t
*header
;
119 ngx_http_realip_ctx_t
*ctx
;
120 ngx_http_realip_loc_conf_t
*rlcf
;
122 ctx
= ngx_http_get_module_ctx(r
, ngx_http_realip_module
);
128 rlcf
= ngx_http_get_module_loc_conf(r
, ngx_http_realip_module
);
130 if (rlcf
->from
== NULL
) {
134 switch (rlcf
->type
) {
136 case NGX_HTTP_REALIP_XREALIP
:
138 if (r
->headers_in
.x_real_ip
== NULL
) {
142 value
= &r
->headers_in
.x_real_ip
->value
;
147 case NGX_HTTP_REALIP_XFWD
:
149 xfwd
= &r
->headers_in
.x_forwarded_for
;
151 if (xfwd
->elts
== NULL
) {
159 default: /* NGX_HTTP_REALIP_HEADER */
161 part
= &r
->headers_in
.headers
.part
;
165 len
= rlcf
->header
.len
;
166 p
= rlcf
->header
.data
;
168 for (i
= 0; /* void */ ; i
++) {
170 if (i
>= part
->nelts
) {
171 if (part
->next
== NULL
) {
180 if (hash
== header
[i
].hash
181 && len
== header
[i
].key
.len
182 && ngx_strncmp(p
, header
[i
].lowcase_key
, len
) == 0)
184 value
= &header
[i
].value
;
198 addr
.sockaddr
= c
->sockaddr
;
199 addr
.socklen
= c
->socklen
;
200 /* addr.name = c->addr_text; */
202 if (ngx_http_get_forwarded_addr(r
, &addr
, xfwd
, value
, rlcf
->from
,
206 return ngx_http_realip_set_addr(r
, &addr
);
214 ngx_http_realip_set_addr(ngx_http_request_t
*r
, ngx_addr_t
*addr
)
218 u_char text
[NGX_SOCKADDR_STRLEN
];
220 ngx_pool_cleanup_t
*cln
;
221 ngx_http_realip_ctx_t
*ctx
;
223 cln
= ngx_pool_cleanup_add(r
->pool
, sizeof(ngx_http_realip_ctx_t
));
225 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
229 ngx_http_set_ctx(r
, ctx
, ngx_http_realip_module
);
233 len
= ngx_sock_ntop(addr
->sockaddr
, text
, NGX_SOCKADDR_STRLEN
, 0);
235 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
238 p
= ngx_pnalloc(c
->pool
, len
);
240 return NGX_HTTP_INTERNAL_SERVER_ERROR
;
243 ngx_memcpy(p
, text
, len
);
245 cln
->handler
= ngx_http_realip_cleanup
;
248 ctx
->sockaddr
= c
->sockaddr
;
249 ctx
->socklen
= c
->socklen
;
250 ctx
->addr_text
= c
->addr_text
;
252 c
->sockaddr
= addr
->sockaddr
;
253 c
->socklen
= addr
->socklen
;
254 c
->addr_text
.len
= len
;
255 c
->addr_text
.data
= p
;
262 ngx_http_realip_cleanup(void *data
)
264 ngx_http_realip_ctx_t
*ctx
= data
;
270 c
->sockaddr
= ctx
->sockaddr
;
271 c
->socklen
= ctx
->socklen
;
272 c
->addr_text
= ctx
->addr_text
;
277 ngx_http_realip_from(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
279 ngx_http_realip_loc_conf_t
*rlcf
= conf
;
285 value
= cf
->args
->elts
;
287 if (rlcf
->from
== NULL
) {
288 rlcf
->from
= ngx_array_create(cf
->pool
, 2,
290 if (rlcf
->from
== NULL
) {
291 return NGX_CONF_ERROR
;
295 cidr
= ngx_array_push(rlcf
->from
);
297 return NGX_CONF_ERROR
;
300 #if (NGX_HAVE_UNIX_DOMAIN)
302 if (ngx_strcmp(value
[1].data
, "unix:") == 0) {
303 cidr
->family
= AF_UNIX
;
309 rc
= ngx_ptocidr(&value
[1], cidr
);
311 if (rc
== NGX_ERROR
) {
312 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0, "invalid parameter \"%V\"",
314 return NGX_CONF_ERROR
;
317 if (rc
== NGX_DONE
) {
318 ngx_conf_log_error(NGX_LOG_WARN
, cf
, 0,
319 "low address bits of %V are meaningless", &value
[1]);
327 ngx_http_realip(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
329 ngx_http_realip_loc_conf_t
*rlcf
= conf
;
333 value
= cf
->args
->elts
;
335 if (ngx_strcmp(value
[1].data
, "X-Real-IP") == 0) {
336 rlcf
->type
= NGX_HTTP_REALIP_XREALIP
;
340 if (ngx_strcmp(value
[1].data
, "X-Forwarded-For") == 0) {
341 rlcf
->type
= NGX_HTTP_REALIP_XFWD
;
345 rlcf
->type
= NGX_HTTP_REALIP_HEADER
;
346 rlcf
->hash
= ngx_hash_strlow(value
[1].data
, value
[1].data
, value
[1].len
);
347 rlcf
->header
= value
[1];
354 ngx_http_realip_create_loc_conf(ngx_conf_t
*cf
)
356 ngx_http_realip_loc_conf_t
*conf
;
358 conf
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_realip_loc_conf_t
));
364 * set by ngx_pcalloc():
368 * conf->header = { 0, NULL };
371 conf
->type
= NGX_CONF_UNSET_UINT
;
372 conf
->recursive
= NGX_CONF_UNSET
;
379 ngx_http_realip_merge_loc_conf(ngx_conf_t
*cf
, void *parent
, void *child
)
381 ngx_http_realip_loc_conf_t
*prev
= parent
;
382 ngx_http_realip_loc_conf_t
*conf
= child
;
384 if (conf
->from
== NULL
) {
385 conf
->from
= prev
->from
;
388 ngx_conf_merge_uint_value(conf
->type
, prev
->type
, NGX_HTTP_REALIP_XREALIP
);
389 ngx_conf_merge_value(conf
->recursive
, prev
->recursive
, 0);
391 if (conf
->header
.len
== 0) {
392 conf
->hash
= prev
->hash
;
393 conf
->header
= prev
->header
;
401 ngx_http_realip_init(ngx_conf_t
*cf
)
403 ngx_http_handler_pt
*h
;
404 ngx_http_core_main_conf_t
*cmcf
;
406 cmcf
= ngx_http_conf_get_module_main_conf(cf
, ngx_http_core_module
);
408 h
= ngx_array_push(&cmcf
->phases
[NGX_HTTP_POST_READ_PHASE
].handlers
);
413 *h
= ngx_http_realip_handler
;
415 h
= ngx_array_push(&cmcf
->phases
[NGX_HTTP_PREACCESS_PHASE
].handlers
);
420 *h
= ngx_http_realip_handler
;