Mercurial > hg > nginx-vendor-current
diff src/http/modules/ngx_http_geoip_module.c @ 626:a7a5fa2e395b NGINX_1_0_3
nginx 1.0.3
*) Feature: the "auth_basic_user_file" directive supports "$apr1",
"{PLAIN}", and "{SSHA}" password encryption methods.
Thanks to Maxim Dounin.
*) Feature: the "geoip_org" directive and $geoip_org variable.
Thanks to Alexander Uskov, Arnaud Granal, and Denis F. Latypoff.
*) Feature: ngx_http_geo_module and ngx_http_geoip_module support IPv4
addresses mapped to IPv6 addresses.
*) Bugfix: a segmentation fault occurred in a worker process during
testing IPv4 address mapped to IPv6 address, if access or deny rules
were defined only for IPv6; the bug had appeared in 0.8.22.
*) Bugfix: a cached reponse may be broken if proxy/fastcgi/scgi/
uwsgi_cache_bypass and proxy/fastcgi/scgi/uwsgi_no_cache directive
values were different; the bug had appeared in 0.8.46.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Wed, 25 May 2011 00:00:00 +0400 |
parents | bb20316269e4 |
children | d0f7a625f27c |
line wrap: on
line diff
--- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -14,6 +14,7 @@ typedef struct { GeoIP *country; + GeoIP *org; GeoIP *city; } ngx_http_geoip_conf_t; @@ -28,6 +29,8 @@ typedef const char *(*ngx_http_geoip_var 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, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_geoip_region_name_variable(ngx_http_request_t *r, @@ -42,6 +45,8 @@ static ngx_int_t ngx_http_geoip_add_vari static void *ngx_http_geoip_create_conf(ngx_conf_t *cf); static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_http_geoip_cleanup(void *data); @@ -56,6 +61,13 @@ static ngx_command_t ngx_http_geoip_com 0, NULL }, + { ngx_string("geoip_org"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12, + ngx_http_geoip_org, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + { ngx_string("geoip_city"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12, ngx_http_geoip_city, @@ -112,6 +124,10 @@ static ngx_http_variable_t ngx_http_geo ngx_http_geoip_country_variable, (uintptr_t) 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 }, + { ngx_string("geoip_city_continent_code"), NULL, ngx_http_geoip_city_variable, offsetof(GeoIPRecord, continent_code), 0, 0 }, @@ -164,6 +180,44 @@ static ngx_http_variable_t ngx_http_geo }; +static u_long +ngx_http_geoip_addr(ngx_http_request_t *r) +{ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + u_char *p; + u_long addr; + struct sockaddr_in6 *sin6; +#endif + + switch (r->connection->sockaddr->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) r->connection->sockaddr; + return ntohl(sin->sin_addr.s_addr); + +#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; + } + +#endif + } + + return INADDR_NONE; +} + + static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -171,9 +225,7 @@ ngx_http_geoip_country_variable(ngx_http ngx_http_geoip_variable_handler_pt handler = (ngx_http_geoip_variable_handler_pt) data; - u_long addr; const char *val; - struct sockaddr_in *sin; ngx_http_geoip_conf_t *gcf; gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); @@ -182,14 +234,45 @@ ngx_http_geoip_country_variable(ngx_http goto not_found; } - if (r->connection->sockaddr->sa_family != AF_INET) { + val = handler(gcf->country, ngx_http_geoip_addr(r)); + + if (val == NULL) { goto not_found; } - sin = (struct sockaddr_in *) r->connection->sockaddr; - addr = ntohl(sin->sin_addr.s_addr); + v->len = ngx_strlen(val); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) val; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + - val = handler(gcf->country, addr); +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; + + 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; + } + + val = handler(gcf->org, ngx_http_geoip_addr(r)); if (val == NULL) { goto not_found; @@ -364,18 +447,12 @@ ngx_http_geoip_city_int_variable(ngx_htt static GeoIPRecord * ngx_http_geoip_get_city_record(ngx_http_request_t *r) { - u_long addr; - struct sockaddr_in *sin; ngx_http_geoip_conf_t *gcf; gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); - if (gcf->city && r->connection->sockaddr->sa_family == AF_INET) { - - sin = (struct sockaddr_in *) r->connection->sockaddr; - addr = ntohl(sin->sin_addr.s_addr); - - return GeoIP_record_by_ipnum(gcf->city, addr); + if (gcf->city) { + return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r)); } return NULL; @@ -441,7 +518,7 @@ ngx_http_geoip_country(ngx_conf_t *cf, n if (gcf->country == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "GeoIO_open(\"%V\") failed", &value[1]); + "GeoIP_open(\"%V\") failed", &value[1]); return NGX_CONF_ERROR; } @@ -475,6 +552,57 @@ ngx_http_geoip_country(ngx_conf_t *cf, n static char * +ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->org) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->org == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset (gcf->org, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->org->databaseType) { + + case GEOIP_ISP_EDITION: + case GEOIP_ORG_EDITION: + case GEOIP_DOMAIN_EDITION: + case GEOIP_ASNUM_EDITION: + + return NGX_CONF_OK; + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->org->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_geoip_conf_t *gcf = conf; @@ -491,7 +619,7 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_ if (gcf->city == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "GeoIO_open(\"%V\") failed", &value[1]); + "GeoIP_open(\"%V\") failed", &value[1]); return NGX_CONF_ERROR; } @@ -532,6 +660,10 @@ ngx_http_geoip_cleanup(void *data) GeoIP_delete(gcf->country); } + if (gcf->org) { + GeoIP_delete(gcf->org); + } + if (gcf->city) { GeoIP_delete(gcf->city); }