Mercurial > hg > nginx-vendor-current
comparison src/http/modules/ngx_http_geoip_module.c @ 674:4dcaf40cc702 NGINX_1_3_0
nginx 1.3.0
*) Feature: the "debug_connection" directive now supports IPv6 addresses
and the "unix:" parameter.
*) Feature: the "set_real_ip_from" directive and the "proxy" parameter
of the "geo" directive now support IPv6 addresses.
*) Feature: the "real_ip_recursive", "geoip_proxy", and
"geoip_proxy_recursive" directives.
*) Feature: the "proxy_recursive" parameter of the "geo" directive.
*) Bugfix: a segmentation fault might occur in a worker process if the
"resolver" directive was used.
*) Bugfix: a segmentation fault might occur in a worker process if the
"fastcgi_pass", "scgi_pass", or "uwsgi_pass" directives were used and
backend returned incorrect response.
*) Bugfix: a segmentation fault might occur in a worker process if the
"rewrite" directive was used and new request arguments in a
replacement used variables.
*) Bugfix: nginx might hog CPU if the open file resource limit was
reached.
*) Bugfix: nginx might loop infinitely over backends if the
"proxy_next_upstream" directive with the "http_404" parameter was
used and there were backup servers specified in an upstream block.
*) Bugfix: adding the "down" parameter of the "server" directive might
cause unneeded client redistribution among backend servers if the
"ip_hash" directive was used.
*) Bugfix: socket leak.
Thanks to Yichun Zhang.
*) Bugfix: in the ngx_http_fastcgi_module.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Tue, 15 May 2012 00:00:00 +0400 |
parents | d0f7a625f27c |
children | bfa81a0490a2 |
comparison
equal
deleted
inserted
replaced
673:1e5c7a976f48 | 674:4dcaf40cc702 |
---|---|
12 #include <GeoIP.h> | 12 #include <GeoIP.h> |
13 #include <GeoIPCity.h> | 13 #include <GeoIPCity.h> |
14 | 14 |
15 | 15 |
16 typedef struct { | 16 typedef struct { |
17 GeoIP *country; | 17 GeoIP *country; |
18 GeoIP *org; | 18 GeoIP *org; |
19 GeoIP *city; | 19 GeoIP *city; |
20 ngx_array_t *proxies; /* array of ngx_cidr_t */ | |
21 ngx_flag_t proxy_recursive; | |
20 } ngx_http_geoip_conf_t; | 22 } ngx_http_geoip_conf_t; |
21 | 23 |
22 | 24 |
23 typedef struct { | 25 typedef struct { |
24 ngx_str_t *name; | 26 ngx_str_t *name; |
25 uintptr_t data; | 27 uintptr_t data; |
26 } ngx_http_geoip_var_t; | 28 } ngx_http_geoip_var_t; |
27 | 29 |
28 | 30 |
29 typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr); | 31 typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr); |
30 | 32 |
33 static u_long ngx_http_geoip_addr(ngx_http_request_t *r, | |
34 ngx_http_geoip_conf_t *gcf); | |
31 static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, | 35 static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, |
32 ngx_http_variable_value_t *v, uintptr_t data); | 36 ngx_http_variable_value_t *v, uintptr_t data); |
33 static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r, | 37 static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r, |
34 ngx_http_variable_value_t *v, uintptr_t data); | 38 ngx_http_variable_value_t *v, uintptr_t data); |
35 static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, | 39 static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, |
42 ngx_http_variable_value_t *v, uintptr_t data); | 46 ngx_http_variable_value_t *v, uintptr_t data); |
43 static GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r); | 47 static GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r); |
44 | 48 |
45 static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf); | 49 static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf); |
46 static void *ngx_http_geoip_create_conf(ngx_conf_t *cf); | 50 static void *ngx_http_geoip_create_conf(ngx_conf_t *cf); |
51 static char *ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf); | |
47 static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, | 52 static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, |
48 void *conf); | 53 void *conf); |
49 static char *ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, | 54 static char *ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, |
50 void *conf); | 55 void *conf); |
51 static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, | 56 static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, |
52 void *conf); | 57 void *conf); |
58 static char *ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd, | |
59 void *conf); | |
60 static ngx_int_t ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net, | |
61 ngx_cidr_t *cidr); | |
53 static void ngx_http_geoip_cleanup(void *data); | 62 static void ngx_http_geoip_cleanup(void *data); |
54 | 63 |
55 | 64 |
56 static ngx_command_t ngx_http_geoip_commands[] = { | 65 static ngx_command_t ngx_http_geoip_commands[] = { |
57 | 66 |
74 ngx_http_geoip_city, | 83 ngx_http_geoip_city, |
75 NGX_HTTP_MAIN_CONF_OFFSET, | 84 NGX_HTTP_MAIN_CONF_OFFSET, |
76 0, | 85 0, |
77 NULL }, | 86 NULL }, |
78 | 87 |
88 { ngx_string("geoip_proxy"), | |
89 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, | |
90 ngx_http_geoip_proxy, | |
91 NGX_HTTP_MAIN_CONF_OFFSET, | |
92 0, | |
93 NULL }, | |
94 | |
95 { ngx_string("geoip_proxy_recursive"), | |
96 NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG, | |
97 ngx_conf_set_flag_slot, | |
98 NGX_HTTP_MAIN_CONF_OFFSET, | |
99 offsetof(ngx_http_geoip_conf_t, proxy_recursive), | |
100 NULL }, | |
101 | |
79 ngx_null_command | 102 ngx_null_command |
80 }; | 103 }; |
81 | 104 |
82 | 105 |
83 static ngx_http_module_t ngx_http_geoip_module_ctx = { | 106 static ngx_http_module_t ngx_http_geoip_module_ctx = { |
84 ngx_http_geoip_add_variables, /* preconfiguration */ | 107 ngx_http_geoip_add_variables, /* preconfiguration */ |
85 NULL, /* postconfiguration */ | 108 NULL, /* postconfiguration */ |
86 | 109 |
87 ngx_http_geoip_create_conf, /* create main configuration */ | 110 ngx_http_geoip_create_conf, /* create main configuration */ |
88 NULL, /* init main configuration */ | 111 ngx_http_geoip_init_conf, /* init main configuration */ |
89 | 112 |
90 NULL, /* create server configuration */ | 113 NULL, /* create server configuration */ |
91 NULL, /* merge server configuration */ | 114 NULL, /* merge server configuration */ |
92 | 115 |
93 NULL, /* create location configuration */ | 116 NULL, /* create location configuration */ |
180 { ngx_null_string, NULL, NULL, 0, 0, 0 } | 203 { ngx_null_string, NULL, NULL, 0, 0, 0 } |
181 }; | 204 }; |
182 | 205 |
183 | 206 |
184 static u_long | 207 static u_long |
185 ngx_http_geoip_addr(ngx_http_request_t *r) | 208 ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) |
186 { | 209 { |
187 struct sockaddr_in *sin; | 210 ngx_addr_t addr; |
211 ngx_table_elt_t *xfwd; | |
212 struct sockaddr_in *sin; | |
213 | |
214 addr.sockaddr = r->connection->sockaddr; | |
215 addr.socklen = r->connection->socklen; | |
216 /* addr.name = r->connection->addr_text; */ | |
217 | |
218 xfwd = r->headers_in.x_forwarded_for; | |
219 | |
220 if (xfwd != NULL && gcf->proxies != NULL) { | |
221 (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data, | |
222 xfwd->value.len, gcf->proxies, | |
223 gcf->proxy_recursive); | |
224 } | |
225 | |
188 #if (NGX_HAVE_INET6) | 226 #if (NGX_HAVE_INET6) |
189 u_char *p; | 227 |
190 u_long addr; | 228 if (addr.sockaddr->sa_family == AF_INET6) { |
191 struct sockaddr_in6 *sin6; | 229 struct in6_addr *inaddr6; |
230 | |
231 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; | |
232 | |
233 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { | |
234 return ntohl(*(in_addr_t *) &inaddr6->s6_addr[12]); | |
235 } | |
236 } | |
237 | |
192 #endif | 238 #endif |
193 | 239 |
194 switch (r->connection->sockaddr->sa_family) { | 240 if (addr.sockaddr->sa_family != AF_INET) { |
195 | 241 return INADDR_NONE; |
196 case AF_INET: | 242 } |
197 sin = (struct sockaddr_in *) r->connection->sockaddr; | 243 |
198 return ntohl(sin->sin_addr.s_addr); | 244 sin = (struct sockaddr_in *) addr.sockaddr; |
199 | 245 return ntohl(sin->sin_addr.s_addr); |
200 #if (NGX_HAVE_INET6) | |
201 | |
202 case AF_INET6: | |
203 sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; | |
204 | |
205 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { | |
206 p = sin6->sin6_addr.s6_addr; | |
207 addr = p[12] << 24; | |
208 addr += p[13] << 16; | |
209 addr += p[14] << 8; | |
210 addr += p[15]; | |
211 | |
212 return addr; | |
213 } | |
214 | |
215 #endif | |
216 } | |
217 | |
218 return INADDR_NONE; | |
219 } | 246 } |
220 | 247 |
221 | 248 |
222 static ngx_int_t | 249 static ngx_int_t |
223 ngx_http_geoip_country_variable(ngx_http_request_t *r, | 250 ngx_http_geoip_country_variable(ngx_http_request_t *r, |
233 | 260 |
234 if (gcf->country == NULL) { | 261 if (gcf->country == NULL) { |
235 goto not_found; | 262 goto not_found; |
236 } | 263 } |
237 | 264 |
238 val = handler(gcf->country, ngx_http_geoip_addr(r)); | 265 val = handler(gcf->country, ngx_http_geoip_addr(r, gcf)); |
239 | 266 |
240 if (val == NULL) { | 267 if (val == NULL) { |
241 goto not_found; | 268 goto not_found; |
242 } | 269 } |
243 | 270 |
271 | 298 |
272 if (gcf->org == NULL) { | 299 if (gcf->org == NULL) { |
273 goto not_found; | 300 goto not_found; |
274 } | 301 } |
275 | 302 |
276 val = handler(gcf->org, ngx_http_geoip_addr(r)); | 303 val = handler(gcf->org, ngx_http_geoip_addr(r, gcf)); |
277 | 304 |
278 if (val == NULL) { | 305 if (val == NULL) { |
279 goto not_found; | 306 goto not_found; |
280 } | 307 } |
281 | 308 |
451 ngx_http_geoip_conf_t *gcf; | 478 ngx_http_geoip_conf_t *gcf; |
452 | 479 |
453 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); | 480 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); |
454 | 481 |
455 if (gcf->city) { | 482 if (gcf->city) { |
456 return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r)); | 483 return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf)); |
457 } | 484 } |
458 | 485 |
459 return NULL; | 486 return NULL; |
460 } | 487 } |
461 | 488 |
488 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t)); | 515 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t)); |
489 if (conf == NULL) { | 516 if (conf == NULL) { |
490 return NULL; | 517 return NULL; |
491 } | 518 } |
492 | 519 |
520 conf->proxy_recursive = NGX_CONF_UNSET; | |
521 | |
493 cln = ngx_pool_cleanup_add(cf->pool, 0); | 522 cln = ngx_pool_cleanup_add(cf->pool, 0); |
494 if (cln == NULL) { | 523 if (cln == NULL) { |
495 return NULL; | 524 return NULL; |
496 } | 525 } |
497 | 526 |
498 cln->handler = ngx_http_geoip_cleanup; | 527 cln->handler = ngx_http_geoip_cleanup; |
499 cln->data = conf; | 528 cln->data = conf; |
500 | 529 |
501 return conf; | 530 return conf; |
531 } | |
532 | |
533 | |
534 static char * | |
535 ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf) | |
536 { | |
537 ngx_http_geoip_conf_t *gcf = conf; | |
538 | |
539 ngx_conf_init_value(gcf->proxy_recursive, 0); | |
540 | |
541 return NGX_CONF_OK; | |
502 } | 542 } |
503 | 543 |
504 | 544 |
505 static char * | 545 static char * |
506 ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 546 ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
650 return NGX_CONF_ERROR; | 690 return NGX_CONF_ERROR; |
651 } | 691 } |
652 } | 692 } |
653 | 693 |
654 | 694 |
695 static char * | |
696 ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
697 { | |
698 ngx_http_geoip_conf_t *gcf = conf; | |
699 | |
700 ngx_str_t *value; | |
701 ngx_cidr_t cidr, *c; | |
702 | |
703 value = cf->args->elts; | |
704 | |
705 if (ngx_http_geoip_cidr_value(cf, &value[1], &cidr) != NGX_OK) { | |
706 return NGX_CONF_ERROR; | |
707 } | |
708 | |
709 if (gcf->proxies == NULL) { | |
710 gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t)); | |
711 if (gcf->proxies == NULL) { | |
712 return NGX_CONF_ERROR; | |
713 } | |
714 } | |
715 | |
716 c = ngx_array_push(gcf->proxies); | |
717 if (c == NULL) { | |
718 return NGX_CONF_ERROR; | |
719 } | |
720 | |
721 *c = cidr; | |
722 | |
723 return NGX_CONF_OK; | |
724 } | |
725 | |
726 static ngx_int_t | |
727 ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr) | |
728 { | |
729 ngx_int_t rc; | |
730 | |
731 if (ngx_strcmp(net->data, "255.255.255.255") == 0) { | |
732 cidr->family = AF_INET; | |
733 cidr->u.in.addr = 0xffffffff; | |
734 cidr->u.in.mask = 0xffffffff; | |
735 | |
736 return NGX_OK; | |
737 } | |
738 | |
739 rc = ngx_ptocidr(net, cidr); | |
740 | |
741 if (rc == NGX_ERROR) { | |
742 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net); | |
743 return NGX_ERROR; | |
744 } | |
745 | |
746 if (rc == NGX_DONE) { | |
747 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
748 "low address bits of %V are meaningless", net); | |
749 } | |
750 | |
751 return NGX_OK; | |
752 } | |
753 | |
754 | |
655 static void | 755 static void |
656 ngx_http_geoip_cleanup(void *data) | 756 ngx_http_geoip_cleanup(void *data) |
657 { | 757 { |
658 ngx_http_geoip_conf_t *gcf = data; | 758 ngx_http_geoip_conf_t *gcf = data; |
659 | 759 |