mirror of
https://github.com/nginx/nginx.git
synced 2024-12-31 19:27:43 -06:00
geoip: trusted proxies support and partial IPv6 support.
The module now supports recursive search of client address through the chain of trusted proxies (closes #100), in the same scope as the geo module. Proxies are listed by the "geoip_proxy" directive, recursive search is enabled by the "geoip_proxy_recursive" directive. IPv6 is partially supported: proxies may be specified with IPv6 addresses. Example: geoip_country .../GeoIP.dat; geoip_proxy 127.0.0.1; geoip_proxy ::1; geoip_proxy 10.0.0.0/8; geoip_proxy_recursive on;
This commit is contained in:
parent
69521ddebf
commit
d4ba06c31a
@ -14,20 +14,24 @@
|
||||
|
||||
|
||||
typedef struct {
|
||||
GeoIP *country;
|
||||
GeoIP *org;
|
||||
GeoIP *city;
|
||||
GeoIP *country;
|
||||
GeoIP *org;
|
||||
GeoIP *city;
|
||||
ngx_array_t *proxies; /* array of ngx_cidr_t */
|
||||
ngx_flag_t proxy_recursive;
|
||||
} ngx_http_geoip_conf_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t *name;
|
||||
uintptr_t data;
|
||||
ngx_str_t *name;
|
||||
uintptr_t data;
|
||||
} ngx_http_geoip_var_t;
|
||||
|
||||
|
||||
typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr);
|
||||
|
||||
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,
|
||||
@ -44,12 +48,17 @@ static GeoIPRecord *ngx_http_geoip_get_city_record(ngx_http_request_t *r);
|
||||
|
||||
static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
|
||||
static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
|
||||
static char *ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf);
|
||||
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 char *ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static ngx_int_t ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
|
||||
ngx_cidr_t *cidr);
|
||||
static void ngx_http_geoip_cleanup(void *data);
|
||||
|
||||
|
||||
@ -76,6 +85,20 @@ static ngx_command_t ngx_http_geoip_commands[] = {
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("geoip_proxy"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
|
||||
ngx_http_geoip_proxy,
|
||||
NGX_HTTP_MAIN_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("geoip_proxy_recursive"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_CONF_FLAG,
|
||||
ngx_conf_set_flag_slot,
|
||||
NGX_HTTP_MAIN_CONF_OFFSET,
|
||||
offsetof(ngx_http_geoip_conf_t, proxy_recursive),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
@ -85,7 +108,7 @@ static ngx_http_module_t ngx_http_geoip_module_ctx = {
|
||||
NULL, /* postconfiguration */
|
||||
|
||||
ngx_http_geoip_create_conf, /* create main configuration */
|
||||
NULL, /* init main configuration */
|
||||
ngx_http_geoip_init_conf, /* init main configuration */
|
||||
|
||||
NULL, /* create server configuration */
|
||||
NULL, /* merge server configuration */
|
||||
@ -182,40 +205,44 @@ static ngx_http_variable_t ngx_http_geoip_vars[] = {
|
||||
|
||||
|
||||
static u_long
|
||||
ngx_http_geoip_addr(ngx_http_request_t *r)
|
||||
ngx_http_geoip_addr(ngx_http_request_t *r, ngx_http_geoip_conf_t *gcf)
|
||||
{
|
||||
struct sockaddr_in *sin;
|
||||
#if (NGX_HAVE_INET6)
|
||||
u_char *p;
|
||||
u_long addr;
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif
|
||||
ngx_addr_t addr;
|
||||
ngx_table_elt_t *xfwd;
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
switch (r->connection->sockaddr->sa_family) {
|
||||
addr.sockaddr = r->connection->sockaddr;
|
||||
addr.socklen = r->connection->socklen;
|
||||
/* addr.name = r->connection->addr_text; */
|
||||
|
||||
case AF_INET:
|
||||
sin = (struct sockaddr_in *) r->connection->sockaddr;
|
||||
return ntohl(sin->sin_addr.s_addr);
|
||||
xfwd = r->headers_in.x_forwarded_for;
|
||||
|
||||
#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
|
||||
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);
|
||||
}
|
||||
|
||||
return INADDR_NONE;
|
||||
#if (NGX_HAVE_INET6)
|
||||
|
||||
if (addr.sockaddr->sa_family == AF_INET6) {
|
||||
struct in6_addr *inaddr6;
|
||||
|
||||
inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
|
||||
|
||||
if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
|
||||
return ntohl(*(in_addr_t *) &inaddr6->s6_addr[12]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (addr.sockaddr->sa_family != AF_INET) {
|
||||
return INADDR_NONE;
|
||||
}
|
||||
|
||||
sin = (struct sockaddr_in *) addr.sockaddr;
|
||||
return ntohl(sin->sin_addr.s_addr);
|
||||
}
|
||||
|
||||
|
||||
@ -235,7 +262,7 @@ ngx_http_geoip_country_variable(ngx_http_request_t *r,
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
val = handler(gcf->country, ngx_http_geoip_addr(r));
|
||||
val = handler(gcf->country, ngx_http_geoip_addr(r, gcf));
|
||||
|
||||
if (val == NULL) {
|
||||
goto not_found;
|
||||
@ -273,7 +300,7 @@ ngx_http_geoip_org_variable(ngx_http_request_t *r,
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
val = handler(gcf->org, ngx_http_geoip_addr(r));
|
||||
val = handler(gcf->org, ngx_http_geoip_addr(r, gcf));
|
||||
|
||||
if (val == NULL) {
|
||||
goto not_found;
|
||||
@ -453,7 +480,7 @@ 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) {
|
||||
return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r));
|
||||
return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r, gcf));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -490,6 +517,8 @@ ngx_http_geoip_create_conf(ngx_conf_t *cf)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conf->proxy_recursive = NGX_CONF_UNSET;
|
||||
|
||||
cln = ngx_pool_cleanup_add(cf->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NULL;
|
||||
@ -502,6 +531,17 @@ ngx_http_geoip_create_conf(ngx_conf_t *cf)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_geoip_init_conf(ngx_conf_t *cf, void *conf)
|
||||
{
|
||||
ngx_http_geoip_conf_t *gcf = conf;
|
||||
|
||||
ngx_conf_init_value(gcf->proxy_recursive, 0);
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
@ -652,6 +692,66 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_geoip_proxy(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_geoip_conf_t *gcf = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
ngx_cidr_t cidr, *c;
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
if (ngx_http_geoip_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (gcf->proxies == NULL) {
|
||||
gcf->proxies = ngx_array_create(cf->pool, 4, sizeof(ngx_cidr_t));
|
||||
if (gcf->proxies == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
c = ngx_array_push(gcf->proxies);
|
||||
if (c == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
*c = cidr;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_geoip_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
|
||||
cidr->family = AF_INET;
|
||||
cidr->u.in.addr = 0xffffffff;
|
||||
cidr->u.in.mask = 0xffffffff;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
rc = ngx_ptocidr(net, cidr);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"low address bits of %V are meaningless", net);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_geoip_cleanup(void *data)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user