Welcome! Log In Create A New Profile

Advanced

[PATCH] Add IPv6 support to GeoIP module

Bruno Prémont
October 04, 2011 03:24AM
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(r));
+ 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(r));
+ 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(r));
+ 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] << 8) + 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);
+ }
}

_______________________________________________
nginx mailing list
nginx@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx
Subject Author Posted

[PATCH] Add IPv6 support to GeoIP module

Bruno Prémont October 04, 2011 03:24AM

Re: [PATCH] Add IPv6 support to GeoIP module

Maxim Dounin October 05, 2011 07:06AM

Re: [PATCH] Add IPv6 support to GeoIP module

csg October 05, 2011 07:26AM

Re: [PATCH] Add IPv6 support to GeoIP module

MasterMind2k October 05, 2011 07:32AM

Re: [PATCH] Add IPv6 support to GeoIP module

Bruno Prémont October 05, 2011 07:58AM

Re: [PATCH] Add IPv6 support to GeoIP module

Maxim Dounin October 05, 2011 08:54AM

Re: [PATCH] Add IPv6 support to GeoIP module

Bruno Prémont April 13, 2012 04:14AM

Re: [PATCH] Add IPv6 support to GeoIP module

Maxim Dounin April 13, 2012 06:48AM

Re: [PATCH] Add IPv6 support to GeoIP module

MasterMind2k April 13, 2012 06:56AM



Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 169
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready