comparison src/stream/ngx_stream_geoip_module.c @ 6630:558db057adaa

Stream: geoip module.
author Vladimir Homutov <vl@nginx.com>
date Tue, 12 Jul 2016 17:34:43 +0300
parents src/http/modules/ngx_http_geoip_module.c@494c2c2a0247
children 2a288909abc6
comparison
equal deleted inserted replaced
6629:8ed51b02f655 6630:558db057adaa
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_stream.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 #if (NGX_HAVE_GEOIP_V6)
26 unsigned country_v6:1;
27 unsigned org_v6:1;
28 unsigned city_v6:1;
29 #endif
30 } ngx_stream_geoip_conf_t;
31
32
33 typedef struct {
34 ngx_str_t *name;
35 uintptr_t data;
36 } ngx_stream_geoip_var_t;
37
38
39 typedef const char *(*ngx_stream_geoip_variable_handler_pt)(GeoIP *,
40 u_long addr);
41
42
43 ngx_stream_geoip_variable_handler_pt ngx_stream_geoip_country_functions[] = {
44 GeoIP_country_code_by_ipnum,
45 GeoIP_country_code3_by_ipnum,
46 GeoIP_country_name_by_ipnum,
47 };
48
49
50 #if (NGX_HAVE_GEOIP_V6)
51
52 typedef const char *(*ngx_stream_geoip_variable_handler_v6_pt)(GeoIP *,
53 geoipv6_t addr);
54
55
56 ngx_stream_geoip_variable_handler_v6_pt
57 ngx_stream_geoip_country_v6_functions[] =
58 {
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_stream_geoip_country_variable(ngx_stream_session_t *s,
68 ngx_stream_variable_value_t *v, uintptr_t data);
69 static ngx_int_t ngx_stream_geoip_org_variable(ngx_stream_session_t *s,
70 ngx_stream_variable_value_t *v, uintptr_t data);
71 static ngx_int_t ngx_stream_geoip_city_variable(ngx_stream_session_t *s,
72 ngx_stream_variable_value_t *v, uintptr_t data);
73 static ngx_int_t ngx_stream_geoip_region_name_variable(ngx_stream_session_t *s,
74 ngx_stream_variable_value_t *v, uintptr_t data);
75 static ngx_int_t ngx_stream_geoip_city_float_variable(ngx_stream_session_t *s,
76 ngx_stream_variable_value_t *v, uintptr_t data);
77 static ngx_int_t ngx_stream_geoip_city_int_variable(ngx_stream_session_t *s,
78 ngx_stream_variable_value_t *v, uintptr_t data);
79 static GeoIPRecord *ngx_stream_geoip_get_city_record(ngx_stream_session_t *s);
80
81 static ngx_int_t ngx_stream_geoip_add_variables(ngx_conf_t *cf);
82 static void *ngx_stream_geoip_create_conf(ngx_conf_t *cf);
83 static char *ngx_stream_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
84 void *conf);
85 static char *ngx_stream_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd,
86 void *conf);
87 static char *ngx_stream_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
88 void *conf);
89 static void ngx_stream_geoip_cleanup(void *data);
90
91
92 static ngx_command_t ngx_stream_geoip_commands[] = {
93
94 { ngx_string("geoip_country"),
95 NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12,
96 ngx_stream_geoip_country,
97 NGX_STREAM_MAIN_CONF_OFFSET,
98 0,
99 NULL },
100
101 { ngx_string("geoip_org"),
102 NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12,
103 ngx_stream_geoip_org,
104 NGX_STREAM_MAIN_CONF_OFFSET,
105 0,
106 NULL },
107
108 { ngx_string("geoip_city"),
109 NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE12,
110 ngx_stream_geoip_city,
111 NGX_STREAM_MAIN_CONF_OFFSET,
112 0,
113 NULL },
114
115 ngx_null_command
116 };
117
118
119 static ngx_stream_module_t ngx_stream_geoip_module_ctx = {
120 ngx_stream_geoip_add_variables, /* preconfiguration */
121 NULL, /* postconfiguration */
122
123 ngx_stream_geoip_create_conf, /* create main configuration */
124 NULL, /* init main configuration */
125
126 NULL, /* create server configuration */
127 NULL /* merge server configuration */
128 };
129
130
131 ngx_module_t ngx_stream_geoip_module = {
132 NGX_MODULE_V1,
133 &ngx_stream_geoip_module_ctx, /* module context */
134 ngx_stream_geoip_commands, /* module directives */
135 NGX_STREAM_MODULE, /* module type */
136 NULL, /* init master */
137 NULL, /* init module */
138 NULL, /* init process */
139 NULL, /* init thread */
140 NULL, /* exit thread */
141 NULL, /* exit process */
142 NULL, /* exit master */
143 NGX_MODULE_V1_PADDING
144 };
145
146
147 static ngx_stream_variable_t ngx_stream_geoip_vars[] = {
148
149 { ngx_string("geoip_country_code"), NULL,
150 ngx_stream_geoip_country_variable,
151 NGX_GEOIP_COUNTRY_CODE, 0, 0 },
152
153 { ngx_string("geoip_country_code3"), NULL,
154 ngx_stream_geoip_country_variable,
155 NGX_GEOIP_COUNTRY_CODE3, 0, 0 },
156
157 { ngx_string("geoip_country_name"), NULL,
158 ngx_stream_geoip_country_variable,
159 NGX_GEOIP_COUNTRY_NAME, 0, 0 },
160
161 { ngx_string("geoip_org"), NULL,
162 ngx_stream_geoip_org_variable,
163 0, 0, 0 },
164
165 { ngx_string("geoip_city_continent_code"), NULL,
166 ngx_stream_geoip_city_variable,
167 offsetof(GeoIPRecord, continent_code), 0, 0 },
168
169 { ngx_string("geoip_city_country_code"), NULL,
170 ngx_stream_geoip_city_variable,
171 offsetof(GeoIPRecord, country_code), 0, 0 },
172
173 { ngx_string("geoip_city_country_code3"), NULL,
174 ngx_stream_geoip_city_variable,
175 offsetof(GeoIPRecord, country_code3), 0, 0 },
176
177 { ngx_string("geoip_city_country_name"), NULL,
178 ngx_stream_geoip_city_variable,
179 offsetof(GeoIPRecord, country_name), 0, 0 },
180
181 { ngx_string("geoip_region"), NULL,
182 ngx_stream_geoip_city_variable,
183 offsetof(GeoIPRecord, region), 0, 0 },
184
185 { ngx_string("geoip_region_name"), NULL,
186 ngx_stream_geoip_region_name_variable,
187 0, 0, 0 },
188
189 { ngx_string("geoip_city"), NULL,
190 ngx_stream_geoip_city_variable,
191 offsetof(GeoIPRecord, city), 0, 0 },
192
193 { ngx_string("geoip_postal_code"), NULL,
194 ngx_stream_geoip_city_variable,
195 offsetof(GeoIPRecord, postal_code), 0, 0 },
196
197 { ngx_string("geoip_latitude"), NULL,
198 ngx_stream_geoip_city_float_variable,
199 offsetof(GeoIPRecord, latitude), 0, 0 },
200
201 { ngx_string("geoip_longitude"), NULL,
202 ngx_stream_geoip_city_float_variable,
203 offsetof(GeoIPRecord, longitude), 0, 0 },
204
205 { ngx_string("geoip_dma_code"), NULL,
206 ngx_stream_geoip_city_int_variable,
207 offsetof(GeoIPRecord, dma_code), 0, 0 },
208
209 { ngx_string("geoip_area_code"), NULL,
210 ngx_stream_geoip_city_int_variable,
211 offsetof(GeoIPRecord, area_code), 0, 0 },
212
213 { ngx_null_string, NULL, NULL, 0, 0, 0 }
214 };
215
216
217 static u_long
218 ngx_stream_geoip_addr(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf)
219 {
220 ngx_addr_t addr;
221 struct sockaddr_in *sin;
222
223 addr.sockaddr = s->connection->sockaddr;
224 addr.socklen = s->connection->socklen;
225 /* addr.name = s->connection->addr_text; */
226
227 #if (NGX_HAVE_INET6)
228
229 if (addr.sockaddr->sa_family == AF_INET6) {
230 u_char *p;
231 in_addr_t inaddr;
232 struct in6_addr *inaddr6;
233
234 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
235
236 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
237 p = inaddr6->s6_addr;
238
239 inaddr = p[12] << 24;
240 inaddr += p[13] << 16;
241 inaddr += p[14] << 8;
242 inaddr += p[15];
243
244 return inaddr;
245 }
246 }
247
248 #endif
249
250 if (addr.sockaddr->sa_family != AF_INET) {
251 return INADDR_NONE;
252 }
253
254 sin = (struct sockaddr_in *) addr.sockaddr;
255 return ntohl(sin->sin_addr.s_addr);
256 }
257
258
259 #if (NGX_HAVE_GEOIP_V6)
260
261 static geoipv6_t
262 ngx_stream_geoip_addr_v6(ngx_stream_session_t *s, ngx_stream_geoip_conf_t *gcf)
263 {
264 ngx_addr_t addr;
265 in_addr_t addr4;
266 struct in6_addr addr6;
267 struct sockaddr_in *sin;
268 struct sockaddr_in6 *sin6;
269
270 addr.sockaddr = s->connection->sockaddr;
271 addr.socklen = s->connection->socklen;
272 /* addr.name = s->connection->addr_text; */
273
274 switch (addr.sockaddr->sa_family) {
275
276 case AF_INET:
277 /* Produce IPv4-mapped IPv6 address. */
278 sin = (struct sockaddr_in *) addr.sockaddr;
279 addr4 = ntohl(sin->sin_addr.s_addr);
280
281 ngx_memzero(&addr6, sizeof(struct in6_addr));
282 addr6.s6_addr[10] = 0xff;
283 addr6.s6_addr[11] = 0xff;
284 addr6.s6_addr[12] = addr4 >> 24;
285 addr6.s6_addr[13] = addr4 >> 16;
286 addr6.s6_addr[14] = addr4 >> 8;
287 addr6.s6_addr[15] = addr4;
288 return addr6;
289
290 case AF_INET6:
291 sin6 = (struct sockaddr_in6 *) addr.sockaddr;
292 return sin6->sin6_addr;
293
294 default:
295 return in6addr_any;
296 }
297 }
298
299 #endif
300
301
302 static ngx_int_t
303 ngx_stream_geoip_country_variable(ngx_stream_session_t *s,
304 ngx_stream_variable_value_t *v, uintptr_t data)
305 {
306 ngx_stream_geoip_variable_handler_pt handler =
307 ngx_stream_geoip_country_functions[data];
308 #if (NGX_HAVE_GEOIP_V6)
309 ngx_stream_geoip_variable_handler_v6_pt handler_v6 =
310 ngx_stream_geoip_country_v6_functions[data];
311 #endif
312
313 const char *val;
314 ngx_stream_geoip_conf_t *gcf;
315
316 gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);
317
318 if (gcf->country == NULL) {
319 goto not_found;
320 }
321
322 #if (NGX_HAVE_GEOIP_V6)
323 val = gcf->country_v6
324 ? handler_v6(gcf->country, ngx_stream_geoip_addr_v6(s, gcf))
325 : handler(gcf->country, ngx_stream_geoip_addr(s, gcf));
326 #else
327 val = handler(gcf->country, ngx_stream_geoip_addr(s, gcf));
328 #endif
329
330 if (val == NULL) {
331 goto not_found;
332 }
333
334 v->len = ngx_strlen(val);
335 v->valid = 1;
336 v->no_cacheable = 0;
337 v->not_found = 0;
338 v->data = (u_char *) val;
339
340 return NGX_OK;
341
342 not_found:
343
344 v->not_found = 1;
345
346 return NGX_OK;
347 }
348
349
350 static ngx_int_t
351 ngx_stream_geoip_org_variable(ngx_stream_session_t *s,
352 ngx_stream_variable_value_t *v, uintptr_t data)
353 {
354 size_t len;
355 char *val;
356 ngx_stream_geoip_conf_t *gcf;
357
358 gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);
359
360 if (gcf->org == NULL) {
361 goto not_found;
362 }
363
364 #if (NGX_HAVE_GEOIP_V6)
365 val = gcf->org_v6
366 ? GeoIP_name_by_ipnum_v6(gcf->org,
367 ngx_stream_geoip_addr_v6(s, gcf))
368 : GeoIP_name_by_ipnum(gcf->org,
369 ngx_stream_geoip_addr(s, gcf));
370 #else
371 val = GeoIP_name_by_ipnum(gcf->org, ngx_stream_geoip_addr(s, gcf));
372 #endif
373
374 if (val == NULL) {
375 goto not_found;
376 }
377
378 len = ngx_strlen(val);
379 v->data = ngx_pnalloc(s->connection->pool, len);
380 if (v->data == NULL) {
381 ngx_free(val);
382 return NGX_ERROR;
383 }
384
385 ngx_memcpy(v->data, val, len);
386
387 v->len = len;
388 v->valid = 1;
389 v->no_cacheable = 0;
390 v->not_found = 0;
391
392 ngx_free(val);
393
394 return NGX_OK;
395
396 not_found:
397
398 v->not_found = 1;
399
400 return NGX_OK;
401 }
402
403
404 static ngx_int_t
405 ngx_stream_geoip_city_variable(ngx_stream_session_t *s,
406 ngx_stream_variable_value_t *v, uintptr_t data)
407 {
408 char *val;
409 size_t len;
410 GeoIPRecord *gr;
411
412 gr = ngx_stream_geoip_get_city_record(s);
413 if (gr == NULL) {
414 goto not_found;
415 }
416
417 val = *(char **) ((char *) gr + data);
418 if (val == NULL) {
419 goto no_value;
420 }
421
422 len = ngx_strlen(val);
423 v->data = ngx_pnalloc(s->connection->pool, len);
424 if (v->data == NULL) {
425 GeoIPRecord_delete(gr);
426 return NGX_ERROR;
427 }
428
429 ngx_memcpy(v->data, val, len);
430
431 v->len = len;
432 v->valid = 1;
433 v->no_cacheable = 0;
434 v->not_found = 0;
435
436 GeoIPRecord_delete(gr);
437
438 return NGX_OK;
439
440 no_value:
441
442 GeoIPRecord_delete(gr);
443
444 not_found:
445
446 v->not_found = 1;
447
448 return NGX_OK;
449 }
450
451
452 static ngx_int_t
453 ngx_stream_geoip_region_name_variable(ngx_stream_session_t *s,
454 ngx_stream_variable_value_t *v, uintptr_t data)
455 {
456 size_t len;
457 const char *val;
458 GeoIPRecord *gr;
459
460 gr = ngx_stream_geoip_get_city_record(s);
461 if (gr == NULL) {
462 goto not_found;
463 }
464
465 val = GeoIP_region_name_by_code(gr->country_code, gr->region);
466
467 GeoIPRecord_delete(gr);
468
469 if (val == NULL) {
470 goto not_found;
471 }
472
473 len = ngx_strlen(val);
474 v->data = ngx_pnalloc(s->connection->pool, len);
475 if (v->data == NULL) {
476 return NGX_ERROR;
477 }
478
479 ngx_memcpy(v->data, val, len);
480
481 v->len = len;
482 v->valid = 1;
483 v->no_cacheable = 0;
484 v->not_found = 0;
485
486 return NGX_OK;
487
488 not_found:
489
490 v->not_found = 1;
491
492 return NGX_OK;
493 }
494
495
496 static ngx_int_t
497 ngx_stream_geoip_city_float_variable(ngx_stream_session_t *s,
498 ngx_stream_variable_value_t *v, uintptr_t data)
499 {
500 float val;
501 GeoIPRecord *gr;
502
503 gr = ngx_stream_geoip_get_city_record(s);
504 if (gr == NULL) {
505 v->not_found = 1;
506 return NGX_OK;
507 }
508
509 v->data = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN + 5);
510 if (v->data == NULL) {
511 GeoIPRecord_delete(gr);
512 return NGX_ERROR;
513 }
514
515 val = *(float *) ((char *) gr + data);
516
517 v->len = ngx_sprintf(v->data, "%.4f", val) - v->data;
518 v->valid = 1;
519 v->no_cacheable = 0;
520 v->not_found = 0;
521
522 GeoIPRecord_delete(gr);
523
524 return NGX_OK;
525 }
526
527
528 static ngx_int_t
529 ngx_stream_geoip_city_int_variable(ngx_stream_session_t *s,
530 ngx_stream_variable_value_t *v, uintptr_t data)
531 {
532 int val;
533 GeoIPRecord *gr;
534
535 gr = ngx_stream_geoip_get_city_record(s);
536 if (gr == NULL) {
537 v->not_found = 1;
538 return NGX_OK;
539 }
540
541 v->data = ngx_pnalloc(s->connection->pool, NGX_INT64_LEN);
542 if (v->data == NULL) {
543 GeoIPRecord_delete(gr);
544 return NGX_ERROR;
545 }
546
547 val = *(int *) ((char *) gr + data);
548
549 v->len = ngx_sprintf(v->data, "%d", val) - v->data;
550 v->valid = 1;
551 v->no_cacheable = 0;
552 v->not_found = 0;
553
554 GeoIPRecord_delete(gr);
555
556 return NGX_OK;
557 }
558
559
560 static GeoIPRecord *
561 ngx_stream_geoip_get_city_record(ngx_stream_session_t *s)
562 {
563 ngx_stream_geoip_conf_t *gcf;
564
565 gcf = ngx_stream_get_module_main_conf(s, ngx_stream_geoip_module);
566
567 if (gcf->city) {
568 #if (NGX_HAVE_GEOIP_V6)
569 return gcf->city_v6
570 ? GeoIP_record_by_ipnum_v6(gcf->city,
571 ngx_stream_geoip_addr_v6(s, gcf))
572 : GeoIP_record_by_ipnum(gcf->city,
573 ngx_stream_geoip_addr(s, gcf));
574 #else
575 return GeoIP_record_by_ipnum(gcf->city, ngx_stream_geoip_addr(s, gcf));
576 #endif
577 }
578
579 return NULL;
580 }
581
582
583 static ngx_int_t
584 ngx_stream_geoip_add_variables(ngx_conf_t *cf)
585 {
586 ngx_stream_variable_t *var, *v;
587
588 for (v = ngx_stream_geoip_vars; v->name.len; v++) {
589 var = ngx_stream_add_variable(cf, &v->name, v->flags);
590 if (var == NULL) {
591 return NGX_ERROR;
592 }
593
594 var->get_handler = v->get_handler;
595 var->data = v->data;
596 }
597
598 return NGX_OK;
599 }
600
601
602 static void *
603 ngx_stream_geoip_create_conf(ngx_conf_t *cf)
604 {
605 ngx_pool_cleanup_t *cln;
606 ngx_stream_geoip_conf_t *conf;
607
608 conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip_conf_t));
609 if (conf == NULL) {
610 return NULL;
611 }
612
613 cln = ngx_pool_cleanup_add(cf->pool, 0);
614 if (cln == NULL) {
615 return NULL;
616 }
617
618 cln->handler = ngx_stream_geoip_cleanup;
619 cln->data = conf;
620
621 return conf;
622 }
623
624
625 static char *
626 ngx_stream_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
627 {
628 ngx_stream_geoip_conf_t *gcf = conf;
629
630 ngx_str_t *value;
631
632 if (gcf->country) {
633 return "is duplicate";
634 }
635
636 value = cf->args->elts;
637
638 gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
639
640 if (gcf->country == NULL) {
641 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
642 "GeoIP_open(\"%V\") failed", &value[1]);
643
644 return NGX_CONF_ERROR;
645 }
646
647 if (cf->args->nelts == 3) {
648 if (ngx_strcmp(value[2].data, "utf8") == 0) {
649 GeoIP_set_charset(gcf->country, GEOIP_CHARSET_UTF8);
650
651 } else {
652 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
653 "invalid parameter \"%V\"", &value[2]);
654 return NGX_CONF_ERROR;
655 }
656 }
657
658 switch (gcf->country->databaseType) {
659
660 case GEOIP_COUNTRY_EDITION:
661
662 return NGX_CONF_OK;
663
664 #if (NGX_HAVE_GEOIP_V6)
665 case GEOIP_COUNTRY_EDITION_V6:
666
667 gcf->country_v6 = 1;
668 return NGX_CONF_OK;
669 #endif
670
671 default:
672 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
673 "invalid GeoIP database \"%V\" type:%d",
674 &value[1], gcf->country->databaseType);
675 return NGX_CONF_ERROR;
676 }
677 }
678
679
680 static char *
681 ngx_stream_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
682 {
683 ngx_stream_geoip_conf_t *gcf = conf;
684
685 ngx_str_t *value;
686
687 if (gcf->org) {
688 return "is duplicate";
689 }
690
691 value = cf->args->elts;
692
693 gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
694
695 if (gcf->org == NULL) {
696 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
697 "GeoIP_open(\"%V\") failed", &value[1]);
698
699 return NGX_CONF_ERROR;
700 }
701
702 if (cf->args->nelts == 3) {
703 if (ngx_strcmp(value[2].data, "utf8") == 0) {
704 GeoIP_set_charset(gcf->org, GEOIP_CHARSET_UTF8);
705
706 } else {
707 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
708 "invalid parameter \"%V\"", &value[2]);
709 return NGX_CONF_ERROR;
710 }
711 }
712
713 switch (gcf->org->databaseType) {
714
715 case GEOIP_ISP_EDITION:
716 case GEOIP_ORG_EDITION:
717 case GEOIP_DOMAIN_EDITION:
718 case GEOIP_ASNUM_EDITION:
719
720 return NGX_CONF_OK;
721
722 #if (NGX_HAVE_GEOIP_V6)
723 case GEOIP_ISP_EDITION_V6:
724 case GEOIP_ORG_EDITION_V6:
725 case GEOIP_DOMAIN_EDITION_V6:
726 case GEOIP_ASNUM_EDITION_V6:
727
728 gcf->org_v6 = 1;
729 return NGX_CONF_OK;
730 #endif
731
732 default:
733 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
734 "invalid GeoIP database \"%V\" type:%d",
735 &value[1], gcf->org->databaseType);
736 return NGX_CONF_ERROR;
737 }
738 }
739
740
741 static char *
742 ngx_stream_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
743 {
744 ngx_stream_geoip_conf_t *gcf = conf;
745
746 ngx_str_t *value;
747
748 if (gcf->city) {
749 return "is duplicate";
750 }
751
752 value = cf->args->elts;
753
754 gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
755
756 if (gcf->city == NULL) {
757 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
758 "GeoIP_open(\"%V\") failed", &value[1]);
759
760 return NGX_CONF_ERROR;
761 }
762
763 if (cf->args->nelts == 3) {
764 if (ngx_strcmp(value[2].data, "utf8") == 0) {
765 GeoIP_set_charset(gcf->city, GEOIP_CHARSET_UTF8);
766
767 } else {
768 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
769 "invalid parameter \"%V\"", &value[2]);
770 return NGX_CONF_ERROR;
771 }
772 }
773
774 switch (gcf->city->databaseType) {
775
776 case GEOIP_CITY_EDITION_REV0:
777 case GEOIP_CITY_EDITION_REV1:
778
779 return NGX_CONF_OK;
780
781 #if (NGX_HAVE_GEOIP_V6)
782 case GEOIP_CITY_EDITION_REV0_V6:
783 case GEOIP_CITY_EDITION_REV1_V6:
784
785 gcf->city_v6 = 1;
786 return NGX_CONF_OK;
787 #endif
788
789 default:
790 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
791 "invalid GeoIP City database \"%V\" type:%d",
792 &value[1], gcf->city->databaseType);
793 return NGX_CONF_ERROR;
794 }
795 }
796
797
798 static void
799 ngx_stream_geoip_cleanup(void *data)
800 {
801 ngx_stream_geoip_conf_t *gcf = data;
802
803 if (gcf->country) {
804 GeoIP_delete(gcf->country);
805 }
806
807 if (gcf->org) {
808 GeoIP_delete(gcf->org);
809 }
810
811 if (gcf->city) {
812 GeoIP_delete(gcf->city);
813 }
814 }