Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / http / modules / ngx_http_geoip_module.c
blob576fc5f3cd3ed3913c23b10c0a34a80b3162474c
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
12 #include <GeoIP.h>
13 #include <GeoIPCity.h>
16 #define NGX_GEOIP_COUNTRY_CODE 0
17 #define NGX_GEOIP_COUNTRY_CODE3 1
18 #define NGX_GEOIP_COUNTRY_NAME 2
21 typedef struct {
22 GeoIP *country;
23 GeoIP *org;
24 GeoIP *city;
25 ngx_array_t *proxies; /* array of ngx_cidr_t */
26 ngx_flag_t proxy_recursive;
27 #if (NGX_HAVE_GEOIP_V6)
28 unsigned country_v6:1;
29 unsigned org_v6:1;
30 unsigned city_v6:1;
31 #endif
32 } ngx_http_geoip_conf_t;
35 typedef struct {
36 ngx_str_t *name;
37 uintptr_t data;
38 } ngx_http_geoip_var_t;
41 typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *,
42 u_long addr);
45 ngx_http_geoip_variable_handler_pt ngx_http_geoip_country_functions[] = {
46 GeoIP_country_code_by_ipnum,
47 GeoIP_country_code3_by_ipnum,
48 GeoIP_country_name_by_ipnum,
52 #if (NGX_HAVE_GEOIP_V6)
54 typedef const char *(*ngx_http_geoip_variable_handler_v6_pt)(GeoIP *,
55 geoipv6_t addr);
58 ngx_http_geoip_variable_handler_v6_pt ngx_http_geoip_country_v6_functions[] = {
59 GeoIP_country_code_by_ipnum_v6,
60 GeoIP_country_code3_by_ipnum_v6,
61 GeoIP_country_name_by_ipnum_v6,
64 #endif
67 static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
68 ngx_http_variable_value_t *v, uintptr_t data);
69 static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r,
70 ngx_http_variable_value_t *v, uintptr_t data);
71 static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r,
72 ngx_http_variable_value_t *v, uintptr_t data);
73 static ngx_int_t ngx_http_geoip_region_name_variable(ngx_http_request_t *r,
74 ngx_http_variable_value_t *v, uintptr_t data);
75 static ngx_int_t ngx_http_geoip_city_float_variable(ngx_http_request_t *r,
76 ngx_http_variable_value_t *v, uintptr_t data);
77 static ngx_int_t ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
78 ngx_http_variable_value_t *v, uintptr_t data);
79 static GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r);
81 static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
82 static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
83 static char *ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf);
84 static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
85 void *conf);
86 static char *ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd,
87 void *conf);
88 static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
89 void *conf);
90 static char *ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd,
91 void *conf);
92 static ngx_int_t ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
93 ngx_cidr_t *cidr);
94 static void ngx_http_geoip_cleanup(void *data);
97 static ngx_command_t ngx_http_geoip_commands[] = {
99 { ngx_string("geoip_country"),
100 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
101 ngx_http_geoip_country,
102 NGX_HTTP_MAIN_CONF_OFFSET,
104 NULL },
106 { ngx_string("geoip_org"),
107 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
108 ngx_http_geoip_org,
109 NGX_HTTP_MAIN_CONF_OFFSET,
111 NULL },
113 { ngx_string("geoip_city"),
114 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
115 ngx_http_geoip_city,
116 NGX_HTTP_MAIN_CONF_OFFSET,
118 NULL },
120 { ngx_string("geoip_proxy"),
121 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
122 ngx_http_geoip_proxy,
123 NGX_HTTP_MAIN_CONF_OFFSET,
125 NULL },
127 { ngx_string("geoip_proxy_recursive"),
128 NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG,
129 ngx_conf_set_flag_slot,
130 NGX_HTTP_MAIN_CONF_OFFSET,
131 offsetof(ngx_http_geoip_conf_t, proxy_recursive),
132 NULL },
134 ngx_null_command
138 static ngx_http_module_t ngx_http_geoip_module_ctx = {
139 ngx_http_geoip_add_variables, /* preconfiguration */
140 NULL, /* postconfiguration */
142 ngx_http_geoip_create_conf, /* create main configuration */
143 ngx_http_geoip_init_conf, /* init main configuration */
145 NULL, /* create server configuration */
146 NULL, /* merge server configuration */
148 NULL, /* create location configuration */
149 NULL /* merge location configuration */
153 ngx_module_t ngx_http_geoip_module = {
154 NGX_MODULE_V1,
155 &ngx_http_geoip_module_ctx, /* module context */
156 ngx_http_geoip_commands, /* module directives */
157 NGX_HTTP_MODULE, /* module type */
158 NULL, /* init master */
159 NULL, /* init module */
160 NULL, /* init process */
161 NULL, /* init thread */
162 NULL, /* exit thread */
163 NULL, /* exit process */
164 NULL, /* exit master */
165 NGX_MODULE_V1_PADDING
169 static ngx_http_variable_t ngx_http_geoip_vars[] = {
171 { ngx_string("geoip_country_code"), NULL,
172 ngx_http_geoip_country_variable,
173 NGX_GEOIP_COUNTRY_CODE, 0, 0 },
175 { ngx_string("geoip_country_code3"), NULL,
176 ngx_http_geoip_country_variable,
177 NGX_GEOIP_COUNTRY_CODE3, 0, 0 },
179 { ngx_string("geoip_country_name"), NULL,
180 ngx_http_geoip_country_variable,
181 NGX_GEOIP_COUNTRY_NAME, 0, 0 },
183 { ngx_string("geoip_org"), NULL,
184 ngx_http_geoip_org_variable,
185 0, 0, 0 },
187 { ngx_string("geoip_city_continent_code"), NULL,
188 ngx_http_geoip_city_variable,
189 offsetof(GeoIPRecord, continent_code), 0, 0 },
191 { ngx_string("geoip_city_country_code"), NULL,
192 ngx_http_geoip_city_variable,
193 offsetof(GeoIPRecord, country_code), 0, 0 },
195 { ngx_string("geoip_city_country_code3"), NULL,
196 ngx_http_geoip_city_variable,
197 offsetof(GeoIPRecord, country_code3), 0, 0 },
199 { ngx_string("geoip_city_country_name"), NULL,
200 ngx_http_geoip_city_variable,
201 offsetof(GeoIPRecord, country_name), 0, 0 },
203 { ngx_string("geoip_region"), NULL,
204 ngx_http_geoip_city_variable,
205 offsetof(GeoIPRecord, region), 0, 0 },
207 { ngx_string("geoip_region_name"), NULL,
208 ngx_http_geoip_region_name_variable,
209 0, 0, 0 },
211 { ngx_string("geoip_city"), NULL,
212 ngx_http_geoip_city_variable,
213 offsetof(GeoIPRecord, city), 0, 0 },
215 { ngx_string("geoip_postal_code"), NULL,
216 ngx_http_geoip_city_variable,
217 offsetof(GeoIPRecord, postal_code), 0, 0 },
219 { ngx_string("geoip_latitude"), NULL,
220 ngx_http_geoip_city_float_variable,
221 offsetof(GeoIPRecord, latitude), 0, 0 },
223 { ngx_string("geoip_longitude"), NULL,
224 ngx_http_geoip_city_float_variable,
225 offsetof(GeoIPRecord, longitude), 0, 0 },
227 { ngx_string("geoip_dma_code"), NULL,
228 ngx_http_geoip_city_int_variable,
229 offsetof(GeoIPRecord, dma_code), 0, 0 },
231 { ngx_string("geoip_area_code"), NULL,
232 ngx_http_geoip_city_int_variable,
233 offsetof(GeoIPRecord, area_code), 0, 0 },
235 { ngx_null_string, NULL, NULL, 0, 0, 0 }
239 static u_long
240 ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
242 ngx_addr_t addr;
243 ngx_array_t *xfwd;
244 struct sockaddr_in *sin;
246 addr.sockaddr = r->connection->sockaddr;
247 addr.socklen = r->connection->socklen;
248 /* addr.name = r->connection->addr_text; */
250 xfwd = &r->headers_in.x_forwarded_for;
252 if (xfwd->nelts > 0 && gcf->proxies != NULL) {
253 (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
254 gcf->proxies, gcf->proxy_recursive);
257 #if (NGX_HAVE_INET6)
259 if (addr.sockaddr->sa_family == AF_INET6) {
260 u_char *p;
261 in_addr_t inaddr;
262 struct in6_addr *inaddr6;
264 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
266 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
267 p = inaddr6->s6_addr;
269 inaddr = p[12] << 24;
270 inaddr += p[13] << 16;
271 inaddr += p[14] << 8;
272 inaddr += p[15];
274 return inaddr;
278 #endif
280 if (addr.sockaddr->sa_family != AF_INET) {
281 return INADDR_NONE;
284 sin = (struct sockaddr_in *) addr.sockaddr;
285 return ntohl(sin->sin_addr.s_addr);
289 #if (NGX_HAVE_GEOIP_V6)
291 static geoipv6_t
292 ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
294 ngx_addr_t addr;
295 ngx_array_t *xfwd;
296 in_addr_t addr4;
297 struct in6_addr addr6;
298 struct sockaddr_in *sin;
299 struct sockaddr_in6 *sin6;
301 addr.sockaddr = r->connection->sockaddr;
302 addr.socklen = r->connection->socklen;
303 /* addr.name = r->connection->addr_text; */
305 xfwd = &r->headers_in.x_forwarded_for;
307 if (xfwd->nelts > 0 && gcf->proxies != NULL) {
308 (void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
309 gcf->proxies, gcf->proxy_recursive);
312 switch (addr.sockaddr->sa_family) {
314 case AF_INET:
315 /* Produce IPv4-mapped IPv6 address. */
316 sin = (struct sockaddr_in *) addr.sockaddr;
317 addr4 = ntohl(sin->sin_addr.s_addr);
319 ngx_memzero(&addr6, sizeof(struct in6_addr));
320 addr6.s6_addr[10] = 0xff;
321 addr6.s6_addr[11] = 0xff;
322 addr6.s6_addr[12] = addr4 >> 24;
323 addr6.s6_addr[13] = addr4 >> 16;
324 addr6.s6_addr[14] = addr4 >> 8;
325 addr6.s6_addr[15] = addr4;
326 return addr6;
328 case AF_INET6:
329 sin6 = (struct sockaddr_in6 *) addr.sockaddr;
330 return sin6->sin6_addr;
332 default:
333 return in6addr_any;
337 #endif
340 static ngx_int_t
341 ngx_http_geoip_country_variable(ngx_http_request_t *r,
342 ngx_http_variable_value_t *v, uintptr_t data)
344 ngx_http_geoip_variable_handler_pt handler =
345 ngx_http_geoip_country_functions[data];
346 #if (NGX_HAVE_GEOIP_V6)
347 ngx_http_geoip_variable_handler_v6_pt handler_v6 =
348 ngx_http_geoip_country_v6_functions[data];
349 #endif
351 const char *val;
352 ngx_http_geoip_conf_t *gcf;
354 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
356 if (gcf->country == NULL) {
357 goto not_found;
360 #if (NGX_HAVE_GEOIP_V6)
361 val = gcf->country_v6
362 ? handler_v6(gcf->country, ngx_http_geoip_addr_v6(r, gcf))
363 : handler(gcf->country, ngx_http_geoip_addr(r, gcf));
364 #else
365 val = handler(gcf->country, ngx_http_geoip_addr(r, gcf));
366 #endif
368 if (val == NULL) {
369 goto not_found;
372 v->len = ngx_strlen(val);
373 v->valid = 1;
374 v->no_cacheable = 0;
375 v->not_found = 0;
376 v->data = (u_char *) val;
378 return NGX_OK;
380 not_found:
382 v->not_found = 1;
384 return NGX_OK;
388 static ngx_int_t
389 ngx_http_geoip_org_variable(ngx_http_request_t *r,
390 ngx_http_variable_value_t *v, uintptr_t data)
392 size_t len;
393 char *val;
394 ngx_http_geoip_conf_t *gcf;
396 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
398 if (gcf->org == NULL) {
399 goto not_found;
402 #if (NGX_HAVE_GEOIP_V6)
403 val = gcf->org_v6
404 ? GeoIP_name_by_ipnum_v6(gcf->org,
405 ngx_http_geoip_addr_v6(r, gcf))
406 : GeoIP_name_by_ipnum(gcf->org,
407 ngx_http_geoip_addr(r, gcf));
408 #else
409 val = GeoIP_name_by_ipnum(gcf->org, ngx_http_geoip_addr(r, gcf));
410 #endif
412 if (val == NULL) {
413 goto not_found;
416 len = ngx_strlen(val);
417 v->data = ngx_pnalloc(r->pool, len);
418 if (v->data == NULL) {
419 ngx_free(val);
420 return NGX_ERROR;
423 ngx_memcpy(v->data, val, len);
425 v->len = len;
426 v->valid = 1;
427 v->no_cacheable = 0;
428 v->not_found = 0;
430 ngx_free(val);
432 return NGX_OK;
434 not_found:
436 v->not_found = 1;
438 return NGX_OK;
442 static ngx_int_t
443 ngx_http_geoip_city_variable(ngx_http_request_t *r,
444 ngx_http_variable_value_t *v, uintptr_t data)
446 char *val;
447 size_t len;
448 GeoIPRecord *gr;
450 gr = ngx_http_geoip_get_city_record(r);
451 if (gr == NULL) {
452 goto not_found;
455 val = *(char **) ((char *) gr + data);
456 if (val == NULL) {
457 goto no_value;
460 len = ngx_strlen(val);
461 v->data = ngx_pnalloc(r->pool, len);
462 if (v->data == NULL) {
463 GeoIPRecord_delete(gr);
464 return NGX_ERROR;
467 ngx_memcpy(v->data, val, len);
469 v->len = len;
470 v->valid = 1;
471 v->no_cacheable = 0;
472 v->not_found = 0;
474 GeoIPRecord_delete(gr);
476 return NGX_OK;
478 no_value:
480 GeoIPRecord_delete(gr);
482 not_found:
484 v->not_found = 1;
486 return NGX_OK;
490 static ngx_int_t
491 ngx_http_geoip_region_name_variable(ngx_http_request_t *r,
492 ngx_http_variable_value_t *v, uintptr_t data)
494 size_t len;
495 const char *val;
496 GeoIPRecord *gr;
498 gr = ngx_http_geoip_get_city_record(r);
499 if (gr == NULL) {
500 goto not_found;
503 val = GeoIP_region_name_by_code(gr->country_code, gr->region);
505 GeoIPRecord_delete(gr);
507 if (val == NULL) {
508 goto not_found;
511 len = ngx_strlen(val);
512 v->data = ngx_pnalloc(r->pool, len);
513 if (v->data == NULL) {
514 return NGX_ERROR;
517 ngx_memcpy(v->data, val, len);
519 v->len = len;
520 v->valid = 1;
521 v->no_cacheable = 0;
522 v->not_found = 0;
524 return NGX_OK;
526 not_found:
528 v->not_found = 1;
530 return NGX_OK;
534 static ngx_int_t
535 ngx_http_geoip_city_float_variable(ngx_http_request_t *r,
536 ngx_http_variable_value_t *v, uintptr_t data)
538 float val;
539 GeoIPRecord *gr;
541 gr = ngx_http_geoip_get_city_record(r);
542 if (gr == NULL) {
543 v->not_found = 1;
544 return NGX_OK;
547 v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN + 5);
548 if (v->data == NULL) {
549 GeoIPRecord_delete(gr);
550 return NGX_ERROR;
553 val = *(float *) ((char *) gr + data);
555 v->len = ngx_sprintf(v->data, "%.4f", val) - v->data;
557 GeoIPRecord_delete(gr);
559 return NGX_OK;
563 static ngx_int_t
564 ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
565 ngx_http_variable_value_t *v, uintptr_t data)
567 int val;
568 GeoIPRecord *gr;
570 gr = ngx_http_geoip_get_city_record(r);
571 if (gr == NULL) {
572 v->not_found = 1;
573 return NGX_OK;
576 v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN);
577 if (v->data == NULL) {
578 GeoIPRecord_delete(gr);
579 return NGX_ERROR;
582 val = *(int *) ((char *) gr + data);
584 v->len = ngx_sprintf(v->data, "%d", val) - v->data;
586 GeoIPRecord_delete(gr);
588 return NGX_OK;
592 static GeoIPRecord *
593 ngx_http_geoip_get_city_record(ngx_http_request_t *r)
595 ngx_http_geoip_conf_t *gcf;
597 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
599 if (gcf->city) {
600 #if (NGX_HAVE_GEOIP_V6)
601 return gcf->city_v6
602 ? GeoIP_record_by_ipnum_v6(gcf->city,
603 ngx_http_geoip_addr_v6(r, gcf))
604 : GeoIP_record_by_ipnum(gcf->city,
605 ngx_http_geoip_addr(r, gcf));
606 #else
607 return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf));
608 #endif
611 return NULL;
615 static ngx_int_t
616 ngx_http_geoip_add_variables(ngx_conf_t *cf)
618 ngx_http_variable_t *var, *v;
620 for (v = ngx_http_geoip_vars; v->name.len; v++) {
621 var = ngx_http_add_variable(cf, &v->name, v->flags);
622 if (var == NULL) {
623 return NGX_ERROR;
626 var->get_handler = v->get_handler;
627 var->data = v->data;
630 return NGX_OK;
634 static void *
635 ngx_http_geoip_create_conf(ngx_conf_t *cf)
637 ngx_pool_cleanup_t *cln;
638 ngx_http_geoip_conf_t *conf;
640 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
641 if (conf == NULL) {
642 return NULL;
645 conf->proxy_recursive = NGX_CONF_UNSET;
647 cln = ngx_pool_cleanup_add(cf->pool, 0);
648 if (cln == NULL) {
649 return NULL;
652 cln->handler = ngx_http_geoip_cleanup;
653 cln->data = conf;
655 return conf;
659 static char *
660 ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf)
662 ngx_http_geoip_conf_t *gcf = conf;
664 ngx_conf_init_value(gcf->proxy_recursive, 0);
666 return NGX_CONF_OK;
670 static char *
671 ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
673 ngx_http_geoip_conf_t *gcf = conf;
675 ngx_str_t *value;
677 if (gcf->country) {
678 return "is duplicate";
681 value = cf->args->elts;
683 gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
685 if (gcf->country == NULL) {
686 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
687 "GeoIP_open(\"%V\") failed", &value[1]);
689 return NGX_CONF_ERROR;
692 if (cf->args->nelts == 3) {
693 if (ngx_strcmp(value[2].data, "utf8") == 0) {
694 GeoIP_set_charset (gcf->country, GEOIP_CHARSET_UTF8);
696 } else {
697 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
698 "invalid parameter \"%V\"", &value[2]);
699 return NGX_CONF_ERROR;
703 switch (gcf->country->databaseType) {
705 case GEOIP_COUNTRY_EDITION:
707 return NGX_CONF_OK;
709 #if (NGX_HAVE_GEOIP_V6)
710 case GEOIP_COUNTRY_EDITION_V6:
712 gcf->country_v6 = 1;
713 return NGX_CONF_OK;
714 #endif
716 default:
717 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
718 "invalid GeoIP database \"%V\" type:%d",
719 &value[1], gcf->country->databaseType);
720 return NGX_CONF_ERROR;
725 static char *
726 ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
728 ngx_http_geoip_conf_t *gcf = conf;
730 ngx_str_t *value;
732 if (gcf->org) {
733 return "is duplicate";
736 value = cf->args->elts;
738 gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
740 if (gcf->org == NULL) {
741 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
742 "GeoIP_open(\"%V\") failed", &value[1]);
744 return NGX_CONF_ERROR;
747 if (cf->args->nelts == 3) {
748 if (ngx_strcmp(value[2].data, "utf8") == 0) {
749 GeoIP_set_charset (gcf->org, GEOIP_CHARSET_UTF8);
751 } else {
752 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
753 "invalid parameter \"%V\"", &value[2]);
754 return NGX_CONF_ERROR;
758 switch (gcf->org->databaseType) {
760 case GEOIP_ISP_EDITION:
761 case GEOIP_ORG_EDITION:
762 case GEOIP_DOMAIN_EDITION:
763 case GEOIP_ASNUM_EDITION:
765 return NGX_CONF_OK;
767 #if (NGX_HAVE_GEOIP_V6)
768 case GEOIP_ISP_EDITION_V6:
769 case GEOIP_ORG_EDITION_V6:
770 case GEOIP_DOMAIN_EDITION_V6:
771 case GEOIP_ASNUM_EDITION_V6:
773 gcf->org_v6 = 1;
774 return NGX_CONF_OK;
775 #endif
777 default:
778 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
779 "invalid GeoIP database \"%V\" type:%d",
780 &value[1], gcf->org->databaseType);
781 return NGX_CONF_ERROR;
786 static char *
787 ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
789 ngx_http_geoip_conf_t *gcf = conf;
791 ngx_str_t *value;
793 if (gcf->city) {
794 return "is duplicate";
797 value = cf->args->elts;
799 gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
801 if (gcf->city == NULL) {
802 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
803 "GeoIP_open(\"%V\") failed", &value[1]);
805 return NGX_CONF_ERROR;
808 if (cf->args->nelts == 3) {
809 if (ngx_strcmp(value[2].data, "utf8") == 0) {
810 GeoIP_set_charset (gcf->city, GEOIP_CHARSET_UTF8);
812 } else {
813 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
814 "invalid parameter \"%V\"", &value[2]);
815 return NGX_CONF_ERROR;
819 switch (gcf->city->databaseType) {
821 case GEOIP_CITY_EDITION_REV0:
822 case GEOIP_CITY_EDITION_REV1:
824 return NGX_CONF_OK;
826 #if (NGX_HAVE_GEOIP_V6)
827 case GEOIP_CITY_EDITION_REV0_V6:
828 case GEOIP_CITY_EDITION_REV1_V6:
830 gcf->city_v6 = 1;
831 return NGX_CONF_OK;
832 #endif
834 default:
835 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
836 "invalid GeoIP City database \"%V\" type:%d",
837 &value[1], gcf->city->databaseType);
838 return NGX_CONF_ERROR;
843 static char *
844 ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
846 ngx_http_geoip_conf_t *gcf = conf;
848 ngx_str_t *value;
849 ngx_cidr_t cidr, *c;
851 value = cf->args->elts;
853 if (ngx_http_geoip_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
854 return NGX_CONF_ERROR;
857 if (gcf->proxies == NULL) {
858 gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t));
859 if (gcf->proxies == NULL) {
860 return NGX_CONF_ERROR;
864 c = ngx_array_push(gcf->proxies);
865 if (c == NULL) {
866 return NGX_CONF_ERROR;
869 *c = cidr;
871 return NGX_CONF_OK;
874 static ngx_int_t
875 ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
877 ngx_int_t rc;
879 if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
880 cidr->family = AF_INET;
881 cidr->u.in.addr = 0xffffffff;
882 cidr->u.in.mask = 0xffffffff;
884 return NGX_OK;
887 rc = ngx_ptocidr(net, cidr);
889 if (rc == NGX_ERROR) {
890 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
891 return NGX_ERROR;
894 if (rc == NGX_DONE) {
895 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
896 "low address bits of %V are meaningless", net);
899 return NGX_OK;
903 static void
904 ngx_http_geoip_cleanup(void *data)
906 ngx_http_geoip_conf_t *gcf = data;
908 if (gcf->country) {
909 GeoIP_delete(gcf->country);
912 if (gcf->org) {
913 GeoIP_delete(gcf->org);
916 if (gcf->city) {
917 GeoIP_delete(gcf->city);