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