Mercurial > hg > nginx
comparison src/http/modules/ngx_http_geo_module.c @ 5048:2f0862333985 stable-1.2
Merge of r4993, r4994, r4997, r5000: geo ipv6 support.
*) Geo: IPv6 support. The "ranges" mode is still limited to IPv4 only.
*) Geo: properly initialize ngx_cidr_t when dealing with "default".
*) Geo: made "default" affect both IPv4 and IPv6 when using prefixes.
Previously, "default" was equivalent to specifying 0.0.0.0/0, now
it's equivalent to specifying both 0.0.0.0/0 and ::/0 (if support
for IPv6 is enabled) with the same value.
*) Geo: improved code readability.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 11 Feb 2013 12:31:43 +0000 |
parents | 852f40088278 |
children |
comparison
equal
deleted
inserted
replaced
5047:852f40088278 | 5048:2f0862333985 |
---|---|
16 u_short end; | 16 u_short end; |
17 } ngx_http_geo_range_t; | 17 } ngx_http_geo_range_t; |
18 | 18 |
19 | 19 |
20 typedef struct { | 20 typedef struct { |
21 ngx_radix_tree_t *tree; | |
22 #if (NGX_HAVE_INET6) | |
23 ngx_radix_tree_t *tree6; | |
24 #endif | |
25 } ngx_http_geo_trees_t; | |
26 | |
27 | |
28 typedef struct { | |
21 ngx_http_geo_range_t **low; | 29 ngx_http_geo_range_t **low; |
22 ngx_http_variable_value_t *default_value; | 30 ngx_http_variable_value_t *default_value; |
23 } ngx_http_geo_high_ranges_t; | 31 } ngx_http_geo_high_ranges_t; |
24 | 32 |
25 | 33 |
33 typedef struct { | 41 typedef struct { |
34 ngx_http_variable_value_t *value; | 42 ngx_http_variable_value_t *value; |
35 ngx_str_t *net; | 43 ngx_str_t *net; |
36 ngx_http_geo_high_ranges_t high; | 44 ngx_http_geo_high_ranges_t high; |
37 ngx_radix_tree_t *tree; | 45 ngx_radix_tree_t *tree; |
46 #if (NGX_HAVE_INET6) | |
47 ngx_radix_tree_t *tree6; | |
48 #endif | |
38 ngx_rbtree_t rbtree; | 49 ngx_rbtree_t rbtree; |
39 ngx_rbtree_node_t sentinel; | 50 ngx_rbtree_node_t sentinel; |
40 ngx_array_t *proxies; | 51 ngx_array_t *proxies; |
41 ngx_pool_t *pool; | 52 ngx_pool_t *pool; |
42 ngx_pool_t *temp_pool; | 53 ngx_pool_t *temp_pool; |
55 } ngx_http_geo_conf_ctx_t; | 66 } ngx_http_geo_conf_ctx_t; |
56 | 67 |
57 | 68 |
58 typedef struct { | 69 typedef struct { |
59 union { | 70 union { |
60 ngx_radix_tree_t *tree; | 71 ngx_http_geo_trees_t trees; |
61 ngx_http_geo_high_ranges_t high; | 72 ngx_http_geo_high_ranges_t high; |
62 } u; | 73 } u; |
63 | 74 |
64 ngx_array_t *proxies; | 75 ngx_array_t *proxies; |
65 unsigned proxy_recursive:1; | 76 unsigned proxy_recursive:1; |
66 | 77 |
67 ngx_int_t index; | 78 ngx_int_t index; |
68 } ngx_http_geo_ctx_t; | 79 } ngx_http_geo_ctx_t; |
69 | 80 |
70 | 81 |
71 static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, | 82 static ngx_int_t ngx_http_geo_addr(ngx_http_request_t *r, |
72 ngx_http_geo_ctx_t *ctx); | 83 ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr); |
73 static ngx_int_t ngx_http_geo_real_addr(ngx_http_request_t *r, | 84 static ngx_int_t ngx_http_geo_real_addr(ngx_http_request_t *r, |
74 ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr); | 85 ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr); |
75 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | 86 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); |
76 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); | 87 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); |
77 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, | 88 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, |
80 ngx_http_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); | 91 ngx_http_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); |
81 static ngx_uint_t ngx_http_geo_delete_range(ngx_conf_t *cf, | 92 static ngx_uint_t ngx_http_geo_delete_range(ngx_conf_t *cf, |
82 ngx_http_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); | 93 ngx_http_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); |
83 static char *ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, | 94 static char *ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, |
84 ngx_str_t *value); | 95 ngx_str_t *value); |
96 static char *ngx_http_geo_cidr_add(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, | |
97 ngx_cidr_t *cidr, ngx_str_t *value, ngx_str_t *net); | |
85 static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf, | 98 static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf, |
86 ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value); | 99 ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value); |
87 static char *ngx_http_geo_add_proxy(ngx_conf_t *cf, | 100 static char *ngx_http_geo_add_proxy(ngx_conf_t *cf, |
88 ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr); | 101 ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr); |
89 static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, | 102 static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, |
153 static ngx_http_geo_header_t ngx_http_geo_header = { | 166 static ngx_http_geo_header_t ngx_http_geo_header = { |
154 { 'G', 'E', 'O', 'R', 'N', 'G' }, 0, sizeof(void *), 0x12345678, 0 | 167 { 'G', 'E', 'O', 'R', 'N', 'G' }, 0, sizeof(void *), 0x12345678, 0 |
155 }; | 168 }; |
156 | 169 |
157 | 170 |
158 /* AF_INET only */ | 171 /* geo range is AF_INET only */ |
159 | 172 |
160 static ngx_int_t | 173 static ngx_int_t |
161 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, | 174 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, |
162 uintptr_t data) | 175 uintptr_t data) |
163 { | 176 { |
164 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; | 177 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; |
165 | 178 |
179 in_addr_t inaddr; | |
180 ngx_addr_t addr; | |
181 struct sockaddr_in *sin; | |
166 ngx_http_variable_value_t *vv; | 182 ngx_http_variable_value_t *vv; |
167 | 183 #if (NGX_HAVE_INET6) |
168 vv = (ngx_http_variable_value_t *) | 184 u_char *p; |
169 ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx)); | 185 struct in6_addr *inaddr6; |
186 #endif | |
187 | |
188 if (ngx_http_geo_addr(r, ctx, &addr) != NGX_OK) { | |
189 vv = (ngx_http_variable_value_t *) | |
190 ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE); | |
191 goto done; | |
192 } | |
193 | |
194 switch (addr.sockaddr->sa_family) { | |
195 | |
196 #if (NGX_HAVE_INET6) | |
197 case AF_INET6: | |
198 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; | |
199 p = inaddr6->s6_addr; | |
200 | |
201 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { | |
202 inaddr = p[12] << 24; | |
203 inaddr += p[13] << 16; | |
204 inaddr += p[14] << 8; | |
205 inaddr += p[15]; | |
206 | |
207 vv = (ngx_http_variable_value_t *) | |
208 ngx_radix32tree_find(ctx->u.trees.tree, inaddr); | |
209 | |
210 } else { | |
211 vv = (ngx_http_variable_value_t *) | |
212 ngx_radix128tree_find(ctx->u.trees.tree6, p); | |
213 } | |
214 | |
215 break; | |
216 #endif | |
217 | |
218 default: /* AF_INET */ | |
219 sin = (struct sockaddr_in *) addr.sockaddr; | |
220 inaddr = ntohl(sin->sin_addr.s_addr); | |
221 | |
222 vv = (ngx_http_variable_value_t *) | |
223 ngx_radix32tree_find(ctx->u.trees.tree, inaddr); | |
224 | |
225 break; | |
226 } | |
227 | |
228 done: | |
170 | 229 |
171 *v = *vv; | 230 *v = *vv; |
172 | 231 |
173 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 232 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
174 "http geo: %v", v); | 233 "http geo: %v", v); |
181 ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, | 240 ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, |
182 uintptr_t data) | 241 uintptr_t data) |
183 { | 242 { |
184 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; | 243 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; |
185 | 244 |
186 in_addr_t addr; | 245 in_addr_t inaddr; |
246 ngx_addr_t addr; | |
187 ngx_uint_t n; | 247 ngx_uint_t n; |
248 struct sockaddr_in *sin; | |
188 ngx_http_geo_range_t *range; | 249 ngx_http_geo_range_t *range; |
250 #if (NGX_HAVE_INET6) | |
251 u_char *p; | |
252 struct in6_addr *inaddr6; | |
253 #endif | |
189 | 254 |
190 *v = *ctx->u.high.default_value; | 255 *v = *ctx->u.high.default_value; |
191 | 256 |
257 if (ngx_http_geo_addr(r, ctx, &addr) == NGX_OK) { | |
258 | |
259 switch (addr.sockaddr->sa_family) { | |
260 | |
261 #if (NGX_HAVE_INET6) | |
262 case AF_INET6: | |
263 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; | |
264 | |
265 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { | |
266 p = inaddr6->s6_addr; | |
267 | |
268 inaddr = p[12] << 24; | |
269 inaddr += p[13] << 16; | |
270 inaddr += p[14] << 8; | |
271 inaddr += p[15]; | |
272 | |
273 } else { | |
274 inaddr = INADDR_NONE; | |
275 } | |
276 | |
277 break; | |
278 #endif | |
279 | |
280 default: /* AF_INET */ | |
281 sin = (struct sockaddr_in *) addr.sockaddr; | |
282 inaddr = ntohl(sin->sin_addr.s_addr); | |
283 break; | |
284 } | |
285 | |
286 } else { | |
287 inaddr = INADDR_NONE; | |
288 } | |
289 | |
192 if (ctx->u.high.low) { | 290 if (ctx->u.high.low) { |
193 addr = ngx_http_geo_addr(r, ctx); | 291 range = ctx->u.high.low[inaddr >> 16]; |
194 | |
195 range = ctx->u.high.low[addr >> 16]; | |
196 | 292 |
197 if (range) { | 293 if (range) { |
198 n = addr & 0xffff; | 294 n = inaddr & 0xffff; |
199 do { | 295 do { |
200 if (n >= (ngx_uint_t) range->start | 296 if (n >= (ngx_uint_t) range->start |
201 && n <= (ngx_uint_t) range->end) | 297 && n <= (ngx_uint_t) range->end) |
202 { | 298 { |
203 *v = *range->value; | 299 *v = *range->value; |
212 | 308 |
213 return NGX_OK; | 309 return NGX_OK; |
214 } | 310 } |
215 | 311 |
216 | 312 |
217 static in_addr_t | 313 static ngx_int_t |
218 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) | 314 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, |
219 { | 315 ngx_addr_t *addr) |
220 ngx_addr_t addr; | 316 { |
221 ngx_table_elt_t *xfwd; | 317 ngx_table_elt_t *xfwd; |
222 struct sockaddr_in *sin; | 318 |
223 | 319 if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) { |
224 if (ngx_http_geo_real_addr(r, ctx, &addr) != NGX_OK) { | 320 return NGX_ERROR; |
225 return INADDR_NONE; | |
226 } | 321 } |
227 | 322 |
228 xfwd = r->headers_in.x_forwarded_for; | 323 xfwd = r->headers_in.x_forwarded_for; |
229 | 324 |
230 if (xfwd != NULL && ctx->proxies != NULL) { | 325 if (xfwd != NULL && ctx->proxies != NULL) { |
231 (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data, | 326 (void) ngx_http_get_forwarded_addr(r, addr, xfwd->value.data, |
232 xfwd->value.len, ctx->proxies, | 327 xfwd->value.len, ctx->proxies, |
233 ctx->proxy_recursive); | 328 ctx->proxy_recursive); |
234 } | 329 } |
235 | 330 |
236 #if (NGX_HAVE_INET6) | 331 return NGX_OK; |
237 | |
238 if (addr.sockaddr->sa_family == AF_INET6) { | |
239 u_char *p; | |
240 in_addr_t inaddr; | |
241 struct in6_addr *inaddr6; | |
242 | |
243 inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; | |
244 | |
245 if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { | |
246 p = inaddr6->s6_addr; | |
247 | |
248 inaddr = p[12] << 24; | |
249 inaddr += p[13] << 16; | |
250 inaddr += p[14] << 8; | |
251 inaddr += p[15]; | |
252 | |
253 return inaddr; | |
254 } | |
255 } | |
256 | |
257 #endif | |
258 | |
259 if (addr.sockaddr->sa_family != AF_INET) { | |
260 return INADDR_NONE; | |
261 } | |
262 | |
263 sin = (struct sockaddr_in *) addr.sockaddr; | |
264 return ntohl(sin->sin_addr.s_addr); | |
265 } | 332 } |
266 | 333 |
267 | 334 |
268 static ngx_int_t | 335 static ngx_int_t |
269 ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, | 336 ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, |
313 ngx_pool_t *pool; | 380 ngx_pool_t *pool; |
314 ngx_array_t *a; | 381 ngx_array_t *a; |
315 ngx_http_variable_t *var; | 382 ngx_http_variable_t *var; |
316 ngx_http_geo_ctx_t *geo; | 383 ngx_http_geo_ctx_t *geo; |
317 ngx_http_geo_conf_ctx_t ctx; | 384 ngx_http_geo_conf_ctx_t ctx; |
385 #if (NGX_HAVE_INET6) | |
386 static struct in6_addr zero; | |
387 #endif | |
318 | 388 |
319 value = cf->args->elts; | 389 value = cf->args->elts; |
320 | 390 |
321 geo = ngx_palloc(cf->pool, sizeof(ngx_http_geo_ctx_t)); | 391 geo = ngx_palloc(cf->pool, sizeof(ngx_http_geo_ctx_t)); |
322 if (geo == NULL) { | 392 if (geo == NULL) { |
443 if (ctx.tree == NULL) { | 513 if (ctx.tree == NULL) { |
444 return NGX_CONF_ERROR; | 514 return NGX_CONF_ERROR; |
445 } | 515 } |
446 } | 516 } |
447 | 517 |
448 geo->u.tree = ctx.tree; | 518 geo->u.trees.tree = ctx.tree; |
519 | |
520 #if (NGX_HAVE_INET6) | |
521 if (ctx.tree6 == NULL) { | |
522 ctx.tree6 = ngx_radix_tree_create(cf->pool, -1); | |
523 if (ctx.tree6 == NULL) { | |
524 return NGX_CONF_ERROR; | |
525 } | |
526 } | |
527 | |
528 geo->u.trees.tree6 = ctx.tree6; | |
529 #endif | |
449 | 530 |
450 var->get_handler = ngx_http_geo_cidr_variable; | 531 var->get_handler = ngx_http_geo_cidr_variable; |
451 var->data = (uintptr_t) geo; | 532 var->data = (uintptr_t) geo; |
452 | 533 |
453 ngx_destroy_pool(ctx.temp_pool); | 534 ngx_destroy_pool(ctx.temp_pool); |
459 { | 540 { |
460 return NGX_CONF_ERROR; | 541 return NGX_CONF_ERROR; |
461 } | 542 } |
462 | 543 |
463 /* NGX_BUSY is okay (default was set explicitly) */ | 544 /* NGX_BUSY is okay (default was set explicitly) */ |
545 | |
546 #if (NGX_HAVE_INET6) | |
547 if (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr, | |
548 (uintptr_t) &ngx_http_variable_null_value) | |
549 == NGX_ERROR) | |
550 { | |
551 return NGX_CONF_ERROR; | |
552 } | |
553 #endif | |
464 } | 554 } |
465 | 555 |
466 return rv; | 556 return rv; |
467 } | 557 } |
468 | 558 |
481 | 571 |
482 if (cf->args->nelts == 1) { | 572 if (cf->args->nelts == 1) { |
483 | 573 |
484 if (ngx_strcmp(value[0].data, "ranges") == 0) { | 574 if (ngx_strcmp(value[0].data, "ranges") == 0) { |
485 | 575 |
486 if (ctx->tree) { | 576 if (ctx->tree |
577 #if (NGX_HAVE_INET6) | |
578 || ctx->tree6 | |
579 #endif | |
580 ) | |
581 { | |
487 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 582 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
488 "the \"ranges\" directive must be " | 583 "the \"ranges\" directive must be " |
489 "the first directive inside \"geo\" block"); | 584 "the first directive inside \"geo\" block"); |
490 goto failed; | 585 goto failed; |
491 } | 586 } |
919 | 1014 |
920 static char * | 1015 static char * |
921 ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, | 1016 ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, |
922 ngx_str_t *value) | 1017 ngx_str_t *value) |
923 { | 1018 { |
924 ngx_int_t rc, del; | 1019 char *rv; |
925 ngx_str_t *net; | 1020 ngx_int_t rc, del; |
926 ngx_uint_t i; | 1021 ngx_str_t *net; |
927 ngx_cidr_t cidr; | 1022 ngx_cidr_t cidr; |
928 ngx_http_variable_value_t *val, *old; | |
929 | 1023 |
930 if (ctx->tree == NULL) { | 1024 if (ctx->tree == NULL) { |
931 ctx->tree = ngx_radix_tree_create(ctx->pool, -1); | 1025 ctx->tree = ngx_radix_tree_create(ctx->pool, -1); |
932 if (ctx->tree == NULL) { | 1026 if (ctx->tree == NULL) { |
933 return NGX_CONF_ERROR; | 1027 return NGX_CONF_ERROR; |
934 } | 1028 } |
935 } | 1029 } |
936 | 1030 |
1031 #if (NGX_HAVE_INET6) | |
1032 if (ctx->tree6 == NULL) { | |
1033 ctx->tree6 = ngx_radix_tree_create(ctx->pool, -1); | |
1034 if (ctx->tree6 == NULL) { | |
1035 return NGX_CONF_ERROR; | |
1036 } | |
1037 } | |
1038 #endif | |
1039 | |
937 if (ngx_strcmp(value[0].data, "default") == 0) { | 1040 if (ngx_strcmp(value[0].data, "default") == 0) { |
938 /* cidr.family = AF_INET; */ | 1041 cidr.family = AF_INET; |
939 cidr.u.in.addr = 0; | 1042 cidr.u.in.addr = 0; |
940 cidr.u.in.mask = 0; | 1043 cidr.u.in.mask = 0; |
1044 | |
1045 rv = ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]); | |
1046 | |
1047 if (rv != NGX_CONF_OK) { | |
1048 return rv; | |
1049 } | |
1050 | |
1051 #if (NGX_HAVE_INET6) | |
1052 cidr.family = AF_INET6; | |
1053 ngx_memzero(&cidr.u.in6, sizeof(ngx_in6_cidr_t)); | |
1054 | |
1055 rv = ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]); | |
1056 | |
1057 if (rv != NGX_CONF_OK) { | |
1058 return rv; | |
1059 } | |
1060 #endif | |
1061 | |
1062 return NGX_CONF_OK; | |
1063 } | |
1064 | |
1065 if (ngx_strcmp(value[0].data, "delete") == 0) { | |
1066 net = &value[1]; | |
1067 del = 1; | |
1068 | |
1069 } else { | |
941 net = &value[0]; | 1070 net = &value[0]; |
942 | 1071 del = 0; |
943 } else { | 1072 } |
944 if (ngx_strcmp(value[0].data, "delete") == 0) { | 1073 |
945 net = &value[1]; | 1074 if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) { |
946 del = 1; | 1075 return NGX_CONF_ERROR; |
947 | 1076 } |
948 } else { | 1077 |
949 net = &value[0]; | 1078 if (cidr.family == AF_INET) { |
950 del = 0; | |
951 } | |
952 | |
953 if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) { | |
954 return NGX_CONF_ERROR; | |
955 } | |
956 | |
957 if (cidr.family != AF_INET) { | |
958 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
959 "\"geo\" supports IPv4 only"); | |
960 return NGX_CONF_ERROR; | |
961 } | |
962 | |
963 cidr.u.in.addr = ntohl(cidr.u.in.addr); | 1079 cidr.u.in.addr = ntohl(cidr.u.in.addr); |
964 cidr.u.in.mask = ntohl(cidr.u.in.mask); | 1080 cidr.u.in.mask = ntohl(cidr.u.in.mask); |
965 | 1081 } |
966 if (del) { | 1082 |
967 if (ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, | 1083 if (del) { |
968 cidr.u.in.mask) | 1084 switch (cidr.family) { |
969 != NGX_OK) | 1085 |
970 { | 1086 #if (NGX_HAVE_INET6) |
971 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | 1087 case AF_INET6: |
972 "no network \"%V\" to delete", net); | 1088 rc = ngx_radix128tree_delete(ctx->tree6, |
973 } | 1089 cidr.u.in6.addr.s6_addr, |
974 | 1090 cidr.u.in6.mask.s6_addr); |
975 return NGX_CONF_OK; | 1091 break; |
976 } | 1092 #endif |
977 } | 1093 |
978 | 1094 default: /* AF_INET */ |
979 val = ngx_http_geo_value(cf, ctx, &value[1]); | 1095 rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, |
1096 cidr.u.in.mask); | |
1097 break; | |
1098 } | |
1099 | |
1100 if (rc != NGX_OK) { | |
1101 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
1102 "no network \"%V\" to delete", net); | |
1103 } | |
1104 | |
1105 return NGX_CONF_OK; | |
1106 } | |
1107 | |
1108 return ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], net); | |
1109 } | |
1110 | |
1111 | |
1112 static char * | |
1113 ngx_http_geo_cidr_add(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, | |
1114 ngx_cidr_t *cidr, ngx_str_t *value, ngx_str_t *net) | |
1115 { | |
1116 ngx_int_t rc; | |
1117 ngx_http_variable_value_t *val, *old; | |
1118 | |
1119 val = ngx_http_geo_value(cf, ctx, value); | |
980 | 1120 |
981 if (val == NULL) { | 1121 if (val == NULL) { |
982 return NGX_CONF_ERROR; | 1122 return NGX_CONF_ERROR; |
983 } | 1123 } |
984 | 1124 |
985 for (i = 2; i; i--) { | 1125 switch (cidr->family) { |
986 rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, cidr.u.in.mask, | 1126 |
987 (uintptr_t) val); | 1127 #if (NGX_HAVE_INET6) |
1128 case AF_INET6: | |
1129 rc = ngx_radix128tree_insert(ctx->tree6, cidr->u.in6.addr.s6_addr, | |
1130 cidr->u.in6.mask.s6_addr, | |
1131 (uintptr_t) val); | |
1132 | |
988 if (rc == NGX_OK) { | 1133 if (rc == NGX_OK) { |
989 return NGX_CONF_OK; | 1134 return NGX_CONF_OK; |
990 } | 1135 } |
991 | 1136 |
992 if (rc == NGX_ERROR) { | 1137 if (rc == NGX_ERROR) { |
994 } | 1139 } |
995 | 1140 |
996 /* rc == NGX_BUSY */ | 1141 /* rc == NGX_BUSY */ |
997 | 1142 |
998 old = (ngx_http_variable_value_t *) | 1143 old = (ngx_http_variable_value_t *) |
999 ngx_radix32tree_find(ctx->tree, cidr.u.in.addr); | 1144 ngx_radix128tree_find(ctx->tree6, |
1145 cidr->u.in6.addr.s6_addr); | |
1000 | 1146 |
1001 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | 1147 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
1002 "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", | 1148 "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", |
1003 net, val, old); | 1149 net, val, old); |
1004 | 1150 |
1005 rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, cidr.u.in.mask); | 1151 rc = ngx_radix128tree_delete(ctx->tree6, |
1152 cidr->u.in6.addr.s6_addr, | |
1153 cidr->u.in6.mask.s6_addr); | |
1006 | 1154 |
1007 if (rc == NGX_ERROR) { | 1155 if (rc == NGX_ERROR) { |
1008 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); | 1156 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); |
1009 return NGX_CONF_ERROR; | 1157 return NGX_CONF_ERROR; |
1010 } | 1158 } |
1159 | |
1160 rc = ngx_radix128tree_insert(ctx->tree6, cidr->u.in6.addr.s6_addr, | |
1161 cidr->u.in6.mask.s6_addr, | |
1162 (uintptr_t) val); | |
1163 | |
1164 break; | |
1165 #endif | |
1166 | |
1167 default: /* AF_INET */ | |
1168 rc = ngx_radix32tree_insert(ctx->tree, cidr->u.in.addr, | |
1169 cidr->u.in.mask, (uintptr_t) val); | |
1170 | |
1171 if (rc == NGX_OK) { | |
1172 return NGX_CONF_OK; | |
1173 } | |
1174 | |
1175 if (rc == NGX_ERROR) { | |
1176 return NGX_CONF_ERROR; | |
1177 } | |
1178 | |
1179 /* rc == NGX_BUSY */ | |
1180 | |
1181 old = (ngx_http_variable_value_t *) | |
1182 ngx_radix32tree_find(ctx->tree, cidr->u.in.addr); | |
1183 | |
1184 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | |
1185 "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", | |
1186 net, val, old); | |
1187 | |
1188 rc = ngx_radix32tree_delete(ctx->tree, | |
1189 cidr->u.in.addr, cidr->u.in.mask); | |
1190 | |
1191 if (rc == NGX_ERROR) { | |
1192 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); | |
1193 return NGX_CONF_ERROR; | |
1194 } | |
1195 | |
1196 rc = ngx_radix32tree_insert(ctx->tree, cidr->u.in.addr, | |
1197 cidr->u.in.mask, (uintptr_t) val); | |
1198 | |
1199 break; | |
1200 } | |
1201 | |
1202 if (rc == NGX_OK) { | |
1203 return NGX_CONF_OK; | |
1011 } | 1204 } |
1012 | 1205 |
1013 return NGX_CONF_ERROR; | 1206 return NGX_CONF_ERROR; |
1014 } | 1207 } |
1015 | 1208 |