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 */
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;
33
34
35 typedef struct {
36 ngx_str_t *name;
37 uintptr_t data;
38 } ngx_http_geoip_var_t;
39
40
41 typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *,
42 u_long addr);
43
44
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,
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"),
100 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
101 ngx_http_geoip_country,
102 NGX_HTTP_MAIN_CONF_OFFSET,
103 0,
104 NULL },
105
106 { ngx_string("geoip_org"),
107 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
108 ngx_http_geoip_org,
109 NGX_HTTP_MAIN_CONF_OFFSET,
110 0,
111 NULL },
112
113 { ngx_string("geoip_city"),
114 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
115 ngx_http_geoip_city,
116 NGX_HTTP_MAIN_CONF_OFFSET,
117 0,
118 NULL },
119
120 { ngx_string("geoip_proxy"),
121 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
122 ngx_http_geoip_proxy,
123 NGX_HTTP_MAIN_CONF_OFFSET,
124 0,
125 NULL },
126
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 },
133
134 ngx_null_command
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
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
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_http_null_variable
236 };
237
238
239 static u_long
ngx_http_geoip_addr(ngx_http_request_t * r,ngx_http_geoip_conf_t * gcf)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
ngx_http_geoip_addr_v6(ngx_http_request_t * r,ngx_http_geoip_conf_t * gcf)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
ngx_http_geoip_country_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)341 ngx_http_geoip_country_variable(ngx_http_request_t *r,
342 ngx_http_variable_value_t *v, uintptr_t data)
343 {
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
350
351 const char *val;
352 ngx_http_geoip_conf_t *gcf;
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
ngx_http_geoip_org_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)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;
394 ngx_http_geoip_conf_t *gcf;
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
ngx_http_geoip_city_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)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
ngx_http_geoip_region_name_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)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
ngx_http_geoip_city_float_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)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 v->valid = 1;
557 v->no_cacheable = 0;
558 v->not_found = 0;
559
560 GeoIPRecord_delete(gr);
561
562 return NGX_OK;
563 }
564
565
566 static ngx_int_t
ngx_http_geoip_city_int_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)567 ngx_http_geoip_city_int_variable(ngx_http_request_t *r,
568 ngx_http_variable_value_t *v, uintptr_t data)
569 {
570 int val;
571 GeoIPRecord *gr;
572
573 gr = ngx_http_geoip_get_city_record(r);
574 if (gr == NULL) {
575 v->not_found = 1;
576 return NGX_OK;
577 }
578
579 v->data = ngx_pnalloc(r->pool, NGX_INT64_LEN);
580 if (v->data == NULL) {
581 GeoIPRecord_delete(gr);
582 return NGX_ERROR;
583 }
584
585 val = *(int *) ((char *) gr + data);
586
587 v->len = ngx_sprintf(v->data, "%d", val) - v->data;
588 v->valid = 1;
589 v->no_cacheable = 0;
590 v->not_found = 0;
591
592 GeoIPRecord_delete(gr);
593
594 return NGX_OK;
595 }
596
597
598 static GeoIPRecord *
ngx_http_geoip_get_city_record(ngx_http_request_t * r)599 ngx_http_geoip_get_city_record(ngx_http_request_t *r)
600 {
601 ngx_http_geoip_conf_t *gcf;
602
603 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
604
605 if (gcf->city) {
606 #if (NGX_HAVE_GEOIP_V6)
607 return gcf->city_v6
608 ? GeoIP_record_by_ipnum_v6(gcf->city,
609 ngx_http_geoip_addr_v6(r, gcf))
610 : GeoIP_record_by_ipnum(gcf->city,
611 ngx_http_geoip_addr(r, gcf));
612 #else
613 return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf));
614 #endif
615 }
616
617 return NULL;
618 }
619
620
621 static ngx_int_t
ngx_http_geoip_add_variables(ngx_conf_t * cf)622 ngx_http_geoip_add_variables(ngx_conf_t *cf)
623 {
624 ngx_http_variable_t *var, *v;
625
626 for (v = ngx_http_geoip_vars; v->name.len; v++) {
627 var = ngx_http_add_variable(cf, &v->name, v->flags);
628 if (var == NULL) {
629 return NGX_ERROR;
630 }
631
632 var->get_handler = v->get_handler;
633 var->data = v->data;
634 }
635
636 return NGX_OK;
637 }
638
639
640 static void *
ngx_http_geoip_create_conf(ngx_conf_t * cf)641 ngx_http_geoip_create_conf(ngx_conf_t *cf)
642 {
643 ngx_pool_cleanup_t *cln;
644 ngx_http_geoip_conf_t *conf;
645
646 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
647 if (conf == NULL) {
648 return NULL;
649 }
650
651 conf->proxy_recursive = NGX_CONF_UNSET;
652
653 cln = ngx_pool_cleanup_add(cf->pool, 0);
654 if (cln == NULL) {
655 return NULL;
656 }
657
658 cln->handler = ngx_http_geoip_cleanup;
659 cln->data = conf;
660
661 return conf;
662 }
663
664
665 static char *
ngx_http_geoip_init_conf(ngx_conf_t * cf,void * conf)666 ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf)
667 {
668 ngx_http_geoip_conf_t *gcf = conf;
669
670 ngx_conf_init_value(gcf->proxy_recursive, 0);
671
672 return NGX_CONF_OK;
673 }
674
675
676 static char *
ngx_http_geoip_country(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)677 ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
678 {
679 ngx_http_geoip_conf_t *gcf = conf;
680
681 ngx_str_t *value;
682
683 if (gcf->country) {
684 return "is duplicate";
685 }
686
687 value = cf->args->elts;
688
689 gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
690
691 if (gcf->country == NULL) {
692 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
693 "GeoIP_open(\"%V\") failed", &value[1]);
694
695 return NGX_CONF_ERROR;
696 }
697
698 if (cf->args->nelts == 3) {
699 if (ngx_strcmp(value[2].data, "utf8") == 0) {
700 GeoIP_set_charset(gcf->country, GEOIP_CHARSET_UTF8);
701
702 } else {
703 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
704 "invalid parameter \"%V\"", &value[2]);
705 return NGX_CONF_ERROR;
706 }
707 }
708
709 switch (gcf->country->databaseType) {
710
711 case GEOIP_COUNTRY_EDITION:
712
713 return NGX_CONF_OK;
714
715 #if (NGX_HAVE_GEOIP_V6)
716 case GEOIP_COUNTRY_EDITION_V6:
717
718 gcf->country_v6 = 1;
719 return NGX_CONF_OK;
720 #endif
721
722 default:
723 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
724 "invalid GeoIP database \"%V\" type:%d",
725 &value[1], gcf->country->databaseType);
726 return NGX_CONF_ERROR;
727 }
728 }
729
730
731 static char *
ngx_http_geoip_org(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)732 ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
733 {
734 ngx_http_geoip_conf_t *gcf = conf;
735
736 ngx_str_t *value;
737
738 if (gcf->org) {
739 return "is duplicate";
740 }
741
742 value = cf->args->elts;
743
744 gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
745
746 if (gcf->org == NULL) {
747 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
748 "GeoIP_open(\"%V\") failed", &value[1]);
749
750 return NGX_CONF_ERROR;
751 }
752
753 if (cf->args->nelts == 3) {
754 if (ngx_strcmp(value[2].data, "utf8") == 0) {
755 GeoIP_set_charset(gcf->org, GEOIP_CHARSET_UTF8);
756
757 } else {
758 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
759 "invalid parameter \"%V\"", &value[2]);
760 return NGX_CONF_ERROR;
761 }
762 }
763
764 switch (gcf->org->databaseType) {
765
766 case GEOIP_ISP_EDITION:
767 case GEOIP_ORG_EDITION:
768 case GEOIP_DOMAIN_EDITION:
769 case GEOIP_ASNUM_EDITION:
770
771 return NGX_CONF_OK;
772
773 #if (NGX_HAVE_GEOIP_V6)
774 case GEOIP_ISP_EDITION_V6:
775 case GEOIP_ORG_EDITION_V6:
776 case GEOIP_DOMAIN_EDITION_V6:
777 case GEOIP_ASNUM_EDITION_V6:
778
779 gcf->org_v6 = 1;
780 return NGX_CONF_OK;
781 #endif
782
783 default:
784 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
785 "invalid GeoIP database \"%V\" type:%d",
786 &value[1], gcf->org->databaseType);
787 return NGX_CONF_ERROR;
788 }
789 }
790
791
792 static char *
ngx_http_geoip_city(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)793 ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
794 {
795 ngx_http_geoip_conf_t *gcf = conf;
796
797 ngx_str_t *value;
798
799 if (gcf->city) {
800 return "is duplicate";
801 }
802
803 value = cf->args->elts;
804
805 gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
806
807 if (gcf->city == NULL) {
808 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
809 "GeoIP_open(\"%V\") failed", &value[1]);
810
811 return NGX_CONF_ERROR;
812 }
813
814 if (cf->args->nelts == 3) {
815 if (ngx_strcmp(value[2].data, "utf8") == 0) {
816 GeoIP_set_charset(gcf->city, GEOIP_CHARSET_UTF8);
817
818 } else {
819 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
820 "invalid parameter \"%V\"", &value[2]);
821 return NGX_CONF_ERROR;
822 }
823 }
824
825 switch (gcf->city->databaseType) {
826
827 case GEOIP_CITY_EDITION_REV0:
828 case GEOIP_CITY_EDITION_REV1:
829
830 return NGX_CONF_OK;
831
832 #if (NGX_HAVE_GEOIP_V6)
833 case GEOIP_CITY_EDITION_REV0_V6:
834 case GEOIP_CITY_EDITION_REV1_V6:
835
836 gcf->city_v6 = 1;
837 return NGX_CONF_OK;
838 #endif
839
840 default:
841 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
842 "invalid GeoIP City database \"%V\" type:%d",
843 &value[1], gcf->city->databaseType);
844 return NGX_CONF_ERROR;
845 }
846 }
847
848
849 static char *
ngx_http_geoip_proxy(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)850 ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
851 {
852 ngx_http_geoip_conf_t *gcf = conf;
853
854 ngx_str_t *value;
855 ngx_cidr_t cidr, *c;
856
857 value = cf->args->elts;
858
859 if (ngx_http_geoip_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
860 return NGX_CONF_ERROR;
861 }
862
863 if (gcf->proxies == NULL) {
864 gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t));
865 if (gcf->proxies == NULL) {
866 return NGX_CONF_ERROR;
867 }
868 }
869
870 c = ngx_array_push(gcf->proxies);
871 if (c == NULL) {
872 return NGX_CONF_ERROR;
873 }
874
875 *c = cidr;
876
877 return NGX_CONF_OK;
878 }
879
880 static ngx_int_t
ngx_http_geoip_cidr_value(ngx_conf_t * cf,ngx_str_t * net,ngx_cidr_t * cidr)881 ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
882 {
883 ngx_int_t rc;
884
885 if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
886 cidr->family = AF_INET;
887 cidr->u.in.addr = 0xffffffff;
888 cidr->u.in.mask = 0xffffffff;
889
890 return NGX_OK;
891 }
892
893 rc = ngx_ptocidr(net, cidr);
894
895 if (rc == NGX_ERROR) {
896 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
897 return NGX_ERROR;
898 }
899
900 if (rc == NGX_DONE) {
901 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
902 "low address bits of %V are meaningless", net);
903 }
904
905 return NGX_OK;
906 }
907
908
909 static void
ngx_http_geoip_cleanup(void * data)910 ngx_http_geoip_cleanup(void *data)
911 {
912 ngx_http_geoip_conf_t *gcf = data;
913
914 if (gcf->country) {
915 GeoIP_delete(gcf->country);
916 }
917
918 if (gcf->org) {
919 GeoIP_delete(gcf->org);
920 }
921
922 if (gcf->city) {
923 GeoIP_delete(gcf->city);
924 }
925 }
926