comparison src/http/modules/ngx_http_geo_module.c @ 2399:aecf0755cee3

$geo variable support
author Igor Sysoev <igor@sysoev.ru>
date Thu, 11 Dec 2008 09:46:45 +0000
parents f2e0e1fa87f0
children 39f3b4f9989e
comparison
equal deleted inserted replaced
2398:f2e0e1fa87f0 2399:aecf0755cee3
8 #include <ngx_core.h> 8 #include <ngx_core.h>
9 #include <ngx_http.h> 9 #include <ngx_http.h>
10 10
11 11
12 typedef struct { 12 typedef struct {
13 u_short start; 13 u_short start;
14 u_short end; 14 u_short end;
15 ngx_http_variable_value_t *value; 15 ngx_http_variable_value_t *value;
16 } ngx_http_geo_range_t; 16 } ngx_http_geo_range_t;
17 17
18 18
19 typedef struct { 19 typedef struct {
20 ngx_http_geo_range_t *ranges; 20 ngx_http_geo_range_t *ranges;
21 ngx_uint_t n; 21 ngx_uint_t n;
22 } ngx_http_geo_low_ranges_t; 22 } ngx_http_geo_low_ranges_t;
23 23
24 24
25 typedef struct { 25 typedef struct {
26 ngx_http_geo_low_ranges_t low[0x10000]; 26 ngx_http_geo_low_ranges_t low[0x10000];
27 ngx_http_variable_value_t *default_value; 27 ngx_http_variable_value_t *default_value;
28 } ngx_http_geo_high_ranges_t; 28 } ngx_http_geo_high_ranges_t;
29 29
30 30
31 typedef struct { 31 typedef struct {
32 ngx_http_variable_value_t *value; 32 ngx_http_variable_value_t *value;
33 ngx_str_t *net; 33 ngx_str_t *net;
34 ngx_http_geo_high_ranges_t *high; 34 ngx_http_geo_high_ranges_t *high;
35 ngx_radix_tree_t *tree; 35 ngx_radix_tree_t *tree;
36 ngx_rbtree_t rbtree; 36 ngx_rbtree_t rbtree;
37 ngx_rbtree_node_t sentinel; 37 ngx_rbtree_node_t sentinel;
38 ngx_pool_t *pool; 38 ngx_pool_t *pool;
39 ngx_pool_t *temp_pool; 39 ngx_pool_t *temp_pool;
40 } ngx_http_geo_conf_ctx_t; 40 } ngx_http_geo_conf_ctx_t;
41 41
42 42
43 typedef struct {
44 union {
45 ngx_radix_tree_t *tree;
46 ngx_http_geo_high_ranges_t *high;
47 } u;
48
49 ngx_int_t index;
50 } ngx_http_geo_ctx_t;
51
52
53 static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r,
54 ngx_http_geo_ctx_t *ctx);
43 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 55 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
44 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); 56 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
45 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, 57 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
46 ngx_str_t *value); 58 ngx_str_t *value);
47 static char *ngx_http_geo_add_range(ngx_conf_t *cf, 59 static char *ngx_http_geo_add_range(ngx_conf_t *cf,
55 67
56 68
57 static ngx_command_t ngx_http_geo_commands[] = { 69 static ngx_command_t ngx_http_geo_commands[] = {
58 70
59 { ngx_string("geo"), 71 { ngx_string("geo"),
60 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, 72 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
61 ngx_http_geo_block, 73 ngx_http_geo_block,
62 NGX_HTTP_MAIN_CONF_OFFSET, 74 NGX_HTTP_MAIN_CONF_OFFSET,
63 0, 75 0,
64 NULL }, 76 NULL },
65 77
102 114
103 static ngx_int_t 115 static ngx_int_t
104 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, 116 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
105 uintptr_t data) 117 uintptr_t data)
106 { 118 {
107 ngx_radix_tree_t *tree = (ngx_radix_tree_t *) data; 119 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
108 120
109 struct sockaddr_in *sin;
110 ngx_http_variable_value_t *vv; 121 ngx_http_variable_value_t *vv;
111 122
112 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
113 "http geo started");
114
115 sin = (struct sockaddr_in *) r->connection->sockaddr;
116
117 vv = (ngx_http_variable_value_t *) 123 vv = (ngx_http_variable_value_t *)
118 ngx_radix32tree_find(tree, ntohl(sin->sin_addr.s_addr)); 124 ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx));
119 125
120 *v = *vv; 126 *v = *vv;
121 127
122 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 128 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
123 "http geo: %V %v", &r->connection->addr_text, v); 129 "http geo: %v", v);
124 130
125 return NGX_OK; 131 return NGX_OK;
126 } 132 }
127 133
128 134
129 static ngx_int_t 135 static ngx_int_t
130 ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, 136 ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
131 uintptr_t data) 137 uintptr_t data)
132 { 138 {
133 ngx_http_geo_high_ranges_t *high = (ngx_http_geo_high_ranges_t *) data; 139 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
134 140
135 in_addr_t addr; 141 in_addr_t addr;
136 ngx_uint_t i, n; 142 ngx_uint_t i, n;
137 struct sockaddr_in *sin;
138 ngx_http_geo_range_t *range; 143 ngx_http_geo_range_t *range;
139 144
140 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 145 *v = *ctx->u.high->default_value;
141 "http geo started"); 146
142 147 addr = ngx_http_geo_addr(r, ctx);
143 sin = (struct sockaddr_in *) r->connection->sockaddr; 148
144 149 range = ctx->u.high->low[addr >> 16].ranges;
145 *v = *high->default_value;
146
147 addr = ntohl(sin->sin_addr.s_addr);
148
149 range = high->low[addr >> 16].ranges;
150 150
151 n = addr & 0xffff; 151 n = addr & 0xffff;
152 152
153 for (i = 0; i < high->low[addr >> 16].n; i++) { 153 for (i = 0; i < ctx->u.high->low[addr >> 16].n; i++) {
154 if (n >= (ngx_uint_t) range[i].start 154 if (n >= (ngx_uint_t) range[i].start
155 && n <= (ngx_uint_t) range[i].end) 155 && n <= (ngx_uint_t) range[i].end)
156 { 156 {
157 *v = *range[i].value; 157 *v = *range[i].value;
158 } 158 }
159 } 159 }
160 160
161 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 161 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
162 "http geo: %V %v", &r->connection->addr_text, v); 162 "http geo: %v", v);
163 163
164 return NGX_OK; 164 return NGX_OK;
165 }
166
167
168 static in_addr_t
169 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
170 {
171 struct sockaddr_in *sin;
172 ngx_http_variable_value_t *v;
173
174 if (ctx->index == -1) {
175 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
176 "http geo started: %V", &r->connection->addr_text);
177
178 sin = (struct sockaddr_in *) r->connection->sockaddr;
179 return ntohl(sin->sin_addr.s_addr);
180 }
181
182 v = ngx_http_get_flushed_variable(r, ctx->index);
183
184 if (v == NULL || v->not_found) {
185 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
186 "http geo not found");
187
188 return 0;
189 }
190
191 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
192 "http geo started: %v", v);
193
194 return ntohl(ngx_inet_addr(v->data, v->len));
165 } 195 }
166 196
167 197
168 static char * 198 static char *
169 ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 199 ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
170 { 200 {
171 char *rv; 201 char *rv;
172 size_t len; 202 size_t len;
173 ngx_str_t *value; 203 ngx_str_t *value, name;
174 ngx_uint_t i; 204 ngx_uint_t i;
175 ngx_conf_t save; 205 ngx_conf_t save;
176 ngx_pool_t *pool; 206 ngx_pool_t *pool;
177 ngx_array_t *a; 207 ngx_array_t *a;
178 ngx_http_variable_t *var; 208 ngx_http_variable_t *var;
209 ngx_http_geo_ctx_t *geo;
179 ngx_http_geo_conf_ctx_t ctx; 210 ngx_http_geo_conf_ctx_t ctx;
180 211
181 value = cf->args->elts; 212 value = cf->args->elts;
182 213
183 var = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE); 214 geo = ngx_palloc(cf->pool, sizeof(ngx_http_geo_ctx_t));
215 if (geo == NULL) {
216 return NGX_CONF_ERROR;
217 }
218
219 name = value[1];
220 name.len--;
221 name.data++;
222
223 if (cf->args->nelts == 3) {
224
225 geo->index = ngx_http_get_variable_index(cf, &name);
226 if (geo->index == NGX_ERROR) {
227 return NGX_CONF_ERROR;
228 }
229
230 name = value[2];
231 name.len--;
232 name.data++;
233
234 } else {
235 geo->index = -1;
236 }
237
238 var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
184 if (var == NULL) { 239 if (var == NULL) {
185 return NGX_CONF_ERROR; 240 return NGX_CONF_ERROR;
186 } 241 }
187 242
188 pool = ngx_create_pool(16384, cf->log); 243 pool = ngx_create_pool(16384, cf->log);
231 } 286 }
232 287
233 ngx_memcpy(ctx.high->low[i].ranges, a->elts, len); 288 ngx_memcpy(ctx.high->low[i].ranges, a->elts, len);
234 } 289 }
235 290
291 geo->u.high = ctx.high;
292
236 var->get_handler = ngx_http_geo_range_variable; 293 var->get_handler = ngx_http_geo_range_variable;
237 var->data = (uintptr_t) ctx.high; 294 var->data = (uintptr_t) geo;
238 295
239 ngx_destroy_pool(ctx.temp_pool); 296 ngx_destroy_pool(ctx.temp_pool);
240 ngx_destroy_pool(pool); 297 ngx_destroy_pool(pool);
241 298
242 if (ctx.high->default_value == NULL) { 299 if (ctx.high->default_value == NULL) {
249 if (ctx.tree == NULL) { 306 if (ctx.tree == NULL) {
250 return NGX_CONF_ERROR; 307 return NGX_CONF_ERROR;
251 } 308 }
252 } 309 }
253 310
311 geo->u.tree = ctx.tree;
312
254 var->get_handler = ngx_http_geo_cidr_variable; 313 var->get_handler = ngx_http_geo_cidr_variable;
255 var->data = (uintptr_t) ctx.tree; 314 var->data = (uintptr_t) geo;
256 315
257 ngx_destroy_pool(ctx.temp_pool); 316 ngx_destroy_pool(ctx.temp_pool);
258 ngx_destroy_pool(pool); 317 ngx_destroy_pool(pool);
259 318
260 if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) { 319 if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) {
631 } else { 690 } else {
632 net = &value[0]; 691 net = &value[0];
633 del = 0; 692 del = 0;
634 } 693 }
635 694
636 rc = ngx_ptocidr(net, &cidrin); 695 if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
637 696 cidrin.addr = 0xffffffff;
638 if (rc == NGX_ERROR) { 697 cidrin.mask = 0xffffffff;
639 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, 698
640 "invalid network \"%V\"", net); 699 } else {
641 return NGX_CONF_ERROR; 700 rc = ngx_ptocidr(net, &cidrin);
642 } 701
643 702 if (rc == NGX_ERROR) {
644 if (rc == NGX_DONE) { 703 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
645 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, 704 "invalid network \"%V\"", net);
646 "low address bits of %V are meaningless", net); 705 return NGX_CONF_ERROR;
647 } 706 }
648 707
649 cidrin.addr = ntohl(cidrin.addr); 708 if (rc == NGX_DONE) {
650 cidrin.mask = ntohl(cidrin.mask); 709 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
710 "low address bits of %V are meaningless",
711 net);
712 }
713
714 cidrin.addr = ntohl(cidrin.addr);
715 cidrin.mask = ntohl(cidrin.mask);
716 }
651 717
652 if (del) { 718 if (del) {
653 if (ngx_radix32tree_delete(ctx->tree, cidrin.addr, cidrin.mask) 719 if (ngx_radix32tree_delete(ctx->tree, cidrin.addr, cidrin.mask)
654 != NGX_OK) 720 != NGX_OK)
655 { 721 {