GeoIPv6 patch

Maxim Dounin mdounin at mdounin.ru
Sat Jun 11 16:54:18 MSD 2011


Hello!

On Sat, Jun 11, 2011 at 10:33:58AM +0200, Gregor Kališnik wrote:

> Hi.
> 
> I've created a patch for nginx GeoIP module to also use the GeoIP IPv6 
> version. The patch is attached.
> 
> Currently it runs on http://www.podnapisi.net and there are no appearant 
> problems.
> 
> Best regards,
> Gregor Kališnik

> diff -ru nginx-1.0.4/src/http/modules/ngx_http_geoip_module.c nginx-1.0.4-patched/src/http/modules/ngx_http_geoip_module.c
> --- nginx-1.0.4/src/http/modules/ngx_http_geoip_module.c	2011-05-16 15:50:58.000000000 +0200
> +++ nginx-1.0.4-patched/src/http/modules/ngx_http_geoip_module.c	2011-06-10 12:47:40.072799003 +0200
> @@ -11,7 +11,6 @@
>  #include <GeoIP.h>
>  #include <GeoIPCity.h>
>  
> -

Unrelated whitespace breakage.  There are multiple other style 
issues, too.

>  typedef struct {
>      GeoIP      *country;
>      GeoIP      *org;
> @@ -26,6 +25,49 @@
>  
>  
>  typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr);
> +typedef const char *(*ngx_http_geoip_variable_handler_v6_pt)(GeoIP *, geoipv6_t addr);
> +
> +/* Functions for IPv4 and IPv6 country or org lookup */
> +typedef struct {
> +    ngx_http_geoip_variable_handler_pt v4;
> +    ngx_http_geoip_variable_handler_v6_pt v6;
> +} ngx_http_geoip_lookup_function;
> +
> +ngx_http_geoip_lookup_function ngx_http_geoip_country_code_by_ipnum = {
> +    (ngx_http_geoip_variable_handler_pt) GeoIP_country_code_by_ipnum,
> +#if (NGX_HAVE_INET6)
> +    (ngx_http_geoip_variable_handler_v6_pt) GeoIP_country_code_by_ipnum_v6
> +#else
> +    (ngx_http_geoip_variable_handler_v6_pt) 0l
> +#endif
> +};
> +
> +ngx_http_geoip_lookup_function ngx_http_geoip_country_code3_by_ipnum = {
> +    (ngx_http_geoip_variable_handler_pt) GeoIP_country_code3_by_ipnum,
> +#if (NGX_HAVE_INET6)
> +    (ngx_http_geoip_variable_handler_v6_pt) GeoIP_country_code3_by_ipnum_v6
> +#else
> +    (ngx_http_geoip_variable_handler_v6_pt) 0l
> +#endif
> +};
> +
> +ngx_http_geoip_lookup_function ngx_http_geoip_country_name_by_ipnum = {
> +    (ngx_http_geoip_variable_handler_pt) GeoIP_country_name_by_ipnum,
> +#if (NGX_HAVE_INET6)
> +    (ngx_http_geoip_variable_handler_v6_pt) GeoIP_country_name_by_ipnum_v6
> +#else
> +    (ngx_http_geoip_variable_handler_v6_pt) 0l
> +#endif
> +};
> +
> +ngx_http_geoip_lookup_function ngx_http_geoip_name_by_ipnum = {
> +    (ngx_http_geoip_variable_handler_pt) GeoIP_name_by_ipnum,
> +#if (NGX_HAVE_INET6)
> +    (ngx_http_geoip_variable_handler_v6_pt) GeoIP_name_by_ipnum_v6
> +#else
> +    (ngx_http_geoip_variable_handler_v6_pt) 0l
> +#endif
> +};

I don't really like this aproach.  Result looks to cluttered with 
#if's and hard to read.  Probably it's good idea to try to produce 
something better.

