Added optional source=<variable> setting to allow lookups on

IPs in custom variables.  Defaults to client ip if not set.
This commit is contained in:
Lee Valentine 2016-06-17 10:52:58 -07:00
parent 2f9ee969c8
commit 9d11f35986
2 changed files with 85 additions and 29 deletions

View file

@ -46,7 +46,7 @@ The free GeoLite2 databases are available from [Maxminds website](http://dev.max
http { http {
... ...
geoip2 /etc/maxmind-country.mmdb { geoip2 /etc/maxmind-country.mmdb {
$geoip2_data_country_code default=US country iso_code; $geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
$geoip2_data_country_name country names en; $geoip2_data_country_name country names en;
} }

View file

@ -13,25 +13,26 @@
typedef struct { typedef struct {
MMDB_s mmdb; MMDB_s mmdb;
MMDB_lookup_result_s result; MMDB_lookup_result_s result;
#if (NGX_HAVE_INET6) #if (NGX_HAVE_INET6)
uint8_t address[16]; uint8_t address[16];
#else #else
unsigned long address; unsigned long address;
#endif #endif
} ngx_http_geoip2_db_t; } ngx_http_geoip2_db_t;
typedef struct { typedef struct {
ngx_array_t *databases; ngx_array_t *databases;
ngx_array_t *proxies; ngx_array_t *proxies;
ngx_flag_t proxy_recursive; ngx_flag_t proxy_recursive;
} ngx_http_geoip2_conf_t; } ngx_http_geoip2_conf_t;
typedef struct { typedef struct {
ngx_http_geoip2_db_t *database; ngx_http_geoip2_db_t *database;
const char **lookup; const char **lookup;
ngx_str_t default_value; ngx_str_t default_value;
ngx_http_complex_value_t source;
} ngx_http_geoip2_ctx_t; } ngx_http_geoip2_ctx_t;
@ -129,6 +130,7 @@ ngx_http_geoip2_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
ngx_addr_t addr; ngx_addr_t addr;
ngx_array_t *xfwd; ngx_array_t *xfwd;
u_char *p; u_char *p;
ngx_str_t val;
#if (NGX_HAVE_INET6) #if (NGX_HAVE_INET6)
uint8_t address[16], *addressp = address; uint8_t address[16], *addressp = address;
@ -136,15 +138,25 @@ ngx_http_geoip2_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
unsigned long address; unsigned long address;
#endif #endif
gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module); if (geoip2->source.value.len > 0) {
addr.sockaddr = r->connection->sockaddr; if (ngx_http_complex_value(r, &geoip2->source, &val) != NGX_OK) {
addr.socklen = r->connection->socklen; goto not_found;
}
xfwd = &r->headers_in.x_forwarded_for; if (ngx_parse_addr(r->pool, &addr, val.data, val.len) != NGX_OK) {
goto not_found;
}
} else {
gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip2_module);
addr.sockaddr = r->connection->sockaddr;
addr.socklen = r->connection->socklen;
if (xfwd->nelts > 0 && gcf->proxies != NULL) { xfwd = &r->headers_in.x_forwarded_for;
(void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
gcf->proxies, gcf->proxy_recursive); if (xfwd->nelts > 0 && gcf->proxies != NULL) {
(void) ngx_http_get_forwarded_addr(r, &addr, xfwd, NULL,
gcf->proxies, gcf->proxy_recursive);
}
} }
switch (addr.sockaddr->sa_family) { switch (addr.sockaddr->sa_family) {
@ -352,12 +364,11 @@ ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char * static char *
ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
{ {
ngx_str_t *value, name; ngx_str_t *value, name, source;
ngx_http_geoip2_ctx_t *geoip2; ngx_http_geoip2_ctx_t *geoip2;
ngx_http_variable_t *var; ngx_http_variable_t *var;
int i, nelts, idx; int i, nelts, idx;
char *prefix = "default="; ngx_http_compile_complex_value_t ccv;
size_t prefix_len = sizeof("default=") - 1;
geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_ctx_t)); geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_ctx_t));
if (geoip2 == NULL) { if (geoip2 == NULL) {
@ -378,12 +389,57 @@ ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
nelts = (int) cf->args->nelts; nelts = (int) cf->args->nelts;
idx = 1; idx = 1;
geoip2->database = (ngx_http_geoip2_db_t *) conf; geoip2->database = (ngx_http_geoip2_db_t *) conf;
ngx_str_null(&source);
if (nelts > idx && value[idx].len >= prefix_len && if (nelts > idx) {
ngx_strncmp(value[idx].data, prefix, prefix_len) == 0) { for (i = idx; i < nelts; i++) {
geoip2->default_value.len = value[idx].len - prefix_len; if (ngx_strnstr(value[idx].data, "=", value[idx].len) == NULL) {
geoip2->default_value.data = value[idx].data + prefix_len; break;
idx++; }
if (value[idx].len > 8 && ngx_strncmp(value[idx].data, "default=", 8) == 0) {
if (geoip2->default_value.len > 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"default has already been declared for \"$%V\"", &name);
return NGX_CONF_ERROR;
}
geoip2->default_value.len = value[idx].len - 8;
geoip2->default_value.data = value[idx].data + 8;
} else if (value[idx].len > 7 && ngx_strncmp(value[idx].data, "source=", 7) == 0) {
if (source.len > 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"source has already been declared for \"$%V\"", &name);
return NGX_CONF_ERROR;
}
source.len = value[idx].len - 7;
source.data = value[idx].data + 7;
if (source.data[0] != '$') {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid source variable name \"%V\"", &source);
return NGX_CONF_ERROR;
}
ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &source;
ccv.complex_value = &geoip2->source;
if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"unable to compile \"%V\" for \"$%V\"", &source, &name);
return NGX_CONF_ERROR;
}
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid setting \"%V\" for \"$%V\"", &value[idx], &name);
return NGX_CONF_ERROR;
}
idx++;
}
} }
var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);