Hello all,
geoip module currently only supports a single country and a single city
MaxMind database that must cover IPv4 address range.
Below patch allows setting up to two city and country databases, one
for IPv4 and one for IPv6. It then looks-up the requesting IP address in
the appropriate database.
Please review and consider applying,
Bruno
diff -NurpP nginx-1.0.4.orig/src/http/modules/ngx_http_geoip_module.c
nginx-1.0.4/src/http/modules/ngx_http_geoip_module.c
— nginx-1.0.4.orig/src/http/modules/ngx_http_geoip_module.c
2011-05-16 15:50:58.000000000 +0200
+++ nginx-1.0.4/src/http/modules/ngx_http_geoip_module.c 2011-09-30
10:30:18.785083263 +0200
@@ -16,6 +16,9 @@ typedef struct {
GeoIP *country;
GeoIP *org;
GeoIP *city;
- GeoIP *country_v6;
- GeoIP *org_v6;
- GeoIP *city_v6;
} ngx_http_geoip_conf_t;
@@ -26,8 +29,13 @@ typedef struct {
typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *,
u_long addr);
+typedef const char *(*ngx_http_geoip_variable_handler6_pt)(GeoIP *,
struct in6_addr addr);
-static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
+static ngx_int_t
ngx_http_geoip_country_code_variable(ngx_http_request_t *r,
-
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t
ngx_http_geoip_country_code3_variable(ngx_http_request_t *r, -
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t
ngx_http_geoip_country_name_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,
ngx_http_variable_value_t *v, uintptr_t data);
@@ -113,16 +121,16 @@ ngx_module_t ngx_http_geoip_module = {
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_http_geoip_country_code_variable,
-
0, 0, 0 },
{ ngx_string(“geoip_country_code3”), NULL,
-
ngx_http_geoip_country_variable,
-
(uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 },
-
ngx_http_geoip_country_code3_variable,
-
0, 0, 0 },
{ ngx_string(“geoip_country_name”), NULL,
-
ngx_http_geoip_country_variable,
-
(uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 },
-
ngx_http_geoip_country_name_variable,
-
0, 0, 0 },
{ ngx_string(“geoip_org”), NULL,
ngx_http_geoip_org_variable,
@@ -180,117 +188,146 @@ static ngx_http_variable_t ngx_http_geo
};
-static u_long
-ngx_http_geoip_addr(ngx_http_request_t *r)
+static ngx_int_t
+ngx_http_geoip_get_char(ngx_http_request_t *r,
ngx_http_variable_value_t *v,
- GeoIP *src, ngx_http_geoip_variable_handler_pt handler,
- GeoIP *src_v6, ngx_http_geoip_variable_handler6_pt handler_v6)
{
- struct sockaddr_in *sin;
-#if (NGX_HAVE_INET6) - u_char *p;
- u_long addr;
- struct sockaddr_in6 *sin6;
-#endif
- const char *ret = NULL;
switch (r->connection->sockaddr->sa_family) {
- case AF_INET:
-
sin = (struct sockaddr_in *) r->connection->sockaddr;
-
return ntohl(sin->sin_addr.s_addr);
-
if (src) {
-
struct sockaddr_in *sin = (struct sockaddr_in *)
r->connection->sockaddr;
-
ret = handler(src, ntohl(sin->sin_addr.s_addr));
-
}
-
break;
#if (NGX_HAVE_INET6)
case AF_INET6:
-
sin6 = (struct sockaddr_in6 *) r->connection->sockaddr;
-
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
-
p = sin6->sin6_addr.s6_addr;
-
addr = p[12] << 24;
-
addr += p[13] << 16;
-
addr += p[14] << 8;
-
addr += p[15];
-
return addr;
-
if (src_v6) {
-
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
r->connection->sockaddr;
-
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
-
u_char *p = sin6->sin6_addr.s6_addr;
-
ret = src ? handler(src, (p[12] << 24) + (p[13] << 16)
- (p[14] << 8) + p[15]) : NULL;
-
} else
-
ret = handler_v6(src_v6, sin6->sin6_addr); }
-
break;
#endif
}
- return INADDR_NONE;
- if (ret == NULL) {
-
goto not_found;
- }
- v->len = ngx_strlen(ret);
- v->valid = 1;
- v->no_cacheable = 0;
- v->not_found = 0;
- v->data = (u_char *) ret;
- return NGX_OK;
+not_found:
+
- v->not_found = 1;
- return NGX_OK;
}
static ngx_int_t
-ngx_http_geoip_country_variable(ngx_http_request_t *r,
+ngx_http_geoip_country_code_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;
-
const char *val;
ngx_http_geoip_conf_t *gcf;gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
-
if (gcf->country == NULL) {
-
goto not_found;
- if (gcf->country == NULL && gcf->country_v6 == NULL) {
-
v->not_found = 1;
-
}return NGX_OK;
- val = handler(gcf->country, ngx_http_geoip_addr®);
- return ngx_http_geoip_get_char(r, v, gcf->country,
&GeoIP_country_code_by_ipnum,
+#if (NGX_HAVE_INET6) -
gcf->country_v6, &GeoIP_country_code_by_ipnum_v6
+#else
-
NULL, NULL
+#endif
-
);
+}
-
if (val == NULL) {
-
goto not_found;
-
}
-
v->len = ngx_strlen(val);
-
v->valid = 1;
-
v->no_cacheable = 0;
-
v->not_found = 0;
-
v->data = (u_char *) val;
+static ngx_int_t
+ngx_http_geoip_country_code3_variable(ngx_http_request_t *r,
- ngx_http_variable_value_t *v, uintptr_t data)
+{ - ngx_http_geoip_conf_t *gcf;
- return NGX_OK;
- gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
-not_found:
- if (gcf->country == NULL && gcf->country_v6 == NULL) {
-
v->not_found = 1;
- v->not_found = 1;
-
return NGX_OK;
- }
- return NGX_OK;
- return ngx_http_geoip_get_char(r, v, gcf->country,
&GeoIP_country_code3_by_ipnum,
+#if (NGX_HAVE_INET6) -
gcf->country_v6, &GeoIP_country_code3_by_ipnum_v6
+#else
-
NULL, NULL
+#endif
-
);
}
static ngx_int_t
-ngx_http_geoip_org_variable(ngx_http_request_t *r,
+ngx_http_geoip_country_name_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;
-
const char *val;
ngx_http_geoip_conf_t *gcf;gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
-
if (gcf->org == NULL) {
-
goto not_found;
- if (gcf->country == NULL && gcf->country_v6 == NULL) {
-
v->not_found = 1;
-
}return NGX_OK;
- val = handler(gcf->org, ngx_http_geoip_addr®);
- return ngx_http_geoip_get_char(r, v, gcf->country,
&GeoIP_country_name_by_ipnum,
+#if (NGX_HAVE_INET6) -
gcf->country_v6, &GeoIP_country_name_by_ipnum_v6
+#else
-
NULL, NULL
+#endif
-
);
+}
-
if (val == NULL) {
-
goto not_found;
-
}
-
v->len = ngx_strlen(val);
-
v->valid = 1;
-
v->no_cacheable = 0;
-
v->not_found = 0;
-
v->data = (u_char *) val;
+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_conf_t *gcf;
- return NGX_OK;
- gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
-not_found:
- if (gcf->org == NULL && gcf->org_v6 == NULL) {
-
v->not_found = 1;
- v->not_found = 1;
-
return NGX_OK;
- }
- return NGX_OK;
- return ngx_http_geoip_get_char(r, v, gcf->org,
(ngx_http_geoip_variable_handler_pt)&GeoIP_name_by_ipnum,
+#if (NGX_HAVE_INET6) -
gcf->org_v6,
(ngx_http_geoip_variable_handler6_pt)&GeoIP_name_by_ipnum_v6
+#else
-
NULL, NULL
+#endif
-
);
}
@@ -451,8 +488,26 @@ ngx_http_geoip_get_city_record(ngx_http_
gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
- if (gcf->city) {
-
return GeoIP_record_by_ipnum(gcf->city,
ngx_http_geoip_addr®);
- switch (r->connection->sockaddr->sa_family) {
- case AF_INET:
-
if (gcf->city) {
-
struct sockaddr_in *sin = (struct sockaddr_in *)
r->connection->sockaddr;
-
return GeoIP_record_by_ipnum(gcf->city,
ntohl(sin->sin_addr.s_addr));
-
}
-
return NULL;
+#if (NGX_HAVE_INET6)
- case AF_INET6:
-
if (gcf->city_v6) {
-
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
r->connection->sockaddr;
-
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
-
u_char *p = sin6->sin6_addr.s6_addr;
-
return gcf->city ? GeoIP_record_by_ipnum(gcf->city,
-
(p[12] << 24) + (p[13] << 16) + (p[14] <<
-
- p[15]) : NULL;
-
} else
-
return GeoIP_record_by_ipnum_v6(gcf->city_v6,
sin6->sin6_addr);
-
}
-
return NULL;
+#endif
}
return NULL;
@@ -505,18 +560,19 @@ static char *
ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_geoip_conf_t *gcf = conf;
-
GeoIP *tmp;
ngx_str_t *value;
- if (gcf->country) {
-
if (gcf->country && gcf->country_v6) {
return “is duplicate”;
}value = cf->args->elts;
- gcf->country = GeoIP_open((char *) value[1].data,
GEOIP_MEMORY_CACHE);
- tmp = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
- if (gcf->country == NULL) {
- if (tmp == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
“GeoIP_open(”%V") failed", &value[1]);
@@ -525,7 +581,7 @@ ngx_http_geoip_country(ngx_conf_t *cf, n
if (cf->args->nelts == 3) {
if (ngx_strcmp(value[2].data, "utf8") == 0) {
-
GeoIP_set_charset (gcf->country, GEOIP_CHARSET_UTF8);
-
GeoIP_set_charset (tmp, GEOIP_CHARSET_UTF8); } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -534,18 +590,33 @@ ngx_http_geoip_country(ngx_conf_t *cf, n
}
}
- switch (gcf->country->databaseType) {
-
switch (tmp->databaseType) {
case GEOIP_COUNTRY_EDITION:
case GEOIP_PROXY_EDITION:
case GEOIP_NETSPEED_EDITION: -
if (gcf->country) {
-
GeoIP_delete(tmp);
-
return "is duplicate";
-
} else
-
gcf->country = tmp;
-
return NGX_CONF_OK;
+#if (NGX_HAVE_INET6)
- case GEOIP_COUNTRY_EDITION_V6:
-
if (gcf->country_v6) {
-
GeoIP_delete(tmp);
-
return "is duplicate";
-
} else
-
gcf->country_v6 = tmp; return NGX_CONF_OK;
+#endif
default:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid GeoIP database \"%V\" type:%d",
-
&value[1], gcf->country->databaseType);
-
&value[1], tmp->databaseType);
-
GeoIP_delete(tmp); return NGX_CONF_ERROR;
}
}
@@ -555,18 +626,19 @@ static char *
ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_geoip_conf_t *gcf = conf; -
GeoIP *tmp;
ngx_str_t *value;
- if (gcf->org) {
-
if (gcf->org && gcf->org_v6) {
return “is duplicate”;
}value = cf->args->elts;
- gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
- tmp = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
- if (gcf->org == NULL) {
- if (tmp == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
“GeoIP_open(”%V") failed", &value[1]);
@@ -575,7 +647,7 @@ ngx_http_geoip_org(ngx_conf_t *cf, ngx_c
if (cf->args->nelts == 3) {
if (ngx_strcmp(value[2].data, "utf8") == 0) {
-
GeoIP_set_charset (gcf->org, GEOIP_CHARSET_UTF8);
-
GeoIP_set_charset (tmp, GEOIP_CHARSET_UTF8); } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -584,19 +656,37 @@ ngx_http_geoip_org(ngx_conf_t *cf, ngx_c
}
}
- switch (gcf->org->databaseType) {
-
switch (tmp->databaseType) {
case GEOIP_ISP_EDITION:
case GEOIP_ORG_EDITION:
case GEOIP_DOMAIN_EDITION:
case GEOIP_ASNUM_EDITION: -
if (gcf->org) {
-
GeoIP_delete(tmp);
-
return "is duplicate";
-
} else
-
gcf->org = tmp;
-
return NGX_CONF_OK;
+#if (NGX_HAVE_INET6)
- case GEOIP_ISP_EDITION_V6:
- case GEOIP_ORG_EDITION_V6:
- case GEOIP_DOMAIN_EDITION_V6:
- case GEOIP_ASNUM_EDITION_V6:
-
if (gcf->org_v6) {
-
GeoIP_delete(tmp);
-
return "is duplicate";
-
} else
-
gcf->org_v6 = tmp; return NGX_CONF_OK;
+#endif
default:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid GeoIP database \"%V\" type:%d",
-
&value[1], gcf->org->databaseType);
-
&value[1], tmp->databaseType);
-
GeoIP_delete(tmp); return NGX_CONF_ERROR;
}
}
@@ -606,18 +696,19 @@ static char *
ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_geoip_conf_t *gcf = conf; -
GeoIP *tmp;
ngx_str_t *value;
- if (gcf->city) {
-
if (gcf->city && gcf->city_v6) {
return “is duplicate”;
}value = cf->args->elts;
- gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
- tmp = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
- if (gcf->city == NULL) {
- if (tmp == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
“GeoIP_open(”%V") failed", &value[1]);
@@ -626,7 +717,7 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_
if (cf->args->nelts == 3) {
if (ngx_strcmp(value[2].data, "utf8") == 0) {
-
GeoIP_set_charset (gcf->city, GEOIP_CHARSET_UTF8);
-
GeoIP_set_charset (tmp, GEOIP_CHARSET_UTF8); } else { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -635,17 +726,32 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_
}
}
- switch (gcf->city->databaseType) {
-
switch (tmp->databaseType) {
case GEOIP_CITY_EDITION_REV0:
case GEOIP_CITY_EDITION_REV1: -
if (gcf->city) {
-
GeoIP_delete(tmp);
-
return "is duplicate";
-
} else
-
gcf->city = tmp;
-
return NGX_CONF_OK;
+#if (NGX_HAVE_INET6)
- case GEOIP_CITY_EDITION_REV0_V6:
- case GEOIP_CITY_EDITION_REV1_V6:
-
if (gcf->city_v6) {
-
GeoIP_delete(tmp);
-
return "is duplicate";
-
} else
-
gcf->city_v6 = tmp; return NGX_CONF_OK;
+#endif
default:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid GeoIP City database \"%V\"
type:%d",
-
&value[1], gcf->city->databaseType);
-
&value[1], tmp->databaseType); return NGX_CONF_ERROR;
}
}
@@ -659,12 +765,21 @@ ngx_http_geoip_cleanup(void *data)
if (gcf->country) {
GeoIP_delete(gcf->country);
} -
if (gcf->country_v6) {
-
GeoIP_delete(gcf->country_v6);
-
}
if (gcf->org) {
GeoIP_delete(gcf->org);
} -
if (gcf->org_v6) {
-
GeoIP_delete(gcf->org_v6);
-
}
if (gcf->city) {
GeoIP_delete(gcf->city);
} -
if (gcf->city_v6) {
-
GeoIP_delete(gcf->city_v6);
-
}
}