3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 #define NGX_HTTP_REALIP_XREALIP 0
13 #define NGX_HTTP_REALIP_XFWD 1
14 #define NGX_HTTP_REALIP_HEADER 2
22 } ngx_http_realip_from_t;
26 ngx_array_t *from; /* array of ngx_http_realip_from_t */
30 } ngx_http_realip_loc_conf_t;
34 ngx_connection_t *connection;
37 } ngx_http_realip_ctx_t;
40 static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
41 static void ngx_http_realip_cleanup(void *data);
42 static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
44 static char *ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
45 static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf);
46 static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf,
47 void *parent, void *child);
48 static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf);
51 static ngx_command_t ngx_http_realip_commands[] = {
53 { ngx_string("set_real_ip_from"),
54 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
56 NGX_HTTP_LOC_CONF_OFFSET,
60 { ngx_string("real_ip_header"),
61 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
63 NGX_HTTP_LOC_CONF_OFFSET,
72 static ngx_http_module_t ngx_http_realip_module_ctx = {
73 NULL, /* preconfiguration */
74 ngx_http_realip_init, /* postconfiguration */
76 NULL, /* create main configuration */
77 NULL, /* init main configuration */
79 NULL, /* create server configuration */
80 NULL, /* merge server configuration */
82 ngx_http_realip_create_loc_conf, /* create location configuration */
83 ngx_http_realip_merge_loc_conf /* merge location configuration */
87 ngx_module_t ngx_http_realip_module = {
89 &ngx_http_realip_module_ctx, /* module context */
90 ngx_http_realip_commands, /* module directives */
91 NGX_HTTP_MODULE, /* module type */
92 NULL, /* init master */
93 NULL, /* init module */
94 NULL, /* init process */
95 NULL, /* init thread */
96 NULL, /* exit thread */
97 NULL, /* exit process */
98 NULL, /* exit master */
104 ngx_http_realip_handler(ngx_http_request_t *r)
110 ngx_list_part_t *part;
111 ngx_table_elt_t *header;
112 struct sockaddr_in *sin;
114 ngx_pool_cleanup_t *cln;
115 ngx_http_realip_ctx_t *ctx;
116 ngx_http_realip_from_t *from;
117 ngx_http_realip_loc_conf_t *rlcf;
119 ctx = ngx_http_get_module_ctx(r, ngx_http_realip_module);
125 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t));
127 return NGX_HTTP_INTERNAL_SERVER_ERROR;
130 rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
132 if (rlcf->from == NULL) {
136 switch (rlcf->type) {
138 case NGX_HTTP_REALIP_XREALIP:
140 if (r->headers_in.x_real_ip == NULL) {
144 len = r->headers_in.x_real_ip->value.len;
145 ip = r->headers_in.x_real_ip->value.data;
149 case NGX_HTTP_REALIP_XFWD:
151 if (r->headers_in.x_forwarded_for == NULL) {
155 len = r->headers_in.x_forwarded_for->value.len;
156 ip = r->headers_in.x_forwarded_for->value.data;
158 for (p = ip + len - 1; p > ip; p--) {
159 if (*p == ' ' || *p == ',') {
169 default: /* NGX_HTTP_REALIP_HEADER */
171 part = &r->headers_in.headers.part;
175 len = rlcf->header.len;
176 p = rlcf->header.data;
178 for (i = 0; /* void */ ; i++) {
180 if (i >= part->nelts) {
181 if (part->next == NULL) {
190 if (hash == header[i].hash
191 && len == header[i].key.len
192 && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
194 len = header[i].value.len;
195 ip = header[i].value.data;
208 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "realip: \"%s\"", ip);
212 sin = (struct sockaddr_in *) c->sockaddr;
214 from = rlcf->from->elts;
215 for (i = 0; i < rlcf->from->nelts; i++) {
217 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
218 "realip: %08XD %08XD %08XD",
219 sin->sin_addr.s_addr, from[i].mask, from[i].addr);
221 if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) {
225 ngx_http_set_ctx(r, ctx, ngx_http_realip_module);
227 addr = inet_addr((char *) ip);
229 if (addr == INADDR_NONE) {
233 p = ngx_pnalloc(c->pool, len);
235 return NGX_HTTP_INTERNAL_SERVER_ERROR;
238 ngx_memcpy(p, ip, len);
240 cln->handler = ngx_http_realip_cleanup;
243 ctx->addr = sin->sin_addr.s_addr;
244 ctx->addr_text = c->addr_text;
246 sin->sin_addr.s_addr = addr;
248 c->addr_text.len = len;
249 c->addr_text.data = p;
260 ngx_http_realip_cleanup(void *data)
262 ngx_http_realip_ctx_t *ctx = data;
265 struct sockaddr_in *sin;
269 sin = (struct sockaddr_in *) c->sockaddr;
270 sin->sin_addr.s_addr = ctx->addr;
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;
283 ngx_inet_cidr_t in_cidr;
284 ngx_http_realip_from_t *from;
286 if (rlcf->from == NULL) {
287 rlcf->from = ngx_array_create(cf->pool, 2,
288 sizeof(ngx_http_realip_from_t));
289 if (rlcf->from == NULL) {
290 return NGX_CONF_ERROR;
294 from = ngx_array_push(rlcf->from);
296 return NGX_CONF_ERROR;
299 value = cf->args->elts;
301 rc = ngx_ptocidr(&value[1], &in_cidr);
303 if (rc == NGX_ERROR) {
304 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"",
306 return NGX_CONF_ERROR;
309 if (rc == NGX_DONE) {
310 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
311 "low address bits of %V are meaningless", &value[1]);
314 from->mask = in_cidr.mask;
315 from->addr = in_cidr.addr;
322 ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
324 ngx_http_realip_loc_conf_t *rlcf = conf;
328 value = cf->args->elts;
330 if (ngx_strcmp(value[1].data, "X-Real-IP") == 0) {
331 rlcf->type = NGX_HTTP_REALIP_XREALIP;
335 if (ngx_strcmp(value[1].data, "X-Forwarded-For") == 0) {
336 rlcf->type = NGX_HTTP_REALIP_XFWD;
340 rlcf->type = NGX_HTTP_REALIP_HEADER;
341 rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len);
342 rlcf->header = value[1];
349 ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
351 ngx_http_realip_loc_conf_t *conf;
353 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t));
355 return NGX_CONF_ERROR;
359 * set by ngx_pcalloc():
363 * conf->header = { 0, NULL };
366 conf->type = NGX_CONF_UNSET_UINT;
373 ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
375 ngx_http_realip_loc_conf_t *prev = parent;
376 ngx_http_realip_loc_conf_t *conf = child;
378 if (conf->from == NULL) {
379 conf->from = prev->from;
382 ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
384 if (conf->header.len == 0) {
385 conf->hash = prev->hash;
386 conf->header = prev->header;
394 ngx_http_realip_init(ngx_conf_t *cf)
396 ngx_http_handler_pt *h;
397 ngx_http_core_main_conf_t *cmcf;
399 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
401 h = ngx_array_push(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers);
406 *h = ngx_http_realip_handler;
408 h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
413 *h = ngx_http_realip_handler;