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).
This commit is contained in:
Ruslan Ermilov 2013-01-24 16:15:51 +00:00
parent 6aa684c3c3
commit db5e48d9b8
2 changed files with 157 additions and 13 deletions

View File

@ -69,6 +69,18 @@ if [ $ngx_found = yes ]; then
CORE_INCS="$CORE_INCS $ngx_feature_path"
CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
if [ $NGX_IPV6 = YES ]; then
ngx_feature="GeoIP IPv6 support"
ngx_feature_name="NGX_HAVE_GEOIP_V6"
ngx_feature_run=no
ngx_feature_incs="#include <stdio.h>
#include <GeoIP.h>"
#ngx_feature_path=
#ngx_feature_libs=
ngx_feature_test="printf(\"%d\", GEOIP_CITY_EDITION_REV0_V6);"
. auto/feature
fi
else
cat << END

View File

@ -13,12 +13,22 @@
#include <GeoIPCity.h>
#define NGX_GEOIP_COUNTRY_CODE 0
#define NGX_GEOIP_COUNTRY_CODE3 1
#define NGX_GEOIP_COUNTRY_NAME 2
typedef struct {
GeoIP *country;
GeoIP *org;
GeoIP *city;
ngx_array_t *proxies; /* array of ngx_cidr_t */
ngx_flag_t proxy_recursive;
#if (NGX_HAVE_GEOIP_V6)
unsigned country_v6:1;
unsigned org_v6:1;
unsigned city_v6:1;
#endif
} ngx_http_geoip_conf_t;
@ -28,10 +38,32 @@ typedef struct {
} ngx_http_geoip_var_t;
typedef char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr);
typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *,
u_long addr);
ngx_http_geoip_variable_handler_pt ngx_http_geoip_country_functions[] = {
GeoIP_country_code_by_ipnum,
GeoIP_country_code3_by_ipnum,
GeoIP_country_name_by_ipnum,
};
#if (NGX_HAVE_GEOIP_V6)
typedef const char *(*ngx_http_geoip_variable_handler_v6_pt)(GeoIP *,
geoipv6_t addr);
ngx_http_geoip_variable_handler_v6_pt ngx_http_geoip_country_v6_functions[] = {
GeoIP_country_code_by_ipnum_v6,
GeoIP_country_code3_by_ipnum_v6,
GeoIP_country_name_by_ipnum_v6,
};
#endif
static u_long ngx_http_geoip_addr(ngx_http_request_t *r,
ngx_http_geoip_conf_t *gcf);
static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r,
@ -138,19 +170,19 @@ static ngx_http_variable_t ngx_http_geoip_vars[] = {
{ ngx_string("geoip_country_code"), NULL,
ngx_http_geoip_country_variable,
(uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 },
NGX_GEOIP_COUNTRY_CODE, 0, 0 },
{ ngx_string("geoip_country_code3"), NULL,
ngx_http_geoip_country_variable,
(uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 },
NGX_GEOIP_COUNTRY_CODE3, 0, 0 },
{ ngx_string("geoip_country_name"), NULL,
ngx_http_geoip_country_variable,
(uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 },
NGX_GEOIP_COUNTRY_NAME, 0, 0 },
{ ngx_string("geoip_org"), NULL,
ngx_http_geoip_org_variable,
(uintptr_t) GeoIP_name_by_ipnum, 0, 0 },
0, 0, 0 },
{ ngx_string("geoip_city_continent_code"), NULL,
ngx_http_geoip_city_variable,
@ -255,12 +287,68 @@ ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
}
#if (NGX_HAVE_GEOIP_V6)
static geoipv6_t
ngx_http_geoip_addr_v6(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
{
ngx_addr_t addr;
ngx_table_elt_t *xfwd;
in_addr_t addr4;
struct in6_addr addr6;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
addr.sockaddr = r->connection->sockaddr;
addr.socklen = r->connection->socklen;
/* addr.name = r->connection->addr_text; */
xfwd = r->headers_in.x_forwarded_for;
if (xfwd != NULL && gcf->proxies != NULL) {
(void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data,
xfwd->value.len, gcf->proxies,
gcf->proxy_recursive);
}
switch (addr.sockaddr->sa_family) {
case AF_INET:
/* Produce IPv4-mapped IPv6 address. */
sin = (struct sockaddr_in *) addr.sockaddr;
addr4 = ntohl(sin->sin_addr.s_addr);
ngx_memzero(&addr6, sizeof(struct in6_addr));
addr6.s6_addr[10] = 0xff;
addr6.s6_addr[11] = 0xff;
addr6.s6_addr[12] = addr4 >> 24;
addr6.s6_addr[13] = addr4 >> 16;
addr6.s6_addr[14] = addr4 >> 8;
addr6.s6_addr[15] = addr4;
return addr6;
case AF_INET6:
sin6 = (struct sockaddr_in6 *) addr.sockaddr;
return sin6->sin6_addr;
default:
return in6addr_any;
}
}
#endif
static ngx_int_t
ngx_http_geoip_country_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_http_geoip_variable_handler_pt handler =
(ngx_http_geoip_variable_handler_pt) data;
ngx_http_geoip_variable_handler_pt handler =
ngx_http_geoip_country_functions[data];
#if (NGX_HAVE_GEOIP_V6)
ngx_http_geoip_variable_handler_v6_pt handler_v6 =
ngx_http_geoip_country_v6_functions[data];
#endif
const char *val;
ngx_http_geoip_conf_t *gcf;
@ -271,7 +359,13 @@ ngx_http_geoip_country_variable(ngx_http_request_t *r,
goto not_found;
}
#if (NGX_HAVE_GEOIP_V6)
val = gcf->country_v6
? handler_v6(gcf->country, ngx_http_geoip_addr_v6(r, gcf))
: handler(gcf->country, ngx_http_geoip_addr(r, gcf));
#else
val = handler(gcf->country, ngx_http_geoip_addr(r, gcf));
#endif
if (val == NULL) {
goto not_found;
@ -297,9 +391,6 @@ static ngx_int_t
ngx_http_geoip_org_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ngx_http_geoip_variable_handler_pt handler =
(ngx_http_geoip_variable_handler_pt) data;
size_t len;
char *val;
ngx_http_geoip_conf_t *gcf;
@ -310,7 +401,15 @@ ngx_http_geoip_org_variable(ngx_http_request_t *r,
goto not_found;
}
val = handler(gcf->org, ngx_http_geoip_addr(r, gcf));
#if (NGX_HAVE_GEOIP_V6)
val = gcf->org_v6
? GeoIP_name_by_ipnum_v6(gcf->org,
ngx_http_geoip_addr_v6(r, gcf))
: GeoIP_name_by_ipnum(gcf->org,
ngx_http_geoip_addr(r, gcf));
#else
val = GeoIP_name_by_ipnum(gcf->org, ngx_http_geoip_addr(r, gcf));
#endif
if (val == NULL) {
goto not_found;
@ -500,7 +599,15 @@ ngx_http_geoip_get_city_record(ngx_http_request_t *r)
gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
if (gcf->city) {
#if (NGX_HAVE_GEOIP_V6)
return gcf->city_v6
? GeoIP_record_by_ipnum_v6(gcf->city,
ngx_http_geoip_addr_v6(r, gcf))
: GeoIP_record_by_ipnum(gcf->city,
ngx_http_geoip_addr(r, gcf));
#else
return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf));
#endif
}
return NULL;
@ -603,6 +710,13 @@ ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
#if (NGX_HAVE_GEOIP_V6)
case GEOIP_COUNTRY_EDITION_V6:
gcf->country_v6 = 1;
return NGX_CONF_OK;
#endif
default:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid GeoIP database \"%V\" type:%d",
@ -654,6 +768,16 @@ ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
#if (NGX_HAVE_GEOIP_V6)
case GEOIP_ISP_EDITION_V6:
case GEOIP_ORG_EDITION_V6:
case GEOIP_DOMAIN_EDITION_V6:
case GEOIP_ASNUM_EDITION_V6:
gcf->org_v6 = 1;
return NGX_CONF_OK;
#endif
default:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid GeoIP database \"%V\" type:%d",
@ -703,6 +827,14 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_OK;
#if (NGX_HAVE_GEOIP_V6)
case GEOIP_CITY_EDITION_REV0_V6:
case GEOIP_CITY_EDITION_REV1_V6:
gcf->city_v6 = 1;
return NGX_CONF_OK;
#endif
default:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid GeoIP City database \"%V\" type:%d",