Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_geoip_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 #include <GeoIP.h>
13 #include <GeoIPCity.h>
14 
15 
16 #define NGX_GEOIP_COUNTRY_CODE 0
17 #define NGX_GEOIP_COUNTRY_CODE3 1
18 #define NGX_GEOIP_COUNTRY_NAME 2
19 
20 
21 typedef struct {
22  GeoIP *country;
23  GeoIP *org;
24  GeoIP *city;
25  ngx_array_t *proxies; /* array of ngx_cidr_t */
27 #if (NGX_HAVE_GEOIP_V6)
28  unsigned country_v6:1;
29  unsigned org_v6:1;
30  unsigned city_v6:1;
31 #endif
33 
34 
35 typedef struct {
37  uintptr_t data;
39 
40 
41 typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *,
42  u_long addr);
43 
44 
46  GeoIP_country_code_by_ipnum,
47  GeoIP_country_code3_by_ipnum,
48  GeoIP_country_name_by_ipnum,
49 };
50 
51 
52 #if (NGX_HAVE_GEOIP_V6)
53 
54 typedef const char *(*ngx_http_geoip_variable_handler_v6_pt)(GeoIP *,
55  geoipv6_t addr);
56 
57 
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,
62 };
63 
64 #endif
65 
66 
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);
80 
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);
95 
96 
97 static ngx_command_t ngx_http_geoip_commands[] = {
98 
99  { ngx_string("geoip_country"),
101  ngx_http_geoip_country,
103  0,
104  NULL },
105 
106  { ngx_string("geoip_org"),
108  ngx_http_geoip_org,
110  0,
111  NULL },
112 
113  { ngx_string("geoip_city"),
115  ngx_http_geoip_city,
117  0,
118  NULL },
119 
120  { ngx_string("geoip_proxy"),
122  ngx_http_geoip_proxy,
124  0,
125  NULL },
126 
127  { ngx_string("geoip_proxy_recursive"),
131  offsetof(ngx_http_geoip_conf_t, proxy_recursive),
132  NULL },
133 
135 };
136 
137 
138 static ngx_http_module_t ngx_http_geoip_module_ctx = {
139  ngx_http_geoip_add_variables, /* preconfiguration */
140  NULL, /* postconfiguration */
141 
142  ngx_http_geoip_create_conf, /* create main configuration */
143  ngx_http_geoip_init_conf, /* init main configuration */
144 
145  NULL, /* create server configuration */
146  NULL, /* merge server configuration */
147 
148  NULL, /* create location configuration */
149  NULL /* merge location configuration */
150 };
151 
152 
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 */
166 };
167 
168 
169 static ngx_http_variable_t ngx_http_geoip_vars[] = {
170 
171  { ngx_string("geoip_country_code"), NULL,
172  ngx_http_geoip_country_variable,
173  NGX_GEOIP_COUNTRY_CODE, 0, 0 },
174 
175  { ngx_string("geoip_country_code3"), NULL,
176  ngx_http_geoip_country_variable,
177  NGX_GEOIP_COUNTRY_CODE3, 0, 0 },
178 
179  { ngx_string("geoip_country_name"), NULL,
180  ngx_http_geoip_country_variable,
181  NGX_GEOIP_COUNTRY_NAME, 0, 0 },
182 
183  { ngx_string("geoip_org"), NULL,
184  ngx_http_geoip_org_variable,
185  0, 0, 0 },
186 
187  { ngx_string("geoip_city_continent_code"), NULL,
188  ngx_http_geoip_city_variable,
189  offsetof(GeoIPRecord, continent_code), 0, 0 },
190 
191  { ngx_string("geoip_city_country_code"), NULL,
192  ngx_http_geoip_city_variable,
193  offsetof(GeoIPRecord, country_code), 0, 0 },
194 
195  { ngx_string("geoip_city_country_code3"), NULL,
196  ngx_http_geoip_city_variable,
197  offsetof(GeoIPRecord, country_code3), 0, 0 },
198 
199  { ngx_string("geoip_city_country_name"), NULL,
200  ngx_http_geoip_city_variable,
201  offsetof(GeoIPRecord, country_name), 0, 0 },
202 
203  { ngx_string("geoip_region"), NULL,
204  ngx_http_geoip_city_variable,
205  offsetof(GeoIPRecord, region), 0, 0 },
206 
207  { ngx_string("geoip_region_name"), NULL,
208  ngx_http_geoip_region_name_variable,
209  0, 0, 0 },
210 
211  { ngx_string("geoip_city"), NULL,
212  ngx_http_geoip_city_variable,
213  offsetof(GeoIPRecord, city), 0, 0 },
214 
215  { ngx_string("geoip_postal_code"), NULL,
216  ngx_http_geoip_city_variable,
217  offsetof(GeoIPRecord, postal_code), 0, 0 },
218 
219  { ngx_string("geoip_latitude"), NULL,
220  ngx_http_geoip_city_float_variable,
221  offsetof(GeoIPRecord, latitude), 0, 0 },
222 
223  { ngx_string("geoip_longitude"), NULL,
224  ngx_http_geoip_city_float_variable,
225  offsetof(GeoIPRecord, longitude), 0, 0 },
226 
227  { ngx_string("geoip_dma_code"), NULL,
228  ngx_http_geoip_city_int_variable,
229  offsetof(GeoIPRecord, dma_code), 0, 0 },
230 
231  { ngx_string("geoip_area_code"), NULL,
232  ngx_http_geoip_city_int_variable,
233  offsetof(GeoIPRecord, area_code), 0, 0 },
234 
235  { ngx_null_string, NULL, NULL, 0, 0, 0 }
236 };
237 
238 
239 static u_long
240 ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
241 {
242  ngx_addr_t addr;
243  ngx_array_t *xfwd;
244  struct sockaddr_in *sin;
245 
246  addr.sockaddr = r->connection->sockaddr;
247  addr.socklen = r->connection->socklen;
248  /* addr.name = r->connection->addr_text; */
249 
250  xfwd = &r->headers_in.x_forwarded_for;
251 
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);
255  }
256 
257 #if (NGX_HAVE_INET6)
258 
259  if (addr.sockaddr->sa_family == AF_INET6) {
260  u_char *p;
261  in_addr_t inaddr;
262  struct in6_addr *inaddr6;
263 
264  inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
265 
266  if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
267  p = inaddr6->s6_addr;
268 
269  inaddr = p[12] << 24;
270  inaddr += p[13] << 16;
271  inaddr += p[14] << 8;
272  inaddr += p[15];
273 
274  return inaddr;
275  }
276  }
277 
278 #endif
279 
280  if (addr.sockaddr->sa_family != AF_INET) {
281  return INADDR_NONE;
282  }
283 
284  sin = (struct sockaddr_in *) addr.sockaddr;
285  return ntohl(sin->sin_addr.s_addr);
286 }
287 
288 
289 #if (NGX_HAVE_GEOIP_V6)
290 
291 static geoipv6_t
292 ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
293 {
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;
300 
301  addr.sockaddr = r->connection->sockaddr;
302  addr.socklen = r->connection->socklen;
303  /* addr.name = r->connection->addr_text; */
304 
305  xfwd = &r->headers_in.x_forwarded_for;
306 
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);
310  }
311 
312  switch (addr.sockaddr->sa_family) {
313 
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);
318 
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;
327 
328  case AF_INET6:
329  sin6 = (struct sockaddr_in6 *) addr.sockaddr;
330  return sin6->sin6_addr;
331 
332  default:
333  return in6addr_any;
334  }
335 }
336 
337 #endif
338 
339 
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)
343 {
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
350 
351  const char *val;
353 
354  gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
355 
356  if (gcf->country == NULL) {
357  goto not_found;
358  }
359 
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
367 
368  if (val == NULL) {
369  goto not_found;
370  }
371 
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;
377 
378  return NGX_OK;
379 
380 not_found:
381 
382  v->not_found = 1;
383 
384  return NGX_OK;
385 }
386 
387 
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)
391 {
392  size_t len;
393  char *val;
395 
396  gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
397 
398  if (gcf->org == NULL) {
399  goto not_found;
400  }
401 
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
411 
412  if (val == NULL) {
413  goto not_found;
414  }
415 
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;
421  }
422 
423  ngx_memcpy(v->data, val, len);
424 
425  v->len = len;
426  v->valid = 1;
427  v->no_cacheable = 0;
428  v->not_found = 0;
429 
430  ngx_free(val);
431 
432  return NGX_OK;
433 
434 not_found:
435 
436  v->not_found = 1;
437 
438  return NGX_OK;
439 }
440 
441 
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)
445 {
446  char *val;
447  size_t len;
448  GeoIPRecord *gr;
449 
450  gr = ngx_http_geoip_get_city_record(r);
451  if (gr == NULL) {
452  goto not_found;
453  }
454 
455  val = *(char **) ((char *) gr + data);
456  if (val == NULL) {
457  goto no_value;
458  }
459 
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;
465  }
466 
467  ngx_memcpy(v->data, val, len);
468 
469  v->len = len;
470  v->valid = 1;
471  v->no_cacheable = 0;
472  v->not_found = 0;
473 
474  GeoIPRecord_delete(gr);
475 
476  return NGX_OK;
477 
478 no_value:
479 
480  GeoIPRecord_delete(gr);
481 
482 not_found:
483 
484  v->not_found = 1;
485 
486  return NGX_OK;
487 }
488 
489 
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)
493 {
494  size_t len;
495  const char *val;
496  GeoIPRecord *gr;
497 
498  gr = ngx_http_geoip_get_city_record(r);
499  if (gr == NULL) {
500  goto not_found;
501  }
502 
503  val = GeoIP_region_name_by_code(gr->country_code, gr->region);
504 
505  GeoIPRecord_delete(gr);
506 
507  if (val == NULL) {
508  goto not_found;
509  }
510 
511  len = ngx_strlen(val);
512  v->data = ngx_pnalloc(r->pool, len);
513  if (v->data == NULL) {
514  return NGX_ERROR;
515  }
516 
517  ngx_memcpy(v->data, val, len);
518 
519  v->len = len;
520  v->valid = 1;
521  v->no_cacheable = 0;
522  v->not_found = 0;
523 
524  return NGX_OK;
525 
526 not_found:
527 
528  v->not_found = 1;
529 
530  return NGX_OK;
531 }
532 
533 
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)
537 {
538  float val;
539  GeoIPRecord *gr;
540 
541  gr = ngx_http_geoip_get_city_record(r);
542  if (gr == NULL) {
543  v->not_found = 1;
544  return NGX_OK;
545  }
546 
547  v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN + 5);
548  if (v->data == NULL) {
549  GeoIPRecord_delete(gr);
550  return NGX_ERROR;
551  }
552 
553  val = *(float *) ((char *) gr + data);
554 
555  v->len = ngx_sprintf(v->data, "%.4f", val) - v->data;
556 
557  GeoIPRecord_delete(gr);
558 
559  return NGX_OK;
560 }
561 
562 
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)
566 {
567  int val;
568  GeoIPRecord *gr;
569 
570  gr = ngx_http_geoip_get_city_record(r);
571  if (gr == NULL) {
572  v->not_found = 1;
573  return NGX_OK;
574  }
575 
577  if (v->data == NULL) {
578  GeoIPRecord_delete(gr);
579  return NGX_ERROR;
580  }
581 
582  val = *(int *) ((char *) gr + data);
583 
584  v->len = ngx_sprintf(v->data, "%d", val) - v->data;
585 
586  GeoIPRecord_delete(gr);
587 
588  return NGX_OK;
589 }
590 
591 
592 static GeoIPRecord *
593 ngx_http_geoip_get_city_record(ngx_http_request_t *r)
594 {
596 
597  gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
598 
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
609  }
610 
611  return NULL;
612 }
613 
614 
615 static ngx_int_t
616 ngx_http_geoip_add_variables(ngx_conf_t *cf)
617 {
618  ngx_http_variable_t *var, *v;
619 
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;
624  }
625 
626  var->get_handler = v->get_handler;
627  var->data = v->data;
628  }
629 
630  return NGX_OK;
631 }
632 
633 
634 static void *
635 ngx_http_geoip_create_conf(ngx_conf_t *cf)
636 {
637  ngx_pool_cleanup_t *cln;
638  ngx_http_geoip_conf_t *conf;
639 
640  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
641  if (conf == NULL) {
642  return NULL;
643  }
644 
646 
647  cln = ngx_pool_cleanup_add(cf->pool, 0);
648  if (cln == NULL) {
649  return NULL;
650  }
651 
652  cln->handler = ngx_http_geoip_cleanup;
653  cln->data = conf;
654 
655  return conf;
656 }
657 
658 
659 static char *
660 ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf)
661 {
662  ngx_http_geoip_conf_t *gcf = conf;
663 
665 
666  return NGX_CONF_OK;
667 }
668 
669 
670 static char *
671 ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
672 {
673  ngx_http_geoip_conf_t *gcf = conf;
674 
675  ngx_str_t *value;
676 
677  if (gcf->country) {
678  return "is duplicate";
679  }
680 
681  value = cf->args->elts;
682 
683  gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
684 
685  if (gcf->country == NULL) {
687  "GeoIP_open(\"%V\") failed", &value[1]);
688 
689  return NGX_CONF_ERROR;
690  }
691 
692  if (cf->args->nelts == 3) {
693  if (ngx_strcmp(value[2].data, "utf8") == 0) {
694  GeoIP_set_charset (gcf->country, GEOIP_CHARSET_UTF8);
695 
696  } else {
698  "invalid parameter \"%V\"", &value[2]);
699  return NGX_CONF_ERROR;
700  }
701  }
702 
703  switch (gcf->country->databaseType) {
704 
705  case GEOIP_COUNTRY_EDITION:
706 
707  return NGX_CONF_OK;
708 
709 #if (NGX_HAVE_GEOIP_V6)
710  case GEOIP_COUNTRY_EDITION_V6:
711 
712  gcf->country_v6 = 1;
713  return NGX_CONF_OK;
714 #endif
715 
716  default:
718  "invalid GeoIP database \"%V\" type:%d",
719  &value[1], gcf->country->databaseType);
720  return NGX_CONF_ERROR;
721  }
722 }
723 
724 
725 static char *
726 ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
727 {
728  ngx_http_geoip_conf_t *gcf = conf;
729 
730  ngx_str_t *value;
731 
732  if (gcf->org) {
733  return "is duplicate";
734  }
735 
736  value = cf->args->elts;
737 
738  gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
739 
740  if (gcf->org == NULL) {
742  "GeoIP_open(\"%V\") failed", &value[1]);
743 
744  return NGX_CONF_ERROR;
745  }
746 
747  if (cf->args->nelts == 3) {
748  if (ngx_strcmp(value[2].data, "utf8") == 0) {
749  GeoIP_set_charset (gcf->org, GEOIP_CHARSET_UTF8);
750 
751  } else {
753  "invalid parameter \"%V\"", &value[2]);
754  return NGX_CONF_ERROR;
755  }
756  }
757 
758  switch (gcf->org->databaseType) {
759 
760  case GEOIP_ISP_EDITION:
761  case GEOIP_ORG_EDITION:
762  case GEOIP_DOMAIN_EDITION:
763  case GEOIP_ASNUM_EDITION:
764 
765  return NGX_CONF_OK;
766 
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:
772 
773  gcf->org_v6 = 1;
774  return NGX_CONF_OK;
775 #endif
776 
777  default:
779  "invalid GeoIP database \"%V\" type:%d",
780  &value[1], gcf->org->databaseType);
781  return NGX_CONF_ERROR;
782  }
783 }
784 
785 
786 static char *
787 ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
788 {
789  ngx_http_geoip_conf_t *gcf = conf;
790 
791  ngx_str_t *value;
792 
793  if (gcf->city) {
794  return "is duplicate";
795  }
796 
797  value = cf->args->elts;
798 
799  gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
800 
801  if (gcf->city == NULL) {
803  "GeoIP_open(\"%V\") failed", &value[1]);
804 
805  return NGX_CONF_ERROR;
806  }
807 
808  if (cf->args->nelts == 3) {
809  if (ngx_strcmp(value[2].data, "utf8") == 0) {
810  GeoIP_set_charset (gcf->city, GEOIP_CHARSET_UTF8);
811 
812  } else {
814  "invalid parameter \"%V\"", &value[2]);
815  return NGX_CONF_ERROR;
816  }
817  }
818 
819  switch (gcf->city->databaseType) {
820 
821  case GEOIP_CITY_EDITION_REV0:
822  case GEOIP_CITY_EDITION_REV1:
823 
824  return NGX_CONF_OK;
825 
826 #if (NGX_HAVE_GEOIP_V6)
827  case GEOIP_CITY_EDITION_REV0_V6:
828  case GEOIP_CITY_EDITION_REV1_V6:
829 
830  gcf->city_v6 = 1;
831  return NGX_CONF_OK;
832 #endif
833 
834  default:
836  "invalid GeoIP City database \"%V\" type:%d",
837  &value[1], gcf->city->databaseType);
838  return NGX_CONF_ERROR;
839  }
840 }
841 
842 
843 static char *
844 ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
845 {
846  ngx_http_geoip_conf_t *gcf = conf;
847 
848  ngx_str_t *value;
849  ngx_cidr_t cidr, *c;
850 
851  value = cf->args->elts;
852 
853  if (ngx_http_geoip_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
854  return NGX_CONF_ERROR;
855  }
856 
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;
861  }
862  }
863 
864  c = ngx_array_push(gcf->proxies);
865  if (c == NULL) {
866  return NGX_CONF_ERROR;
867  }
868 
869  *c = cidr;
870 
871  return NGX_CONF_OK;
872 }
873 
874 static ngx_int_t
875 ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
876 {
877  ngx_int_t rc;
878 
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;
883 
884  return NGX_OK;
885  }
886 
887  rc = ngx_ptocidr(net, cidr);
888 
889  if (rc == NGX_ERROR) {
890  ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
891  return NGX_ERROR;
892  }
893 
894  if (rc == NGX_DONE) {
896  "low address bits of %V are meaningless", net);
897  }
898 
899  return NGX_OK;
900 }
901 
902 
903 static void
904 ngx_http_geoip_cleanup(void *data)
905 {
906  ngx_http_geoip_conf_t *gcf = data;
907 
908  if (gcf->country) {
909  GeoIP_delete(gcf->country);
910  }
911 
912  if (gcf->org) {
913  GeoIP_delete(gcf->org);
914  }
915 
916  if (gcf->city) {
917  GeoIP_delete(gcf->city);
918  }
919 }