Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_geoip_module.c @ 5015:a74d211f034d
GeoIP: IPv6 support.
When using IPv6 databases, IPv4 addresses are looked up as IPv4-mapped
IPv6 addresses.
Mostly based on a patch by Gregor Kališnik (ticket #250).
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Thu, 24 Jan 2013 16:15:51 +0000 |
parents | f57154322e0e |
children | 795722a74254 |
comparison
equal
deleted
inserted
replaced
5014:210b66a6fc7f | 5015:a74d211f034d |
---|---|
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_http.h> | 10 #include <ngx_http.h> |
11 | 11 |
12 #include <GeoIP.h> | 12 #include <GeoIP.h> |
13 #include <GeoIPCity.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 | |
14 | 19 |
15 | 20 |
16 typedef struct { | 21 typedef struct { |
17 GeoIP *country; | 22 GeoIP *country; |
18 GeoIP *org; | 23 GeoIP *org; |
19 GeoIP *city; | 24 GeoIP *city; |
20 ngx_array_t *proxies; /* array of ngx_cidr_t */ | 25 ngx_array_t *proxies; /* array of ngx_cidr_t */ |
21 ngx_flag_t proxy_recursive; | 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 | |
22 } ngx_http_geoip_conf_t; | 32 } ngx_http_geoip_conf_t; |
23 | 33 |
24 | 34 |
25 typedef struct { | 35 typedef struct { |
26 ngx_str_t *name; | 36 ngx_str_t *name; |
27 uintptr_t data; | 37 uintptr_t data; |
28 } ngx_http_geoip_var_t; | 38 } ngx_http_geoip_var_t; |
29 | 39 |
30 | 40 |
31 typedef char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr); | 41 typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, |
32 | 42 u_long addr); |
33 static u_long ngx_http_geoip_addr(ngx_http_request_t *r, | 43 |
34 ngx_http_geoip_conf_t *gcf); | 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 | |
35 static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, | 67 static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, |
36 ngx_http_variable_value_t *v, uintptr_t data); | 68 ngx_http_variable_value_t *v, uintptr_t data); |
37 static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r, | 69 static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r, |
38 ngx_http_variable_value_t *v, uintptr_t data); | 70 ngx_http_variable_value_t *v, uintptr_t data); |
39 static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, | 71 static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, |
136 | 168 |
137 static ngx_http_variable_t ngx_http_geoip_vars[] = { | 169 static ngx_http_variable_t ngx_http_geoip_vars[] = { |
138 | 170 |
139 { ngx_string("geoip_country_code"), NULL, | 171 { ngx_string("geoip_country_code"), NULL, |
140 ngx_http_geoip_country_variable, | 172 ngx_http_geoip_country_variable, |
141 (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 }, | 173 NGX_GEOIP_COUNTRY_CODE, 0, 0 }, |
142 | 174 |
143 { ngx_string("geoip_country_code3"), NULL, | 175 { ngx_string("geoip_country_code3"), NULL, |
144 ngx_http_geoip_country_variable, | 176 ngx_http_geoip_country_variable, |
145 (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 }, | 177 NGX_GEOIP_COUNTRY_CODE3, 0, 0 }, |
146 | 178 |
147 { ngx_string("geoip_country_name"), NULL, | 179 { ngx_string("geoip_country_name"), NULL, |
148 ngx_http_geoip_country_variable, | 180 ngx_http_geoip_country_variable, |
149 (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 }, | 181 NGX_GEOIP_COUNTRY_NAME, 0, 0 }, |
150 | 182 |
151 { ngx_string("geoip_org"), NULL, | 183 { ngx_string("geoip_org"), NULL, |
152 ngx_http_geoip_org_variable, | 184 ngx_http_geoip_org_variable, |
153 (uintptr_t) GeoIP_name_by_ipnum, 0, 0 }, | 185 0, 0, 0 }, |
154 | 186 |
155 { ngx_string("geoip_city_continent_code"), NULL, | 187 { ngx_string("geoip_city_continent_code"), NULL, |
156 ngx_http_geoip_city_variable, | 188 ngx_http_geoip_city_variable, |
157 offsetof(GeoIPRecord, continent_code), 0, 0 }, | 189 offsetof(GeoIPRecord, continent_code), 0, 0 }, |
158 | 190 |
253 sin = (struct sockaddr_in *) addr.sockaddr; | 285 sin = (struct sockaddr_in *) addr.sockaddr; |
254 return ntohl(sin->sin_addr.s_addr); | 286 return ntohl(sin->sin_addr.s_addr); |
255 } | 287 } |
256 | 288 |
257 | 289 |
290 #if (NGX_HAVE_GEOIP_V6) | |
291 | |
292 static geoipv6_t | |
293 ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf) | |
294 { | |
295 ngx_addr_t addr; | |
296 ngx_table_elt_t *xfwd; | |
297 in_addr_t addr4; | |
298 struct in6_addr addr6; | |
299 struct sockaddr_in *sin; | |
300 struct sockaddr_in6 *sin6; | |
301 | |
302 addr.sockaddr = r->connection->sockaddr; | |
303 addr.socklen = r->connection->socklen; | |
304 /* addr.name = r->connection->addr_text; */ | |
305 | |
306 xfwd = r->headers_in.x_forwarded_for; | |
307 | |
308 if (xfwd != NULL && gcf->proxies != NULL) { | |
309 (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data, | |
310 xfwd->value.len, gcf->proxies, | |
311 gcf->proxy_recursive); | |
312 } | |
313 | |
314 switch (addr.sockaddr->sa_family) { | |
315 | |
316 case AF_INET: | |
317 /* Produce IPv4-mapped IPv6 address. */ | |
318 sin = (struct sockaddr_in *) addr.sockaddr; | |
319 addr4 = ntohl(sin->sin_addr.s_addr); | |
320 | |
321 ngx_memzero(&addr6, sizeof(struct in6_addr)); | |
322 addr6.s6_addr[10] = 0xff; | |
323 addr6.s6_addr[11] = 0xff; | |
324 addr6.s6_addr[12] = addr4 >> 24; | |
325 addr6.s6_addr[13] = addr4 >> 16; | |
326 addr6.s6_addr[14] = addr4 >> 8; | |
327 addr6.s6_addr[15] = addr4; | |
328 return addr6; | |
329 | |
330 case AF_INET6: | |
331 sin6 = (struct sockaddr_in6 *) addr.sockaddr; | |
332 return sin6->sin6_addr; | |
333 | |
334 default: | |
335 return in6addr_any; | |
336 } | |
337 } | |
338 | |
339 #endif | |
340 | |
341 | |
258 static ngx_int_t | 342 static ngx_int_t |
259 ngx_http_geoip_country_variable(ngx_http_request_t *r, | 343 ngx_http_geoip_country_variable(ngx_http_request_t *r, |
260 ngx_http_variable_value_t *v, uintptr_t data) | 344 ngx_http_variable_value_t *v, uintptr_t data) |
261 { | 345 { |
262 ngx_http_geoip_variable_handler_pt handler = | 346 ngx_http_geoip_variable_handler_pt handler = |
263 (ngx_http_geoip_variable_handler_pt) data; | 347 ngx_http_geoip_country_functions[data]; |
348 #if (NGX_HAVE_GEOIP_V6) | |
349 ngx_http_geoip_variable_handler_v6_pt handler_v6 = | |
350 ngx_http_geoip_country_v6_functions[data]; | |
351 #endif | |
264 | 352 |
265 const char *val; | 353 const char *val; |
266 ngx_http_geoip_conf_t *gcf; | 354 ngx_http_geoip_conf_t *gcf; |
267 | 355 |
268 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); | 356 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); |
269 | 357 |
270 if (gcf->country == NULL) { | 358 if (gcf->country == NULL) { |
271 goto not_found; | 359 goto not_found; |
272 } | 360 } |
273 | 361 |
362 #if (NGX_HAVE_GEOIP_V6) | |
363 val = gcf->country_v6 | |
364 ? handler_v6(gcf->country, ngx_http_geoip_addr_v6(r, gcf)) | |
365 : handler(gcf->country, ngx_http_geoip_addr(r, gcf)); | |
366 #else | |
274 val = handler(gcf->country, ngx_http_geoip_addr(r, gcf)); | 367 val = handler(gcf->country, ngx_http_geoip_addr(r, gcf)); |
368 #endif | |
275 | 369 |
276 if (val == NULL) { | 370 if (val == NULL) { |
277 goto not_found; | 371 goto not_found; |
278 } | 372 } |
279 | 373 |
295 | 389 |
296 static ngx_int_t | 390 static ngx_int_t |
297 ngx_http_geoip_org_variable(ngx_http_request_t *r, | 391 ngx_http_geoip_org_variable(ngx_http_request_t *r, |
298 ngx_http_variable_value_t *v, uintptr_t data) | 392 ngx_http_variable_value_t *v, uintptr_t data) |
299 { | 393 { |
300 ngx_http_geoip_variable_handler_pt handler = | |
301 (ngx_http_geoip_variable_handler_pt) data; | |
302 | |
303 size_t len; | 394 size_t len; |
304 char *val; | 395 char *val; |
305 ngx_http_geoip_conf_t *gcf; | 396 ngx_http_geoip_conf_t *gcf; |
306 | 397 |
307 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); | 398 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); |
308 | 399 |
309 if (gcf->org == NULL) { | 400 if (gcf->org == NULL) { |
310 goto not_found; | 401 goto not_found; |
311 } | 402 } |
312 | 403 |
313 val = handler(gcf->org, ngx_http_geoip_addr(r, gcf)); | 404 #if (NGX_HAVE_GEOIP_V6) |
405 val = gcf->org_v6 | |
406 ? GeoIP_name_by_ipnum_v6(gcf->org, | |
407 ngx_http_geoip_addr_v6(r, gcf)) | |
408 : GeoIP_name_by_ipnum(gcf->org, | |
409 ngx_http_geoip_addr(r, gcf)); | |
410 #else | |
411 val = GeoIP_name_by_ipnum(gcf->org, ngx_http_geoip_addr(r, gcf)); | |
412 #endif | |
314 | 413 |
315 if (val == NULL) { | 414 if (val == NULL) { |
316 goto not_found; | 415 goto not_found; |
317 } | 416 } |
318 | 417 |
498 ngx_http_geoip_conf_t *gcf; | 597 ngx_http_geoip_conf_t *gcf; |
499 | 598 |
500 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); | 599 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); |
501 | 600 |
502 if (gcf->city) { | 601 if (gcf->city) { |
602 #if (NGX_HAVE_GEOIP_V6) | |
603 return gcf->city_v6 | |
604 ? GeoIP_record_by_ipnum_v6(gcf->city, | |
605 ngx_http_geoip_addr_v6(r, gcf)) | |
606 : GeoIP_record_by_ipnum(gcf->city, | |
607 ngx_http_geoip_addr(r, gcf)); | |
608 #else | |
503 return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf)); | 609 return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf)); |
610 #endif | |
504 } | 611 } |
505 | 612 |
506 return NULL; | 613 return NULL; |
507 } | 614 } |
508 | 615 |
601 case GEOIP_PROXY_EDITION: | 708 case GEOIP_PROXY_EDITION: |
602 case GEOIP_NETSPEED_EDITION: | 709 case GEOIP_NETSPEED_EDITION: |
603 | 710 |
604 return NGX_CONF_OK; | 711 return NGX_CONF_OK; |
605 | 712 |
713 #if (NGX_HAVE_GEOIP_V6) | |
714 case GEOIP_COUNTRY_EDITION_V6: | |
715 | |
716 gcf->country_v6 = 1; | |
717 return NGX_CONF_OK; | |
718 #endif | |
719 | |
606 default: | 720 default: |
607 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 721 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
608 "invalid GeoIP database \"%V\" type:%d", | 722 "invalid GeoIP database \"%V\" type:%d", |
609 &value[1], gcf->country->databaseType); | 723 &value[1], gcf->country->databaseType); |
610 return NGX_CONF_ERROR; | 724 return NGX_CONF_ERROR; |
652 case GEOIP_DOMAIN_EDITION: | 766 case GEOIP_DOMAIN_EDITION: |
653 case GEOIP_ASNUM_EDITION: | 767 case GEOIP_ASNUM_EDITION: |
654 | 768 |
655 return NGX_CONF_OK; | 769 return NGX_CONF_OK; |
656 | 770 |
771 #if (NGX_HAVE_GEOIP_V6) | |
772 case GEOIP_ISP_EDITION_V6: | |
773 case GEOIP_ORG_EDITION_V6: | |
774 case GEOIP_DOMAIN_EDITION_V6: | |
775 case GEOIP_ASNUM_EDITION_V6: | |
776 | |
777 gcf->org_v6 = 1; | |
778 return NGX_CONF_OK; | |
779 #endif | |
780 | |
657 default: | 781 default: |
658 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 782 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
659 "invalid GeoIP database \"%V\" type:%d", | 783 "invalid GeoIP database \"%V\" type:%d", |
660 &value[1], gcf->org->databaseType); | 784 &value[1], gcf->org->databaseType); |
661 return NGX_CONF_ERROR; | 785 return NGX_CONF_ERROR; |
701 case GEOIP_CITY_EDITION_REV0: | 825 case GEOIP_CITY_EDITION_REV0: |
702 case GEOIP_CITY_EDITION_REV1: | 826 case GEOIP_CITY_EDITION_REV1: |
703 | 827 |
704 return NGX_CONF_OK; | 828 return NGX_CONF_OK; |
705 | 829 |
830 #if (NGX_HAVE_GEOIP_V6) | |
831 case GEOIP_CITY_EDITION_REV0_V6: | |
832 case GEOIP_CITY_EDITION_REV1_V6: | |
833 | |
834 gcf->city_v6 = 1; | |
835 return NGX_CONF_OK; | |
836 #endif | |
837 | |
706 default: | 838 default: |
707 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 839 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
708 "invalid GeoIP City database \"%V\" type:%d", | 840 "invalid GeoIP City database \"%V\" type:%d", |
709 &value[1], gcf->city->databaseType); | 841 &value[1], gcf->city->databaseType); |
710 return NGX_CONF_ERROR; | 842 return NGX_CONF_ERROR; |