~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/http/modules/ngx_http_geo_module.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  1 
  2 /*
  3  * Copyright (C) Igor Sysoev
  4  */
  5 
  6 
  7 #include <ngx_config.h>
  8 #include <ngx_core.h>
  9 #include <ngx_http.h>
 10 
 11 
 12 typedef struct {
 13     u_short                          start;
 14     u_short                          end;
 15     ngx_http_variable_value_t       *value;
 16 } ngx_http_geo_range_t;
 17 
 18 
 19 typedef struct {
 20     ngx_http_geo_range_t            *ranges;
 21     ngx_uint_t                       n;
 22 } ngx_http_geo_low_ranges_t;
 23 
 24 
 25 typedef struct {
 26     ngx_http_geo_low_ranges_t        low[0x10000];
 27     ngx_http_variable_value_t       *default_value;
 28 } ngx_http_geo_high_ranges_t;
 29 
 30 
 31 typedef struct {
 32     ngx_http_variable_value_t       *value;
 33     ngx_str_t                       *net;
 34     ngx_http_geo_high_ranges_t      *high;
 35     ngx_radix_tree_t                *tree;
 36     ngx_rbtree_t                     rbtree;
 37     ngx_rbtree_node_t                sentinel;
 38     ngx_array_t                     *proxies;
 39     ngx_pool_t                      *pool;
 40     ngx_pool_t                      *temp_pool;
 41 } ngx_http_geo_conf_ctx_t;
 42 
 43 
 44 typedef struct {
 45     union {
 46         ngx_radix_tree_t            *tree;
 47         ngx_http_geo_high_ranges_t  *high;
 48     } u;
 49 
 50     ngx_array_t                     *proxies;
 51 
 52     ngx_int_t                        index;
 53 } ngx_http_geo_ctx_t;
 54 
 55 
 56 static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r,
 57     ngx_http_geo_ctx_t *ctx);
 58 static in_addr_t ngx_http_geo_real_addr(ngx_http_request_t *r,
 59     ngx_http_geo_ctx_t *ctx);
 60 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 61 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
 62 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
 63     ngx_str_t *value);
 64 static char *ngx_http_geo_add_range(ngx_conf_t *cf,
 65     ngx_http_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end);
 66 static ngx_uint_t ngx_http_geo_delete_range(ngx_conf_t *cf,
 67     ngx_http_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end);
 68 static char *ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
 69     ngx_str_t *value);
 70 static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf,
 71     ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value);
 72 static char *ngx_http_geo_add_proxy(ngx_conf_t *cf,
 73     ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr);
 74 static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
 75     ngx_cidr_t *cidr);
 76 
 77 
 78 static ngx_command_t  ngx_http_geo_commands[] = {
 79 
 80     { ngx_string("geo"),
 81       NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
 82       ngx_http_geo_block,
 83       NGX_HTTP_MAIN_CONF_OFFSET,
 84       0,
 85       NULL },
 86 
 87       ngx_null_command
 88 };
 89 
 90 
 91 static ngx_http_module_t  ngx_http_geo_module_ctx = {
 92     NULL,                                  /* preconfiguration */
 93     NULL,                                  /* postconfiguration */
 94 
 95     NULL,                                  /* create main configuration */
 96     NULL,                                  /* init main configuration */
 97 
 98     NULL,                                  /* create server configuration */
 99     NULL,                                  /* merge server configuration */
100 
101     NULL,                                  /* create location configuration */
102     NULL                                   /* merge location configuration */
103 };
104 
105 
106 ngx_module_t  ngx_http_geo_module = {
107     NGX_MODULE_V1,
108     &ngx_http_geo_module_ctx,              /* module context */
109     ngx_http_geo_commands,                 /* module directives */
110     NGX_HTTP_MODULE,                       /* module type */
111     NULL,                                  /* init master */
112     NULL,                                  /* init module */
113     NULL,                                  /* init process */
114     NULL,                                  /* init thread */
115     NULL,                                  /* exit thread */
116     NULL,                                  /* exit process */
117     NULL,                                  /* exit master */
118     NGX_MODULE_V1_PADDING
119 };
120 
121 
122 /* AF_INET only */
123 
124 static ngx_int_t
125 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
126     uintptr_t data)
127 {
128     ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
129 
130     ngx_http_variable_value_t  *vv;
131 
132     vv = (ngx_http_variable_value_t *)
133               ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx));
134 
135     *v = *vv;
136 
137     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
138                    "http geo: %v", v);
139 
140     return NGX_OK;
141 }
142 
143 
144 static ngx_int_t
145 ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
146     uintptr_t data)
147 {
148     ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data;
149 
150     in_addr_t              addr;
151     ngx_uint_t             i, n;
152     ngx_http_geo_range_t  *range;
153 
154     *v = *ctx->u.high->default_value;
155 
156     addr = ngx_http_geo_addr(r, ctx);
157 
158     range = ctx->u.high->low[addr >> 16].ranges;
159 
160     n = addr & 0xffff;
161 
162     for (i = 0; i < ctx->u.high->low[addr >> 16].n; i++) {
163         if (n >= (ngx_uint_t) range[i].start
164             && n <= (ngx_uint_t) range[i].end)
165         {
166             *v = *range[i].value;
167         }
168     }
169 
170     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
171                    "http geo: %v", v);
172 
173     return NGX_OK;
174 }
175 
176 
177 static in_addr_t
178 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
179 {
180     u_char           *p, *ip;
181     size_t            len;
182     in_addr_t         addr;
183     ngx_uint_t        i, n;
184     ngx_in_cidr_t    *proxies;
185     ngx_table_elt_t  *xfwd;
186 
187     addr = ngx_http_geo_real_addr(r, ctx);
188 
189     xfwd = r->headers_in.x_forwarded_for;
190 
191     if (xfwd == NULL || ctx->proxies == NULL) {
192         return addr;
193     }
194 
195     proxies = ctx->proxies->elts;
196     n = ctx->proxies->nelts;
197 
198     for (i = 0; i < n; i++) {
199         if ((addr & proxies[i].mask) == proxies[i].addr) {
200 
201             len = xfwd->value.len;
202             ip = xfwd->value.data;
203 
204             for (p = ip + len - 1; p > ip; p--) {
205                 if (*p == ' ' || *p == ',') {
206                     p++;
207                     len -= p - ip;
208                     ip = p;
209                     break;
210                 }
211             }
212 
213             return ntohl(ngx_inet_addr(ip, len));
214         }
215     }
216 
217     return addr;
218 }
219 
220 
221 static in_addr_t
222 ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx)
223 {
224     struct sockaddr_in         *sin;
225     ngx_http_variable_value_t  *v;
226 
227     if (ctx->index == -1) {
228         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
229                        "http geo started: %V", &r->connection->addr_text);
230 
231         if (r->connection->sockaddr->sa_family != AF_INET) {
232             return 0;
233         }
234 
235         sin = (struct sockaddr_in *) r->connection->sockaddr;
236         return ntohl(sin->sin_addr.s_addr);
237     }
238 
239     v = ngx_http_get_flushed_variable(r, ctx->index);
240 
241     if (v == NULL || v->not_found) {
242         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
243                        "http geo not found");
244 
245         return 0;
246     }
247 
248     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
249                    "http geo started: %v", v);
250 
251     return ntohl(ngx_inet_addr(v->data, v->len));
252 }
253 
254 
255 static char *
256 ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
257 {
258     char                     *rv;
259     size_t                    len;
260     ngx_str_t                *value, name;
261     ngx_uint_t                i;
262     ngx_conf_t                save;
263     ngx_pool_t               *pool;
264     ngx_array_t              *a;
265     ngx_http_variable_t      *var;
266     ngx_http_geo_ctx_t       *geo;
267     ngx_http_geo_conf_ctx_t   ctx;
268 
269     value = cf->args->elts;
270 
271     geo = ngx_palloc(cf->pool, sizeof(ngx_http_geo_ctx_t));
272     if (geo == NULL) {
273         return NGX_CONF_ERROR;
274     }
275 
276     name = value[1];
277     name.len--;
278     name.data++;
279 
280     if (cf->args->nelts == 3) {
281 
282         geo->index = ngx_http_get_variable_index(cf, &name);
283         if (geo->index == NGX_ERROR) {
284             return NGX_CONF_ERROR;
285         }
286 
287         name = value[2];
288         name.len--;
289         name.data++;
290 
291     } else {
292         geo->index = -1;
293     }
294 
295     var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
296     if (var == NULL) {
297         return NGX_CONF_ERROR;
298     }
299 
300     pool = ngx_create_pool(16384, cf->log);
301     if (pool == NULL) {
302         return NGX_CONF_ERROR;
303     }
304 
305     ctx.temp_pool = ngx_create_pool(16384, cf->log);
306     if (ctx.temp_pool == NULL) {
307         return NGX_CONF_ERROR;
308     }
309 
310     ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel,
311                     ngx_http_variable_value_rbtree_insert);
312 
313     ctx.high = NULL;
314     ctx.tree = NULL;
315     ctx.proxies = NULL;
316     ctx.pool = cf->pool;
317 
318     save = *cf;
319     cf->pool = pool;
320     cf->ctx = &ctx;
321     cf->handler = ngx_http_geo;
322     cf->handler_conf = conf;
323 
324     rv = ngx_conf_parse(cf, NULL);
325 
326     *cf = save;
327 
328     geo->proxies = ctx.proxies;
329 
330     if (ctx.high) {
331 
332         for (i = 0; i < 0x10000; i++) {
333             a = (ngx_array_t *) ctx.high->low[i].ranges;
334 
335             if (a == NULL || a->nelts == 0) {
336                 continue;
337             }
338 
339             ctx.high->low[i].n = a->nelts;
340 
341             len = a->nelts * sizeof(ngx_http_geo_range_t);
342 
343             ctx.high->low[i].ranges = ngx_palloc(cf->pool, len);
344             if (ctx.high->low[i].ranges == NULL ){
345                 return NGX_CONF_ERROR;
346             }
347 
348             ngx_memcpy(ctx.high->low[i].ranges, a->elts, len);
349         }
350 
351         geo->u.high = ctx.high;
352 
353         var->get_handler = ngx_http_geo_range_variable;
354         var->data = (uintptr_t) geo;
355 
356         ngx_destroy_pool(ctx.temp_pool);
357         ngx_destroy_pool(pool);
358 
359         if (ctx.high->default_value == NULL) {
360             ctx.high->default_value = &ngx_http_variable_null_value;
361         }
362 
363     } else {
364         if (ctx.tree == NULL) {
365             ctx.tree = ngx_radix_tree_create(cf->pool, -1);
366             if (ctx.tree == NULL) {
367                 return NGX_CONF_ERROR;
368             }
369         }
370 
371         geo->u.tree = ctx.tree;
372 
373         var->get_handler = ngx_http_geo_cidr_variable;
374         var->data = (uintptr_t) geo;
375 
376         ngx_destroy_pool(ctx.temp_pool);
377         ngx_destroy_pool(pool);
378 
379         if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) {
380             return rv;
381         }
382 
383         if (ngx_radix32tree_insert(ctx.tree, 0, 0,
384                                    (uintptr_t) &ngx_http_variable_null_value)
385             == NGX_ERROR)
386         {
387             return NGX_CONF_ERROR;
388         }
389     }
390 
391     return rv;
392 }
393 
394 
395 static char *
396 ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
397 {
398     char                     *rv;
399     ngx_str_t                *value, file;
400     ngx_cidr_t                cidr;
401     ngx_http_geo_conf_ctx_t  *ctx;
402 
403     ctx = cf->ctx;
404 
405     value = cf->args->elts;
406 
407     if (cf->args->nelts == 1) {
408 
409         if (ngx_strcmp(value[0].data, "ranges") == 0) {
410 
411             if (ctx->tree) {
412                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
413                                    "the \"ranges\" directive must be "
414                                    "the first directive inside \"geo\" block");
415                 goto failed;
416             }
417 
418             ctx->high = ngx_pcalloc(ctx->pool,
419                                     sizeof(ngx_http_geo_high_ranges_t));
420             if (ctx->high == NULL) {
421                 goto failed;
422             }
423 
424             rv = NGX_CONF_OK;
425 
426             goto done;
427         }
428     }
429 
430     if (cf->args->nelts != 2) {
431         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
432                            "invalid number of the geo parameters");
433         goto failed;
434     }
435 
436     if (ngx_strcmp(value[0].data, "include") == 0) {
437 
438         file.len = value[1].len++;
439 
440         file.data = ngx_pstrdup(ctx->temp_pool, &value[1]);
441         if (file.data == NULL) {
442             goto failed;
443         }
444 
445         if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK){
446             goto failed;
447         }
448 
449         ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
450 
451         rv = ngx_conf_parse(cf, &file);
452 
453         goto done;
454 
455     } else if (ngx_strcmp(value[0].data, "proxy") == 0) {
456 
457         if (ngx_http_geo_cidr_value(cf, &value[1], &cidr) != NGX_OK) {
458             goto failed;
459         }
460 
461         rv = ngx_http_geo_add_proxy(cf, ctx, &cidr);
462 
463         goto done;
464     }
465 
466     if (ctx->high) {
467         rv = ngx_http_geo_range(cf, ctx, value);
468 
469     } else {
470         rv = ngx_http_geo_cidr(cf, ctx, value);
471     }
472 
473 done:
474 
475     ngx_reset_pool(cf->pool);
476 
477     return rv;
478 
479 failed:
480 
481     ngx_reset_pool(cf->pool);
482 
483     return NGX_CONF_ERROR;
484 }
485 
486 
487 static char *
488 ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
489     ngx_str_t *value)
490 {
491     u_char                     *p, *last;
492     in_addr_t                   start, end;
493     ngx_str_t                  *net;
494     ngx_uint_t                  del;
495     ngx_http_variable_value_t  *old;
496 
497     if (ngx_strcmp(value[0].data, "default") == 0) {
498 
499         old = ctx->high->default_value;
500 
501         ctx->high->default_value = ngx_http_geo_value(cf, ctx, &value[1]);
502         if (ctx->high->default_value == NULL) {
503             return NGX_CONF_ERROR;
504         }
505 
506         if (old) {
507             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
508                     "duplicate range \"%V\", value: \"%v\", old value: \"%v\"",
509                     &value[0], ctx->high->default_value, old);
510         }
511 
512         return NGX_CONF_OK;
513     }
514 
515     if (ngx_strcmp(value[0].data, "delete") == 0) {
516         net = &value[1];
517         del = 1;
518 
519     } else {
520         net = &value[0];
521         del = 0;
522     }
523 
524     last = net->data + net->len;
525 
526     p = ngx_strlchr(net->data, last, '-');
527 
528     if (p == NULL) {
529         goto invalid;
530     }
531 
532     start = ngx_inet_addr(net->data, p - net->data);
533 
534     if (start == INADDR_NONE) {
535         goto invalid;
536     }
537 
538     start = ntohl(start);
539 
540     p++;
541 
542     end = ngx_inet_addr(p, last - p);
543 
544     if (end == INADDR_NONE) {
545         goto invalid;
546     }
547 
548     end = ntohl(end);
549 
550     if (start > end) {
551         goto invalid;
552     }
553 
554     if (del) {
555         if (ngx_http_geo_delete_range(cf, ctx, start, end)) {
556             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
557                                "no address range \"%V\" to delete", net);
558         }
559 
560         return NGX_CONF_OK;
561     }
562 
563     ctx->value = ngx_http_geo_value(cf, ctx, &value[1]);
564 
565     if (ctx->value == NULL) {
566         return NGX_CONF_ERROR;
567     }
568 
569     ctx->net = net;
570 
571     return ngx_http_geo_add_range(cf, ctx, start, end);
572 
573 invalid:
574 
575     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid range \"%V\"", net);
576 
577     return NGX_CONF_ERROR;
578 }
579 
580 
581 /* the add procedure is optimized to add a growing up sequence */
582 
583 static char *
584 ngx_http_geo_add_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
585     in_addr_t start, in_addr_t end)
586 {
587     in_addr_t              n;
588     ngx_uint_t             h, i, s, e;
589     ngx_array_t           *a;
590     ngx_http_geo_range_t  *range;
591 
592     for (n = start; n <= end; n += 0x10000) {
593 
594         h = n >> 16;
595 
596         if (n == start) {
597             s = n & 0xffff;
598         } else {
599             s = 0;
600         }
601 
602         if ((n | 0xffff) > end) {
603             e = end & 0xffff;
604 
605         } else {
606             e = 0xffff;
607         }
608 
609         a = (ngx_array_t *) ctx->high->low[h].ranges;
610 
611         if (a == NULL) {
612             a = ngx_array_create(ctx->temp_pool, 64,
613                                  sizeof(ngx_http_geo_range_t));
614             if (a == NULL) {
615                 return NGX_CONF_ERROR;
616             }
617 
618             ctx->high->low[h].ranges = (ngx_http_geo_range_t *) a;
619         }
620 
621         i = a->nelts;
622         range = a->elts;
623 
624         while (i) {
625 
626             i--;
627 
628             if (e < (ngx_uint_t) range[i].start) {
629                 continue;
630             }
631 
632             if (s > (ngx_uint_t) range[i].end) {
633 
634                 /* add after the range */
635 
636                 range = ngx_array_push(a);
637                 if (range == NULL) {
638                     return NGX_CONF_ERROR;
639                 }
640 
641                 range = a->elts;
642 
643                 ngx_memcpy(&range[i + 2], &range[i + 1],
644                            (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t));
645 
646                 range[i + 1].start = (u_short) s;
647                 range[i + 1].end = (u_short) e;
648                 range[i + 1].value = ctx->value;
649 
650                 goto next;
651             }
652 
653             if (s == (ngx_uint_t) range[i].start
654                 && e == (ngx_uint_t) range[i].end)
655             {
656                 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
657                     "duplicate range \"%V\", value: \"%v\", old value: \"%v\"",
658                     ctx->net, ctx->value, range[i].value);
659 
660                 range[i].value = ctx->value;
661 
662                 goto next;
663             }
664 
665             if (s > (ngx_uint_t) range[i].start
666                 && e < (ngx_uint_t) range[i].end)
667             {
668                 /* split the range and insert the new one */
669 
670                 range = ngx_array_push(a);
671                 if (range == NULL) {
672                     return NGX_CONF_ERROR;
673                 }
674 
675                 range = ngx_array_push(a);
676                 if (range == NULL) {
677                     return NGX_CONF_ERROR;
678                 }
679 
680                 range = a->elts;
681 
682                 ngx_memcpy(&range[i + 3], &range[i + 1],
683                            (a->nelts - 3 - i) * sizeof(ngx_http_geo_range_t));
684 
685                 range[i + 2].start = (u_short) (e + 1);
686                 range[i + 2].end = range[i].end;
687                 range[i + 2].value = range[i].value;
688 
689                 range[i + 1].start = (u_short) s;
690                 range[i + 1].end = (u_short) e;
691                 range[i + 1].value = ctx->value;
692 
693                 range[i].end = (u_short) (s - 1);
694 
695                 goto next;
696             }
697 
698             if (s == (ngx_uint_t) range[i].start
699                 && e < (ngx_uint_t) range[i].end)
700             {
701                 /* shift the range start and insert the new range */
702 
703                 range = ngx_array_push(a);
704                 if (range == NULL) {
705                     return NGX_CONF_ERROR;
706                 }
707 
708                 range = a->elts;
709 
710                 ngx_memcpy(&range[i + 1], &range[i],
711                            (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t));
712 
713                 range[i + 1].start = (u_short) (e + 1);
714 
715                 range[i].start = (u_short) s;
716                 range[i].end = (u_short) e;
717                 range[i].value = ctx->value;
718 
719                 goto next;
720             }
721 
722             if (s > (ngx_uint_t) range[i].start
723                 && e == (ngx_uint_t) range[i].end)
724             {
725                 /* shift the range end and insert the new range */
726 
727                 range = ngx_array_push(a);
728                 if (range == NULL) {
729                     return NGX_CONF_ERROR;
730                 }
731 
732                 range = a->elts;
733 
734                 ngx_memcpy(&range[i + 2], &range[i + 1],
735                            (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t));
736 
737                 range[i + 1].start = (u_short) s;
738                 range[i + 1].end = (u_short) e;
739                 range[i + 1].value = ctx->value;
740 
741                 range[i].end = (u_short) (s - 1);
742 
743                 goto next;
744             }
745 
746             s = (ngx_uint_t) range[i].start;
747             e = (ngx_uint_t) range[i].end;
748 
749             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
750                          "range \"%V\" overlaps \"%d.%d.%d.%d-%d.%d.%d.%d\"",
751                          ctx->net,
752                          h >> 8, h & 0xff, s >> 8, s & 0xff,
753                          h >> 8, h & 0xff, e >> 8, e & 0xff);
754 
755             return NGX_CONF_ERROR;
756         }
757 
758         /* add the first range */
759 
760         range = ngx_array_push(a);
761         if (range == NULL) {
762             return NGX_CONF_ERROR;
763         }
764 
765         range->start = (u_short) s;
766         range->end = (u_short) e;
767         range->value = ctx->value;
768 
769     next:
770 
771         continue;
772     }
773 
774     return NGX_CONF_OK;
775 }
776 
777 
778 static ngx_uint_t
779 ngx_http_geo_delete_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
780     in_addr_t start, in_addr_t end)
781 {
782     in_addr_t              n;
783     ngx_uint_t             h, i, s, e, warn;
784     ngx_array_t           *a;
785     ngx_http_geo_range_t  *range;
786 
787     warn = 0;
788 
789     for (n = start; n <= end; n += 0x10000) {
790 
791         h = n >> 16;
792 
793         if (n == start) {
794             s = n & 0xffff;
795         } else {
796             s = 0;
797         }
798 
799         if ((n | 0xffff) > end) {
800             e = end & 0xffff;
801 
802         } else {
803             e = 0xffff;
804         }
805 
806         a = (ngx_array_t *) ctx->high->low[h].ranges;
807 
808         if (a == NULL) {
809             warn = 1;
810             continue;
811         }
812 
813         range = a->elts;
814         for (i = 0; i < a->nelts; i++) {
815 
816             if (s == (ngx_uint_t) range[i].start
817                 && e == (ngx_uint_t) range[i].end)
818             {
819                 ngx_memcpy(&range[i], &range[i + 1],
820                            (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t));
821 
822                 a->nelts--;
823 
824                 break;
825             }
826 
827             if (s != (ngx_uint_t) range[i].start
828                 && e != (ngx_uint_t) range[i].end)
829             {
830                 continue;
831             }
832 
833             warn = 1;
834         }
835     }
836 
837     return warn;
838 }
839 
840 
841 static char *
842 ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
843     ngx_str_t *value)
844 {
845     ngx_int_t                        rc, del;
846     ngx_str_t                       *net;
847     ngx_uint_t                       i;
848     ngx_cidr_t                       cidr;
849     ngx_http_variable_value_t       *val, *old;
850 
851     if (ctx->tree == NULL) {
852         ctx->tree = ngx_radix_tree_create(ctx->pool, -1);
853         if (ctx->tree == NULL) {
854             return NGX_CONF_ERROR;
855         }
856     }
857 
858     if (ngx_strcmp(value[0].data, "default") == 0) {
859         cidr.u.in.addr = 0;
860         cidr.u.in.mask = 0;
861         net = &value[0];
862 
863     } else {
864         if (ngx_strcmp(value[0].data, "delete") == 0) {
865             net = &value[1];
866             del = 1;
867 
868         } else {
869             net = &value[0];
870             del = 0;
871         }
872 
873         if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) {
874             return NGX_CONF_ERROR;
875         }
876 
877         if (del) {
878             if (ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr,
879                                        cidr.u.in.mask)
880                 != NGX_OK)
881             {
882                 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
883                                    "no network \"%V\" to delete", net);
884             }
885 
886             return NGX_CONF_OK;
887         }
888     }
889 
890     val = ngx_http_geo_value(cf, ctx, &value[1]);
891 
892     if (val == NULL) {
893         return NGX_CONF_ERROR;
894     }
895 
896     for (i = 2; i; i--) {
897         rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, cidr.u.in.mask,
898                                     (uintptr_t) val);
899         if (rc == NGX_OK) {
900             return NGX_CONF_OK;
901         }
902 
903         if (rc == NGX_ERROR) {
904             return NGX_CONF_ERROR;
905         }
906 
907         /* rc == NGX_BUSY */
908 
909         old = (ngx_http_variable_value_t *)
910               ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask);
911 
912         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
913                 "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
914                 net, val, old);
915 
916         rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, cidr.u.in.mask);
917 
918         if (rc == NGX_ERROR) {
919             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
920             return NGX_CONF_ERROR;
921         }
922     }
923 
924     return NGX_CONF_ERROR;
925 }
926 
927 
928 static ngx_http_variable_value_t *
929 ngx_http_geo_value(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
930     ngx_str_t *value)
931 {
932     uint32_t                         hash;
933     ngx_http_variable_value_t       *val;
934     ngx_http_variable_value_node_t  *vvn;
935 
936     hash = ngx_crc32_long(value->data, value->len);
937 
938     val = ngx_http_variable_value_lookup(&ctx->rbtree, value, hash);
939 
940     if (val) {
941         return val;
942     }
943 
944     val = ngx_palloc(ctx->pool, sizeof(ngx_http_variable_value_t));
945     if (val == NULL) {
946         return NULL;
947     }
948 
949     val->len = value->len;
950     val->data = ngx_pstrdup(ctx->pool, value);
951     if (val->data == NULL) {
952         return NULL;
953     }
954 
955     val->valid = 1;
956     val->no_cacheable = 0;
957     val->not_found = 0;
958 
959     vvn = ngx_palloc(ctx->temp_pool, sizeof(ngx_http_variable_value_node_t));
960     if (vvn == NULL) {
961         return NULL;
962     }
963 
964     vvn->node.key = hash;
965     vvn->len = val->len;
966     vvn->value = val;
967 
968     ngx_rbtree_insert(&ctx->rbtree, &vvn->node);
969 
970     return val;
971 }
972 
973 
974 static char *
975 ngx_http_geo_add_proxy(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx,
976     ngx_cidr_t *cidr)
977 {
978     ngx_in_cidr_t  *c;
979 
980     if (ctx->proxies == NULL) {
981         ctx->proxies = ngx_array_create(ctx->pool, 4, sizeof(ngx_in_cidr_t));
982         if (ctx->proxies == NULL) {
983             return NGX_CONF_ERROR;
984         }
985     }
986 
987     c = ngx_array_push(ctx->proxies);
988     if (c == NULL) {
989         return NGX_CONF_ERROR;
990     }
991 
992     c->addr = cidr->u.in.addr;
993     c->mask = cidr->u.in.mask;
994 
995     return NGX_CONF_OK;
996 }
997 
998 
999 static ngx_int_t
1000 ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
1001 {
1002     ngx_int_t  rc;
1003 
1004     if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
1005         cidr->u.in.addr = 0xffffffff;
1006         cidr->u.in.mask = 0xffffffff;
1007 
1008         return NGX_OK;
1009     }
1010 
1011     rc = ngx_ptocidr(net, cidr);
1012 
1013     if (rc == NGX_ERROR) {
1014         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
1015         return NGX_ERROR;
1016     }
1017 
1018     if (cidr->family != AF_INET) {
1019         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"geo\" supports IPv4 only");
1020         return NGX_ERROR;
1021     }
1022 
1023     if (rc == NGX_DONE) {
1024         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
1025                            "low address bits of %V are meaningless", net);
1026     }
1027 
1028     cidr->u.in.addr = ntohl(cidr->u.in.addr);
1029     cidr->u.in.mask = ntohl(cidr->u.in.mask);
1030 
1031     return NGX_OK;
1032 }
1033 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.