3
* Copyright (C) Igor Sysoev
7
#include <ngx_config.h>
12
#include <GeoIPCity.h>
18
} ngx_http_geoip_conf_t;
24
} ngx_http_geoip_var_t;
27
typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr);
29
static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
30
ngx_http_variable_value_t *v, uintptr_t data);
31
static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r,
32
ngx_http_variable_value_t *v, uintptr_t data);
34
static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
35
static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
36
static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
38
static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
40
static void ngx_http_geoip_cleanup(void *data);
43
static ngx_command_t ngx_http_geoip_commands[] = {
45
{ ngx_string("geoip_country"),
46
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
47
ngx_http_geoip_country,
48
NGX_HTTP_MAIN_CONF_OFFSET,
52
{ ngx_string("geoip_city"),
53
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
55
NGX_HTTP_MAIN_CONF_OFFSET,
63
static ngx_http_module_t ngx_http_geoip_module_ctx = {
64
ngx_http_geoip_add_variables, /* preconfiguration */
65
NULL, /* postconfiguration */
67
ngx_http_geoip_create_conf, /* create main configuration */
68
NULL, /* init main configuration */
70
NULL, /* create server configuration */
71
NULL, /* merge server configuration */
73
NULL, /* create location configuration */
74
NULL /* merge location configuration */
78
ngx_module_t ngx_http_geoip_module = {
80
&ngx_http_geoip_module_ctx, /* module context */
81
ngx_http_geoip_commands, /* module directives */
82
NGX_HTTP_MODULE, /* module type */
83
NULL, /* init master */
84
NULL, /* init module */
85
NULL, /* init process */
86
NULL, /* init thread */
87
NULL, /* exit thread */
88
NULL, /* exit process */
89
NULL, /* exit master */
94
static ngx_http_variable_t ngx_http_geoip_vars[] = {
96
{ ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable,
97
(uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 },
99
{ ngx_string("geoip_country_code3"), NULL, ngx_http_geoip_country_variable,
100
(uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 },
102
{ ngx_string("geoip_country_name"), NULL, ngx_http_geoip_country_variable,
103
(uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 },
105
{ ngx_string("geoip_city_country_code"), NULL, ngx_http_geoip_city_variable,
106
offsetof(GeoIPRecord, country_code), 0, 0 },
108
{ ngx_string("geoip_city_country_code3"), NULL,
109
ngx_http_geoip_city_variable,
110
offsetof(GeoIPRecord, country_code3), 0, 0 },
112
{ ngx_string("geoip_city_country_name"), NULL, ngx_http_geoip_city_variable,
113
offsetof(GeoIPRecord, country_name), 0, 0 },
115
{ ngx_string("geoip_region"), NULL,
116
ngx_http_geoip_city_variable,
117
offsetof(GeoIPRecord, region), 0, 0 },
119
{ ngx_string("geoip_city"), NULL,
120
ngx_http_geoip_city_variable,
121
offsetof(GeoIPRecord, city), 0, 0 },
123
{ ngx_string("geoip_postal_code"), NULL,
124
ngx_http_geoip_city_variable,
125
offsetof(GeoIPRecord, postal_code), 0, 0 },
127
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
132
ngx_http_geoip_country_variable(ngx_http_request_t *r,
133
ngx_http_variable_value_t *v, uintptr_t data)
135
ngx_http_geoip_variable_handler_pt handler =
136
(ngx_http_geoip_variable_handler_pt) data;
140
struct sockaddr_in *sin;
141
ngx_http_geoip_conf_t *gcf;
143
gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
145
if (gcf->country == NULL) {
149
if (r->connection->sockaddr->sa_family != AF_INET) {
153
sin = (struct sockaddr_in *) r->connection->sockaddr;
154
addr = ntohl(sin->sin_addr.s_addr);
156
val = handler(gcf->country, addr);
162
v->len = ngx_strlen(val);
166
v->data = (u_char *) val;
179
ngx_http_geoip_city_variable(ngx_http_request_t *r,
180
ngx_http_variable_value_t *v, uintptr_t data)
186
struct sockaddr_in *sin;
187
ngx_http_geoip_conf_t *gcf;
189
gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
191
if (gcf->city == NULL) {
195
if (r->connection->sockaddr->sa_family != AF_INET) {
199
sin = (struct sockaddr_in *) r->connection->sockaddr;
200
addr = ntohl(sin->sin_addr.s_addr);
202
gr = GeoIP_record_by_ipnum(gcf->city, addr);
208
val = *(char **) ((char *) gr + data);
214
len = ngx_strlen(val);
215
v->data = ngx_pnalloc(r->pool, len);
217
if (v->data == NULL) {
218
GeoIPRecord_delete(gr);
222
ngx_memcpy(v->data, val, len);
229
GeoIPRecord_delete(gr);
235
GeoIPRecord_delete(gr);
246
ngx_http_geoip_add_variables(ngx_conf_t *cf)
248
ngx_http_variable_t *var, *v;
250
for (v = ngx_http_geoip_vars; v->name.len; v++) {
251
var = ngx_http_add_variable(cf, &v->name, v->flags);
256
var->get_handler = v->get_handler;
265
ngx_http_geoip_create_conf(ngx_conf_t *cf)
267
ngx_pool_cleanup_t *cln;
268
ngx_http_geoip_conf_t *conf;
270
conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
275
cln = ngx_pool_cleanup_add(cf->pool, 0);
280
cln->handler = ngx_http_geoip_cleanup;
288
ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
290
ngx_http_geoip_conf_t *gcf = conf;
295
return "is duplicate";
298
value = cf->args->elts;
300
gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
302
if (gcf->country == NULL) {
303
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
304
"GeoIO_open(\"%V\") failed", &value[1]);
306
return NGX_CONF_ERROR;
309
switch (gcf->country->databaseType) {
311
case GEOIP_COUNTRY_EDITION:
312
case GEOIP_PROXY_EDITION:
313
case GEOIP_NETSPEED_EDITION:
318
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
319
"invalid GeoIP database \"%V\" type:%d",
320
&value[1], gcf->country->databaseType);
321
return NGX_CONF_ERROR;
327
ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
329
ngx_http_geoip_conf_t *gcf = conf;
334
return "is duplicate";
337
value = cf->args->elts;
339
gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
341
if (gcf->city == NULL) {
342
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
343
"GeoIO_open(\"%V\") failed", &value[1]);
345
return NGX_CONF_ERROR;
348
switch (gcf->city->databaseType) {
350
case GEOIP_CITY_EDITION_REV0:
351
case GEOIP_CITY_EDITION_REV1:
356
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
357
"invalid GeoIP City database \"%V\" type:%d",
358
&value[1], gcf->city->databaseType);
359
return NGX_CONF_ERROR;
365
ngx_http_geoip_cleanup(void *data)
367
ngx_http_geoip_conf_t *gcf = data;
370
GeoIP_delete(gcf->country);
374
GeoIP_delete(gcf->city);