Mercurial > hg > nginx-quic
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 { |