Skip to content

Commit 7eaa956

Browse files
authored
Merge pull request #53 from leev/metadata
Add support for retrieving mmdb metadata, specifically build_epoch
2 parents f4364b5 + 4674ba7 commit 7eaa956

File tree

3 files changed

+231
-37
lines changed

3 files changed

+231
-37
lines changed

README.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ load_module modules/ngx_http_geoip2_module.so;
3333
##### To build as a static module:
3434
```
3535
./configure --add-module=/path/to/ngx_http_geoip2_module
36-
make
36+
make
3737
make install
3838
```
3939

@@ -48,6 +48,7 @@ The free GeoLite2 databases are available from [Maxminds website](http://dev.max
4848
http {
4949
...
5050
geoip2 /etc/maxmind-country.mmdb {
51+
$geoip2_metadata_country_build metadata build_epoch;
5152
$geoip2_data_country_code default=US source=$variable_with_ip country iso_code;
5253
$geoip2_data_country_name country names en;
5354
}
@@ -72,23 +73,38 @@ stream {
7273
}
7374
```
7475

75-
To find the path of the data you want (eg: city names en), use the [mmdblookup tool](https://maxmind.github.io/libmaxminddb/mmdblookup.html):
76+
##### Metadata:
77+
Retrieve metadata regarding the geoip database.
78+
```
79+
$variable_name metadata <field>
80+
```
81+
Currently the only metadata field supported is build_epoch.
82+
83+
##### GeoIP:
84+
```
85+
$variable_name [default=<value] [source=$variable_with_ip] path ...
86+
```
87+
If default is not specified, the variable will be empty if not found.
88+
89+
If source is not specified, $remote_addr will be used to perform the lookup.
90+
91+
To find the path of the data you want (eg: country names en), use the [mmdblookup tool](https://maxmind.github.io/libmaxminddb/mmdblookup.html):
7692

7793
```
7894
$ mmdblookup --file /usr/share/GeoIP/GeoIP2-Country.mmdb --ip 8.8.8.8
7995
8096
{
81-
"country":
97+
"country":
8298
{
83-
"geoname_id":
99+
"geoname_id":
84100
6252001 <uint32>
85-
"iso_code":
101+
"iso_code":
86102
"US" <utf8_string>
87-
"names":
103+
"names":
88104
{
89-
"de":
105+
"de":
90106
"USA" <utf8_string>
91-
"en":
107+
"en":
92108
"United States" <utf8_string>
93109
}
94110
}
@@ -98,3 +114,9 @@ $ mmdblookup --file /usr/share/GeoIP/GeoIP2-Country.mmdb --ip 8.8.8.8 country na
98114
99115
"United States" <utf8_string>
100116
```
117+
118+
This translates to:
119+
120+
```
121+
$country_name "default=United States" source=$remote_addr country names en
122+
```

ngx_http_geoip2_module.c

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,26 @@ typedef struct {
3535
ngx_http_complex_value_t source;
3636
} ngx_http_geoip2_ctx_t;
3737

38+
typedef struct {
39+
ngx_http_geoip2_db_t *database;
40+
ngx_str_t metavalue;
41+
} ngx_http_geoip2_metadata_t;
42+
3843

3944
static ngx_int_t ngx_http_geoip2_variable(ngx_http_request_t *r,
4045
ngx_http_variable_value_t *v, uintptr_t data);
46+
static ngx_int_t ngx_http_geoip2_metadata(ngx_http_request_t *r,
47+
ngx_http_variable_value_t *v, uintptr_t data);
4148
static void *ngx_http_geoip2_create_conf(ngx_conf_t *cf);
4249
static char *ngx_http_geoip2_init_conf(ngx_conf_t *cf, void *conf);
4350
static char *ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd,
4451
void *conf);
4552
static char *ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy,
4653
void *conf);
54+
static char *ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf,
55+
ngx_http_geoip2_db_t *database);
56+
static char *ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf,
57+
ngx_http_geoip2_db_t *database);
4758
static char *ngx_http_geoip2_proxy(ngx_conf_t *cf, ngx_command_t *cmd,
4859
void *conf);
4960
static ngx_int_t ngx_http_geoip2_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
@@ -275,6 +286,29 @@ ngx_http_geoip2_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
275286
}
276287

277288

289+
static ngx_int_t
290+
ngx_http_geoip2_metadata(ngx_http_request_t *r, ngx_http_variable_value_t *v,
291+
uintptr_t data)
292+
{
293+
ngx_http_geoip2_metadata_t *metadata = (ngx_http_geoip2_metadata_t *) data;
294+
ngx_http_geoip2_db_t *database = metadata->database;
295+
u_char *p;
296+
297+
if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) {
298+
FORMAT("%uL", database->mmdb.metadata.build_epoch);
299+
} else {
300+
v->not_found = 1;
301+
return NGX_OK;
302+
}
303+
304+
v->valid = 1;
305+
v->no_cacheable = 0;
306+
v->not_found = 0;
307+
308+
return NGX_OK;
309+
}
310+
311+
278312
static void *
279313
ngx_http_geoip2_create_conf(ngx_conf_t *cf)
280314
{
@@ -370,32 +404,84 @@ ngx_http_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
370404
static char *
371405
ngx_http_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
372406
{
373-
ngx_str_t *value, name, source;
374-
ngx_http_geoip2_ctx_t *geoip2;
375-
ngx_http_variable_t *var;
376-
int i, nelts, idx;
377-
ngx_http_compile_complex_value_t ccv;
407+
ngx_http_geoip2_db_t *database;
408+
ngx_str_t *value;
409+
int nelts;
378410

379-
geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_ctx_t));
380-
if (geoip2 == NULL) {
411+
value = cf->args->elts;
412+
413+
if (value[0].data[0] != '$') {
414+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
415+
"invalid variable name \"%V\"", &value[0]);
416+
return NGX_CONF_ERROR;
417+
}
418+
419+
value[0].len--;
420+
value[0].data++;
421+
422+
nelts = (int) cf->args->nelts;
423+
database = (ngx_http_geoip2_db_t *) conf;
424+
425+
if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) {
426+
return ngx_http_geoip2_add_variable_metadata(cf, database);
427+
}
428+
429+
return ngx_http_geoip2_add_variable_geodata(cf, database);
430+
}
431+
432+
433+
static char *
434+
ngx_http_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database)
435+
{
436+
ngx_http_geoip2_metadata_t *metadata;
437+
ngx_str_t *value, name;
438+
ngx_http_variable_t *var;
439+
440+
metadata = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_metadata_t));
441+
if (metadata == NULL) {
381442
return NGX_CONF_ERROR;
382443
}
383444

384445
value = cf->args->elts;
385446
name = value[0];
386447

387-
if (name.data[0] != '$') {
388-
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
389-
"invalid variable name \"%V\"", &name);
448+
metadata->database = database;
449+
metadata->metavalue = value[2];
450+
451+
var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
452+
if (var == NULL) {
390453
return NGX_CONF_ERROR;
391454
}
392455

393-
name.len--;
394-
name.data++;
456+
var->get_handler = ngx_http_geoip2_metadata;
457+
var->data = (uintptr_t) metadata;
458+
459+
return NGX_CONF_OK;
460+
}
461+
462+
463+
static char *
464+
ngx_http_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_http_geoip2_db_t *database)
465+
{
466+
ngx_http_geoip2_ctx_t *geoip2;
467+
ngx_http_compile_complex_value_t ccv;
468+
ngx_str_t *value, name, source;
469+
ngx_http_variable_t *var;
470+
int i, nelts, idx;
471+
472+
geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip2_ctx_t));
473+
if (geoip2 == NULL) {
474+
return NGX_CONF_ERROR;
475+
}
476+
477+
geoip2->database = database;
478+
ngx_str_null(&source);
479+
480+
value = cf->args->elts;
481+
name = value[0];
482+
395483
nelts = (int) cf->args->nelts;
396484
idx = 1;
397-
geoip2->database = (ngx_http_geoip2_db_t *) conf;
398-
ngx_str_null(&source);
399485

400486
if (nelts > idx) {
401487
for (i = idx; i < nelts; i++) {

ngx_stream_geoip2_module.c

Lines changed: 101 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,25 @@ typedef struct {
3434
ngx_stream_complex_value_t source;
3535
} ngx_stream_geoip2_ctx_t;
3636

37+
typedef struct {
38+
ngx_stream_geoip2_db_t *database;
39+
ngx_str_t metavalue;
40+
} ngx_stream_geoip2_metadata_t;
41+
3742

3843
static ngx_int_t ngx_stream_geoip2_variable(ngx_stream_session_t *s,
3944
ngx_stream_variable_value_t *v, uintptr_t data);
45+
static ngx_int_t ngx_stream_geoip2_metadata(ngx_stream_session_t *s,
46+
ngx_stream_variable_value_t *v, uintptr_t data);
4047
static void *ngx_stream_geoip2_create_conf(ngx_conf_t *cf);
4148
static char *ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd,
4249
void *conf);
4350
static char *ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy,
4451
void *conf);
52+
static char *ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf,
53+
ngx_stream_geoip2_db_t *database);
54+
static char *ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf,
55+
ngx_stream_geoip2_db_t *database);
4556
static void ngx_stream_geoip2_cleanup(void *data);
4657

4758

@@ -244,6 +255,29 @@ ngx_stream_geoip2_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t
244255
}
245256

246257

258+
static ngx_int_t
259+
ngx_stream_geoip2_metadata(ngx_stream_session_t *s, ngx_stream_variable_value_t *v,
260+
uintptr_t data)
261+
{
262+
ngx_stream_geoip2_metadata_t *metadata = (ngx_stream_geoip2_metadata_t *) data;
263+
ngx_stream_geoip2_db_t *database = metadata->database;
264+
u_char *p;
265+
266+
if (ngx_strncmp(metadata->metavalue.data, "build_epoch", 11) == 0) {
267+
FORMAT("%uL", database->mmdb.metadata.build_epoch);
268+
} else {
269+
v->not_found = 1;
270+
return NGX_OK;
271+
}
272+
273+
v->valid = 1;
274+
v->no_cacheable = 0;
275+
v->not_found = 0;
276+
277+
return NGX_OK;
278+
}
279+
280+
247281
static void *
248282
ngx_stream_geoip2_create_conf(ngx_conf_t *cf)
249283
{
@@ -270,10 +304,10 @@ ngx_stream_geoip2_create_conf(ngx_conf_t *cf)
270304
static char *
271305
ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
272306
{
273-
int status, nelts, i;
307+
int status, nelts, i;
274308
char *rv;
275309
ngx_str_t *value;
276-
ngx_conf_t save;
310+
ngx_conf_t save;
277311
ngx_stream_geoip2_db_t *database;
278312
ngx_stream_geoip2_conf_t *gcf = conf;
279313

@@ -337,32 +371,84 @@ ngx_stream_geoip2(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
337371
static char *
338372
ngx_stream_geoip2_add_variable(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
339373
{
340-
int i, nelts, idx;
374+
ngx_stream_geoip2_db_t *database;
375+
ngx_str_t *value;
376+
int nelts;
377+
378+
value = cf->args->elts;
379+
380+
if (value[0].data[0] != '$') {
381+
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
382+
"invalid variable name \"%V\"", &value[0]);
383+
return NGX_CONF_ERROR;
384+
}
385+
386+
value[0].len--;
387+
value[0].data++;
388+
389+
nelts = (int) cf->args->nelts;
390+
database = (ngx_stream_geoip2_db_t *) conf;
391+
392+
if (nelts > 0 && value[1].len == 8 && ngx_strncmp(value[1].data, "metadata", 8) == 0) {
393+
return ngx_stream_geoip2_add_variable_metadata(cf, database);
394+
}
395+
396+
return ngx_stream_geoip2_add_variable_geodata(cf, database);
397+
}
398+
399+
400+
static char *
401+
ngx_stream_geoip2_add_variable_metadata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database)
402+
{
403+
ngx_stream_geoip2_metadata_t *metadata;
404+
ngx_str_t *value, name;
405+
ngx_stream_variable_t *var;
406+
407+
metadata = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_metadata_t));
408+
if (metadata == NULL) {
409+
return NGX_CONF_ERROR;
410+
}
411+
412+
value = cf->args->elts;
413+
name = value[0];
414+
415+
metadata->database = database;
416+
metadata->metavalue = value[2];
417+
418+
var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
419+
if (var == NULL) {
420+
return NGX_CONF_ERROR;
421+
}
422+
423+
var->get_handler = ngx_stream_geoip2_metadata;
424+
var->data = (uintptr_t) metadata;
425+
426+
return NGX_CONF_OK;
427+
}
428+
429+
430+
static char *
431+
ngx_stream_geoip2_add_variable_geodata(ngx_conf_t *cf, ngx_stream_geoip2_db_t *database)
432+
{
433+
ngx_stream_geoip2_ctx_t *geoip2;
434+
ngx_stream_compile_complex_value_t ccv;
341435
ngx_str_t *value, name, source;
342436
ngx_stream_variable_t *var;
343-
ngx_stream_geoip2_ctx_t *geoip2;
344-
ngx_stream_compile_complex_value_t ccv;
437+
int i, nelts, idx;
345438

346439
geoip2 = ngx_pcalloc(cf->pool, sizeof(ngx_stream_geoip2_ctx_t));
347440
if (geoip2 == NULL) {
348441
return NGX_CONF_ERROR;
349442
}
350443

444+
geoip2->database = database;
445+
ngx_str_null(&source);
446+
351447
value = cf->args->elts;
352448
name = value[0];
353449

354-
if (name.data[0] != '$') {
355-
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
356-
"invalid variable name \"%V\"", &name);
357-
return NGX_CONF_ERROR;
358-
}
359-
360-
name.len--;
361-
name.data++;
362450
nelts = (int) cf->args->nelts;
363451
idx = 1;
364-
geoip2->database = (ngx_stream_geoip2_db_t *) conf;
365-
ngx_str_null(&source);
366452

367453
if (nelts > idx) {
368454
for (i = idx; i < nelts; i++) {

0 commit comments

Comments
 (0)