>  static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
>      ngx_http_variable_value_t *v, uintptr_t data);
> @@ -114,19 +156,19 @@
>  
>      { ngx_string("geoip_country_code"), NULL,
>        ngx_http_geoip_country_variable,
> -      (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 },
> +      (uintptr_t) &ngx_http_geoip_country_code_by_ipnum, 0, 0 },
>  
>      { ngx_string("geoip_country_code3"), NULL,
>        ngx_http_geoip_country_variable,
> -      (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 },
> +      (uintptr_t) &ngx_http_geoip_country_code3_by_ipnum, 0, 0 },
>  
>      { ngx_string("geoip_country_name"), NULL,
>        ngx_http_geoip_country_variable,
> -      (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 },
> +      (uintptr_t) &ngx_http_geoip_country_name_by_ipnum, 0, 0 },
>  
>      { ngx_string("geoip_org"), NULL,
>        ngx_http_geoip_org_variable,
> -      (uintptr_t) GeoIP_name_by_ipnum, 0, 0 },
> +      (uintptr_t) &ngx_http_geoip_name_by_ipnum, 0, 0 },
>  
>      { ngx_string("geoip_city_continent_code"), NULL,
>        ngx_http_geoip_city_variable,
> @@ -217,13 +259,44 @@
>      return INADDR_NONE;
>  }
>  
> +#if (NGX_HAVE_INET6)
> +static geoipv6_t
> +ngx_http_geoip_addr_v6(ngx_http_request_t *r)
> +{
> +    struct sockaddr_in6  *sin;
> +    struct sockaddr_in   *sin4;
> +    struct in6_addr v6address;
> +    char temp[INET_ADDRSTRLEN];
> +    // 7B for ::FFFF: prefix
> +    char temp_mapped[7 + INET_ADDRSTRLEN];
> +
> +    switch (r->connection->sockaddr->sa_family) {
> +    
> +    case AF_INET:
> +        sin4 = (struct sockaddr_in *) r->connection->sockaddr;
> +        inet_ntop(AF_INET, &sin4->sin_addr, temp, INET_ADDRSTRLEN);
> +        sprintf(temp_mapped, "::FFFF:%s", temp);
> +        inet_pton(AF_INET6, temp_mapped, &v6address);

Using inet_ntop/sprintf/inet_pton to map ipv4 binary address to 
ipv4-mapped ipv6 binary address is cool.  :)

What about just setting appropriate bytes?

> +        
> +        return v6address;
> +
> +    case AF_INET6:
> +        sin = (struct sockaddr_in6 *) r->connection->sockaddr;
> +
> +        return sin->sin6_addr;
> +
> +    }
> +    
> +    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_lookup_function *handler =
> +        (ngx_http_geoip_lookup_function*) data;
>  
>      const char             *val;
>      ngx_http_geoip_conf_t  *gcf;
> @@ -234,7 +307,12 @@
>          goto not_found;
>      }
>  
> -    val = handler(gcf->country, ngx_http_geoip_addr(r));
> +#if (NGX_HAVE_INET6)
> +    if (gcf->country->databaseType == GEOIP_COUNTRY_EDITION_V6)
> +      val = handler->v6(gcf->country, ngx_http_geoip_addr_v6(r));
> +    else
> +#endif
> +      val = handler->v4(gcf->country, ngx_http_geoip_addr(r));
>  
>      if (val == NULL) {
>          goto not_found;
> @@ -260,8 +338,8 @@
>  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;
> +    ngx_http_geoip_lookup_function *handler =
> +        (ngx_http_geoip_lookup_function*) data;
>  
>      const char             *val;
>      ngx_http_geoip_conf_t  *gcf;
> @@ -272,7 +350,15 @@
>          goto not_found;
>      }
>  
> -    val = handler(gcf->org, ngx_http_geoip_addr(r));
> +#if (NGX_HAVE_INET6)
> +    if (gcf->org->databaseType == GEOIP_ISP_EDITION_V6 ||
> +        gcf->org->databaseType == GEOIP_ORG_EDITION_V6 ||
> +        gcf->org->databaseType == GEOIP_DOMAIN_EDITION_V6 ||
> +        gcf->org->databaseType == GEOIP_ASNUM_EDITION_V6)
> +      val = handler->v6(gcf->org, ngx_http_geoip_addr_v6(r));
> +    else
> +#endif
> +      val = handler->v4(gcf->org, ngx_http_geoip_addr(r));

It's probably good idea to centralize all these checks at 
configuration stage.

Please also note that nginx style is to use 4 spaces for 
indentation, and always use {}.

>  
>      if (val == NULL) {
>          goto not_found;
> @@ -452,7 +538,13 @@
>      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));
> +#if (NGX_HAVE_INET6)
> +        if (gcf->city->databaseType == GEOIP_CITY_EDITION_REV0_V6 ||
> +            gcf->city->databaseType == GEOIP_CITY_EDITION_REV1_V6)
> +          return GeoIP_record_by_ipnum_v6(gcf->city, ngx_http_geoip_addr_v6(r));
> +        else
> +#endif
> +          return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r));
>      }
>  
>      return NULL;
> @@ -539,6 +631,9 @@
>      case GEOIP_COUNTRY_EDITION:
>      case GEOIP_PROXY_EDITION:
>      case GEOIP_NETSPEED_EDITION:
> +#if (NGX_HAVE_INET6)
> +    case GEOIP_COUNTRY_EDITION_V6:
> +#endif
>  
>          return NGX_CONF_OK;
>  
> @@ -590,6 +685,12 @@
>      case GEOIP_ORG_EDITION:
>      case GEOIP_DOMAIN_EDITION:
>      case GEOIP_ASNUM_EDITION:
> +#if (NGX_HAVE_INET6)
> +    case GEOIP_ISP_EDITION_V6:
> +    case GEOIP_ORG_EDITION_V6:
> +    case GEOIP_DOMAIN_EDITION_V6:
> +    case GEOIP_ASNUM_EDITION_V6:
> +#endif
>  
>          return NGX_CONF_OK;
>  
> @@ -639,6 +740,10 @@
>  
>      case GEOIP_CITY_EDITION_REV0:
>      case GEOIP_CITY_EDITION_REV1:
> +#if (NGX_HAVE_INET6)
> +    case GEOIP_CITY_EDITION_REV0_V6:
> +    case GEOIP_CITY_EDITION_REV1_V6:
> +#endif
>  
>          return NGX_CONF_OK;
>  
> Only in nginx-1.0.4-patched/src/http/modules: ngx_http_geoip_module.c~

Some configure checks for ipv6 support in libgeoip may also be 
needed as I have no idea if recent libgeoip versions are widely 
availabe on some known-to-be-slow Linux'es.  Not sure, but it at 
least deserves some investigation.

Maxim Dounin



More information about the nginx-devel mailing list