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;