3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
13 ngx_radix_tree_t
*tree
;
16 } ngx_http_geo_conf_t
;
19 static char *ngx_http_geo_block(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
);
20 static char *ngx_http_geo(ngx_conf_t
*cf
, ngx_command_t
*dummy
, void *conf
);
23 static ngx_command_t ngx_http_geo_commands
[] = {
26 NGX_HTTP_MAIN_CONF
|NGX_CONF_BLOCK
|NGX_CONF_TAKE1
,
28 NGX_HTTP_MAIN_CONF_OFFSET
,
36 static ngx_http_module_t ngx_http_geo_module_ctx
= {
39 NULL
, /* create main configuration */
40 NULL
, /* init main configuration */
42 NULL
, /* create server configuration */
43 NULL
, /* merge server configuration */
45 NULL
, /* create location configuration */
46 NULL
/* merge location configuration */
50 ngx_module_t ngx_http_geo_module
= {
52 &ngx_http_geo_module_ctx
, /* module context */
53 ngx_http_geo_commands
, /* module directives */
54 NGX_HTTP_MODULE
, /* module type */
55 NULL
, /* init module */
56 NULL
/* init process */
60 static ngx_http_variable_value_t ngx_http_geo_null_value
=
61 { 0, ngx_string("0") };
66 static ngx_http_variable_value_t
*
67 ngx_http_geo_variable(ngx_http_request_t
*r
, void *data
)
69 ngx_radix_tree_t
*tree
= data
;
71 struct sockaddr_in
*sin
;
72 ngx_http_variable_value_t
*var
;
74 sin
= (struct sockaddr_in
*) r
->connection
->sockaddr
;
76 ngx_log_debug0(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
79 var
= (ngx_http_variable_value_t
*)
80 ngx_radix32tree_find(tree
, ntohl(sin
->sin_addr
.s_addr
));
82 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
83 "http geo: %V %V", &r
->connection
->addr_text
, &var
->text
);
90 ngx_http_geo_block(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
96 ngx_radix_tree_t
*tree
;
97 ngx_http_geo_conf_t geo
;
98 ngx_http_variable_t
*var
;
100 if (!(var
= ngx_http_add_variable(cf
))) {
101 return NGX_CONF_ERROR
;
104 if (!(tree
= ngx_radix_tree_create(cf
->pool
, -1))) {
105 return NGX_CONF_ERROR
;
108 value
= cf
->args
->elts
;
110 var
->name
= value
[1];
111 var
->handler
= ngx_http_geo_variable
;
115 * create the temporary pool of a huge initial size
116 * to process quickly a large number of geo lines
119 if (!(pool
= ngx_create_pool(512 * 1024, cf
->log
))) {
120 return NGX_CONF_ERROR
;
123 if (ngx_array_init(&geo
.values
, pool
, 512,
124 sizeof(ngx_http_variable_value_t
*)) == NGX_ERROR
)
126 ngx_destroy_pool(pool
);
127 return NGX_CONF_ERROR
;
136 cf
->handler
= ngx_http_geo
;
137 cf
->handler_conf
= conf
;
139 rv
= ngx_conf_parse(cf
, NULL
);
143 ngx_destroy_pool(pool
);
145 if (ngx_radix32tree_find(tree
, 0) != NGX_RADIX_NO_VALUE
) {
149 if (ngx_radix32tree_insert(tree
, 0, 0,
150 (uintptr_t) &ngx_http_geo_null_value
) == NGX_ERROR
)
152 return NGX_CONF_ERROR
;
162 ngx_http_geo(ngx_conf_t
*cf
, ngx_command_t
*dummy
, void *conf
)
166 ngx_str_t
*value
, file
;
167 ngx_inet_cidr_t cidrin
;
168 ngx_http_geo_conf_t
*geo
;
169 ngx_http_variable_value_t
*var
, **v
;
173 if (cf
->args
->nelts
!= 2) {
174 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
175 "invalid number of the geo parameters");
176 return NGX_CONF_ERROR
;
179 value
= cf
->args
->elts
;
181 if (ngx_strcmp(value
[0].data
, "include") == 0) {
184 if (ngx_conf_full_name(cf
->cycle
, &file
) == NGX_ERROR
){
185 return NGX_CONF_ERROR
;
188 ngx_log_debug1(NGX_LOG_DEBUG_CORE
, cf
->log
, 0, "include %s", file
.data
);
190 return ngx_conf_parse(cf
, &file
);
193 if (ngx_strcmp(value
[0].data
, "default") == 0) {
198 if (ngx_ptocidr(&value
[0], &cidrin
) == NGX_ERROR
) {
199 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
200 "invalid parameter \"%V\"", &value
[0]);
201 return NGX_CONF_ERROR
;
204 cidrin
.addr
= ntohl(cidrin
.addr
);
205 cidrin
.mask
= ntohl(cidrin
.mask
);
208 n
= ngx_atoi(value
[1].data
, value
[1].len
);
211 v
= geo
->values
.elts
;
213 if (n
== NGX_ERROR
) {
214 for (i
= 0; i
< geo
->values
.nelts
; i
++) {
215 if (ngx_strcmp(value
[1].data
, v
[i
]->text
.data
) == 0) {
222 for (i
= 0; i
< geo
->values
.nelts
; i
++) {
223 if (v
[i
]->value
== (ngx_uint_t
) n
) {
230 if (i
== geo
->values
.nelts
) {
231 var
= ngx_palloc(geo
->pool
, sizeof(ngx_http_variable_value_t
));
233 return NGX_CONF_ERROR
;
236 var
->text
.len
= value
[1].len
;
237 if (!(var
->text
.data
= ngx_pstrdup(geo
->pool
, &value
[1]))) {
238 return NGX_CONF_ERROR
;
241 var
->value
= (n
== NGX_ERROR
) ? 0 : n
;
243 if (!(v
= ngx_array_push(&geo
->values
))) {
244 return NGX_CONF_ERROR
;
250 rc
= ngx_radix32tree_insert(geo
->tree
, cidrin
.addr
, cidrin
.mask
,
252 if (rc
== NGX_ERROR
) {
253 return NGX_CONF_ERROR
;
256 if (rc
== NGX_BUSY
) {
257 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0, "duplicate parameter \"%V\"",
259 return NGX_CONF_ERROR
;