aboutsummaryrefslogtreecommitdiffstats
path: root/nginx/src/stream/ngx_stream_geo_module.c
diff options
context:
space:
mode:
Diffstat (limited to 'nginx/src/stream/ngx_stream_geo_module.c')
-rw-r--r--nginx/src/stream/ngx_stream_geo_module.c1596
1 files changed, 0 insertions, 1596 deletions
diff --git a/nginx/src/stream/ngx_stream_geo_module.c b/nginx/src/stream/ngx_stream_geo_module.c
deleted file mode 100644
index 83f7fb4..0000000
--- a/nginx/src/stream/ngx_stream_geo_module.c
+++ /dev/null
@@ -1,1596 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- * Copyright (C) Nginx, Inc.
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_stream.h>
-
-
-typedef struct {
- ngx_stream_variable_value_t *value;
- u_short start;
- u_short end;
-} ngx_stream_geo_range_t;
-
-
-typedef struct {
- ngx_radix_tree_t *tree;
-#if (NGX_HAVE_INET6)
- ngx_radix_tree_t *tree6;
-#endif
-} ngx_stream_geo_trees_t;
-
-
-typedef struct {
- ngx_stream_geo_range_t **low;
- ngx_stream_variable_value_t *default_value;
-} ngx_stream_geo_high_ranges_t;
-
-
-typedef struct {
- ngx_str_node_t sn;
- ngx_stream_variable_value_t *value;
- size_t offset;
-} ngx_stream_geo_variable_value_node_t;
-
-
-typedef struct {
- ngx_stream_variable_value_t *value;
- ngx_str_t *net;
- ngx_stream_geo_high_ranges_t high;
- ngx_radix_tree_t *tree;
-#if (NGX_HAVE_INET6)
- ngx_radix_tree_t *tree6;
-#endif
- ngx_rbtree_t rbtree;
- ngx_rbtree_node_t sentinel;
- ngx_pool_t *pool;
- ngx_pool_t *temp_pool;
-
- size_t data_size;
-
- ngx_str_t include_name;
- ngx_uint_t includes;
- ngx_uint_t entries;
-
- unsigned ranges:1;
- unsigned outside_entries:1;
- unsigned allow_binary_include:1;
- unsigned binary_include:1;
-} ngx_stream_geo_conf_ctx_t;
-
-
-typedef struct {
- union {
- ngx_stream_geo_trees_t trees;
- ngx_stream_geo_high_ranges_t high;
- } u;
-
- ngx_int_t index;
-} ngx_stream_geo_ctx_t;
-
-
-static ngx_int_t ngx_stream_geo_addr(ngx_stream_session_t *s,
- ngx_stream_geo_ctx_t *ctx, ngx_addr_t *addr);
-
-static char *ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf);
-static char *ngx_stream_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
-static char *ngx_stream_geo_range(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value);
-static char *ngx_stream_geo_add_range(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end);
-static ngx_uint_t ngx_stream_geo_delete_range(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end);
-static char *ngx_stream_geo_cidr(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value);
-static char *ngx_stream_geo_cidr_add(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr, ngx_str_t *value,
- ngx_str_t *net);
-static ngx_stream_variable_value_t *ngx_stream_geo_value(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *value);
-static ngx_int_t ngx_stream_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net,
- ngx_cidr_t *cidr);
-static char *ngx_stream_geo_include(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name);
-static ngx_int_t ngx_stream_geo_include_binary_base(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name);
-static void ngx_stream_geo_create_binary_base(ngx_stream_geo_conf_ctx_t *ctx);
-static u_char *ngx_stream_geo_copy_values(u_char *base, u_char *p,
- ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
-
-
-static ngx_command_t ngx_stream_geo_commands[] = {
-
- { ngx_string("geo"),
- NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
- ngx_stream_geo_block,
- 0,
- 0,
- NULL },
-
- ngx_null_command
-};
-
-
-static ngx_stream_module_t ngx_stream_geo_module_ctx = {
- NULL, /* preconfiguration */
- NULL, /* postconfiguration */
-
- NULL, /* create main configuration */
- NULL, /* init main configuration */
-
- NULL, /* create server configuration */
- NULL /* merge server configuration */
-};
-
-
-ngx_module_t ngx_stream_geo_module = {
- NGX_MODULE_V1,
- &ngx_stream_geo_module_ctx, /* module context */
- ngx_stream_geo_commands, /* module directives */
- NGX_STREAM_MODULE, /* module type */
- NULL, /* init master */
- NULL, /* init module */
- NULL, /* init process */
- NULL, /* init thread */
- NULL, /* exit thread */
- NULL, /* exit process */
- NULL, /* exit master */
- NGX_MODULE_V1_PADDING
-};
-
-
-typedef struct {
- u_char GEORNG[6];
- u_char version;
- u_char ptr_size;
- uint32_t endianness;
- uint32_t crc32;
-} ngx_stream_geo_header_t;
-
-
-static ngx_stream_geo_header_t ngx_stream_geo_header = {
- { 'G', 'E', 'O', 'R', 'N', 'G' }, 0, sizeof(void *), 0x12345678, 0
-};
-
-
-/* geo range is AF_INET only */
-
-static ngx_int_t
-ngx_stream_geo_cidr_variable(ngx_stream_session_t *s,
- ngx_stream_variable_value_t *v, uintptr_t data)
-{
- ngx_stream_geo_ctx_t *ctx = (ngx_stream_geo_ctx_t *) data;
-
- in_addr_t inaddr;
- ngx_addr_t addr;
- struct sockaddr_in *sin;
- ngx_stream_variable_value_t *vv;
-#if (NGX_HAVE_INET6)
- u_char *p;
- struct in6_addr *inaddr6;
-#endif
-
- if (ngx_stream_geo_addr(s, ctx, &addr) != NGX_OK) {
- vv = (ngx_stream_variable_value_t *)
- ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE);
- goto done;
- }
-
- switch (addr.sockaddr->sa_family) {
-
-#if (NGX_HAVE_INET6)
- case AF_INET6:
- inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
- p = inaddr6->s6_addr;
-
- if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
- inaddr = p[12] << 24;
- inaddr += p[13] << 16;
- inaddr += p[14] << 8;
- inaddr += p[15];
-
- vv = (ngx_stream_variable_value_t *)
- ngx_radix32tree_find(ctx->u.trees.tree, inaddr);
-
- } else {
- vv = (ngx_stream_variable_value_t *)
- ngx_radix128tree_find(ctx->u.trees.tree6, p);
- }
-
- break;
-#endif
-
- default: /* AF_INET */
- sin = (struct sockaddr_in *) addr.sockaddr;
- inaddr = ntohl(sin->sin_addr.s_addr);
-
- vv = (ngx_stream_variable_value_t *)
- ngx_radix32tree_find(ctx->u.trees.tree, inaddr);
-
- break;
- }
-
-done:
-
- *v = *vv;
-
- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
- "stream geo: %v", v);
-
- return NGX_OK;
-}
-
-
-static ngx_int_t
-ngx_stream_geo_range_variable(ngx_stream_session_t *s,
- ngx_stream_variable_value_t *v, uintptr_t data)
-{
- ngx_stream_geo_ctx_t *ctx = (ngx_stream_geo_ctx_t *) data;
-
- in_addr_t inaddr;
- ngx_addr_t addr;
- ngx_uint_t n;
- struct sockaddr_in *sin;
- ngx_stream_geo_range_t *range;
-#if (NGX_HAVE_INET6)
- u_char *p;
- struct in6_addr *inaddr6;
-#endif
-
- *v = *ctx->u.high.default_value;
-
- if (ngx_stream_geo_addr(s, ctx, &addr) == NGX_OK) {
-
- switch (addr.sockaddr->sa_family) {
-
-#if (NGX_HAVE_INET6)
- case AF_INET6:
- inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr;
-
- if (IN6_IS_ADDR_V4MAPPED(inaddr6)) {
- p = inaddr6->s6_addr;
-
- inaddr = p[12] << 24;
- inaddr += p[13] << 16;
- inaddr += p[14] << 8;
- inaddr += p[15];
-
- } else {
- inaddr = INADDR_NONE;
- }
-
- break;
-#endif
-
- default: /* AF_INET */
- sin = (struct sockaddr_in *) addr.sockaddr;
- inaddr = ntohl(sin->sin_addr.s_addr);
- break;
- }
-
- } else {
- inaddr = INADDR_NONE;
- }
-
- if (ctx->u.high.low) {
- range = ctx->u.high.low[inaddr >> 16];
-
- if (range) {
- n = inaddr & 0xffff;
- do {
- if (n >= (ngx_uint_t) range->start
- && n <= (ngx_uint_t) range->end)
- {
- *v = *range->value;
- break;
- }
- } while ((++range)->value);
- }
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
- "stream geo: %v", v);
-
- return NGX_OK;
-}
-
-
-static ngx_int_t
-ngx_stream_geo_addr(ngx_stream_session_t *s, ngx_stream_geo_ctx_t *ctx,
- ngx_addr_t *addr)
-{
- ngx_stream_variable_value_t *v;
-
- if (ctx->index == -1) {
- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
- "stream geo started: %V", &s->connection->addr_text);
-
- addr->sockaddr = s->connection->sockaddr;
- addr->socklen = s->connection->socklen;
- /* addr->name = s->connection->addr_text; */
-
- return NGX_OK;
- }
-
- v = ngx_stream_get_flushed_variable(s, ctx->index);
-
- if (v == NULL || v->not_found) {
- ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
- "stream geo not found");
-
- return NGX_ERROR;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
- "stream geo started: %v", v);
-
- if (ngx_parse_addr(s->connection->pool, addr, v->data, v->len) == NGX_OK) {
- return NGX_OK;
- }
-
- return NGX_ERROR;
-}
-
-
-static char *
-ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
- char *rv;
- size_t len;
- ngx_str_t *value, name;
- ngx_uint_t i;
- ngx_conf_t save;
- ngx_pool_t *pool;
- ngx_array_t *a;
- ngx_stream_variable_t *var;
- ngx_stream_geo_ctx_t *geo;
- ngx_stream_geo_conf_ctx_t ctx;
-#if (NGX_HAVE_INET6)
- static struct in6_addr zero;
-#endif
-
- value = cf->args->elts;
-
- geo = ngx_palloc(cf->pool, sizeof(ngx_stream_geo_ctx_t));
- if (geo == NULL) {
- return NGX_CONF_ERROR;
- }
-
- name = value[1];
-
- if (name.data[0] != '$') {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid variable name \"%V\"", &name);
- return NGX_CONF_ERROR;
- }
-
- name.len--;
- name.data++;
-
- if (cf->args->nelts == 3) {
-
- geo->index = ngx_stream_get_variable_index(cf, &name);
- if (geo->index == NGX_ERROR) {
- return NGX_CONF_ERROR;
- }
-
- name = value[2];
-
- if (name.data[0] != '$') {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid variable name \"%V\"", &name);
- return NGX_CONF_ERROR;
- }
-
- name.len--;
- name.data++;
-
- } else {
- geo->index = -1;
- }
-
- var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE);
- if (var == NULL) {
- return NGX_CONF_ERROR;
- }
-
- pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
- if (pool == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ngx_memzero(&ctx, sizeof(ngx_stream_geo_conf_ctx_t));
-
- ctx.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
- if (ctx.temp_pool == NULL) {
- ngx_destroy_pool(pool);
- return NGX_CONF_ERROR;
- }
-
- ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel, ngx_str_rbtree_insert_value);
-
- ctx.pool = cf->pool;
- ctx.data_size = sizeof(ngx_stream_geo_header_t)
- + sizeof(ngx_stream_variable_value_t)
- + 0x10000 * sizeof(ngx_stream_geo_range_t *);
- ctx.allow_binary_include = 1;
-
- save = *cf;
- cf->pool = pool;
- cf->ctx = &ctx;
- cf->handler = ngx_stream_geo;
- cf->handler_conf = conf;
-
- rv = ngx_conf_parse(cf, NULL);
-
- *cf = save;
-
- if (rv != NGX_CONF_OK) {
- goto failed;
- }
-
- if (ctx.ranges) {
-
- if (ctx.high.low && !ctx.binary_include) {
- for (i = 0; i < 0x10000; i++) {
- a = (ngx_array_t *) ctx.high.low[i];
-
- if (a == NULL) {
- continue;
- }
-
- if (a->nelts == 0) {
- ctx.high.low[i] = NULL;
- continue;
- }
-
- len = a->nelts * sizeof(ngx_stream_geo_range_t);
-
- ctx.high.low[i] = ngx_palloc(cf->pool, len + sizeof(void *));
- if (ctx.high.low[i] == NULL) {
- goto failed;
- }
-
- ngx_memcpy(ctx.high.low[i], a->elts, len);
- ctx.high.low[i][a->nelts].value = NULL;
- ctx.data_size += len + sizeof(void *);
- }
-
- if (ctx.allow_binary_include
- && !ctx.outside_entries
- && ctx.entries > 100000
- && ctx.includes == 1)
- {
- ngx_stream_geo_create_binary_base(&ctx);
- }
- }
-
- if (ctx.high.default_value == NULL) {
- ctx.high.default_value = &ngx_stream_variable_null_value;
- }
-
- geo->u.high = ctx.high;
-
- var->get_handler = ngx_stream_geo_range_variable;
- var->data = (uintptr_t) geo;
-
- } else {
- if (ctx.tree == NULL) {
- ctx.tree = ngx_radix_tree_create(cf->pool, -1);
- if (ctx.tree == NULL) {
- goto failed;
- }
- }
-
- geo->u.trees.tree = ctx.tree;
-
-#if (NGX_HAVE_INET6)
- if (ctx.tree6 == NULL) {
- ctx.tree6 = ngx_radix_tree_create(cf->pool, -1);
- if (ctx.tree6 == NULL) {
- goto failed;
- }
- }
-
- geo->u.trees.tree6 = ctx.tree6;
-#endif
-
- var->get_handler = ngx_stream_geo_cidr_variable;
- var->data = (uintptr_t) geo;
-
- if (ngx_radix32tree_insert(ctx.tree, 0, 0,
- (uintptr_t) &ngx_stream_variable_null_value)
- == NGX_ERROR)
- {
- goto failed;
- }
-
- /* NGX_BUSY is okay (default was set explicitly) */
-
-#if (NGX_HAVE_INET6)
- if (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr,
- (uintptr_t) &ngx_stream_variable_null_value)
- == NGX_ERROR)
- {
- goto failed;
- }
-#endif
- }
-
- ngx_destroy_pool(ctx.temp_pool);
- ngx_destroy_pool(pool);
-
- return NGX_CONF_OK;
-
-failed:
-
- ngx_destroy_pool(ctx.temp_pool);
- ngx_destroy_pool(pool);
-
- return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_stream_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
-{
- char *rv;
- ngx_str_t *value;
- ngx_stream_geo_conf_ctx_t *ctx;
-
- ctx = cf->ctx;
-
- value = cf->args->elts;
-
- if (cf->args->nelts == 1) {
-
- if (ngx_strcmp(value[0].data, "ranges") == 0) {
-
- if (ctx->tree
-#if (NGX_HAVE_INET6)
- || ctx->tree6
-#endif
- )
- {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "the \"ranges\" directive must be "
- "the first directive inside \"geo\" block");
- goto failed;
- }
-
- ctx->ranges = 1;
-
- rv = NGX_CONF_OK;
-
- goto done;
- }
- }
-
- if (cf->args->nelts != 2) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid number of the geo parameters");
- goto failed;
- }
-
- if (ngx_strcmp(value[0].data, "include") == 0) {
-
- rv = ngx_stream_geo_include(cf, ctx, &value[1]);
-
- goto done;
- }
-
- if (ctx->ranges) {
- rv = ngx_stream_geo_range(cf, ctx, value);
-
- } else {
- rv = ngx_stream_geo_cidr(cf, ctx, value);
- }
-
-done:
-
- ngx_reset_pool(cf->pool);
-
- return rv;
-
-failed:
-
- ngx_reset_pool(cf->pool);
-
- return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_stream_geo_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx,
- ngx_str_t *value)
-{
- u_char *p, *last;
- in_addr_t start, end;
- ngx_str_t *net;
- ngx_uint_t del;
-
- if (ngx_strcmp(value[0].data, "default") == 0) {
-
- if (ctx->high.default_value) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "duplicate default geo range value: \"%V\", old value: \"%v\"",
- &value[1], ctx->high.default_value);
- }
-
- ctx->high.default_value = ngx_stream_geo_value(cf, ctx, &value[1]);
- if (ctx->high.default_value == NULL) {
- return NGX_CONF_ERROR;
- }
-
- return NGX_CONF_OK;
- }
-
- if (ctx->binary_include) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "binary geo range base \"%s\" cannot be mixed with usual entries",
- ctx->include_name.data);
- return NGX_CONF_ERROR;
- }
-
- if (ctx->high.low == NULL) {
- ctx->high.low = ngx_pcalloc(ctx->pool,
- 0x10000 * sizeof(ngx_stream_geo_range_t *));
- if (ctx->high.low == NULL) {
- return NGX_CONF_ERROR;
- }
- }
-
- ctx->entries++;
- ctx->outside_entries = 1;
-
- if (ngx_strcmp(value[0].data, "delete") == 0) {
- net = &value[1];
- del = 1;
-
- } else {
- net = &value[0];
- del = 0;
- }
-
- last = net->data + net->len;
-
- p = ngx_strlchr(net->data, last, '-');
-
- if (p == NULL) {
- goto invalid;
- }
-
- start = ngx_inet_addr(net->data, p - net->data);
-
- if (start == INADDR_NONE) {
- goto invalid;
- }
-
- start = ntohl(start);
-
- p++;
-
- end = ngx_inet_addr(p, last - p);
-
- if (end == INADDR_NONE) {
- goto invalid;
- }
-
- end = ntohl(end);
-
- if (start > end) {
- goto invalid;
- }
-
- if (del) {
- if (ngx_stream_geo_delete_range(cf, ctx, start, end)) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "no address range \"%V\" to delete", net);
- }
-
- return NGX_CONF_OK;
- }
-
- ctx->value = ngx_stream_geo_value(cf, ctx, &value[1]);
-
- if (ctx->value == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ctx->net = net;
-
- return ngx_stream_geo_add_range(cf, ctx, start, end);
-
-invalid:
-
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid range \"%V\"", net);
-
- return NGX_CONF_ERROR;
-}
-
-
-/* the add procedure is optimized to add a growing up sequence */
-
-static char *
-ngx_stream_geo_add_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx,
- in_addr_t start, in_addr_t end)
-{
- in_addr_t n;
- ngx_uint_t h, i, s, e;
- ngx_array_t *a;
- ngx_stream_geo_range_t *range;
-
- for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) {
-
- h = n >> 16;
-
- if (n == start) {
- s = n & 0xffff;
- } else {
- s = 0;
- }
-
- if ((n | 0xffff) > end) {
- e = end & 0xffff;
-
- } else {
- e = 0xffff;
- }
-
- a = (ngx_array_t *) ctx->high.low[h];
-
- if (a == NULL) {
- a = ngx_array_create(ctx->temp_pool, 64,
- sizeof(ngx_stream_geo_range_t));
- if (a == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ctx->high.low[h] = (ngx_stream_geo_range_t *) a;
- }
-
- i = a->nelts;
- range = a->elts;
-
- while (i) {
-
- i--;
-
- if (e < (ngx_uint_t) range[i].start) {
- continue;
- }
-
- if (s > (ngx_uint_t) range[i].end) {
-
- /* add after the range */
-
- range = ngx_array_push(a);
- if (range == NULL) {
- return NGX_CONF_ERROR;
- }
-
- range = a->elts;
-
- ngx_memmove(&range[i + 2], &range[i + 1],
- (a->nelts - 2 - i) * sizeof(ngx_stream_geo_range_t));
-
- range[i + 1].start = (u_short) s;
- range[i + 1].end = (u_short) e;
- range[i + 1].value = ctx->value;
-
- goto next;
- }
-
- if (s == (ngx_uint_t) range[i].start
- && e == (ngx_uint_t) range[i].end)
- {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "duplicate range \"%V\", value: \"%v\", old value: \"%v\"",
- ctx->net, ctx->value, range[i].value);
-
- range[i].value = ctx->value;
-
- goto next;
- }
-
- if (s > (ngx_uint_t) range[i].start
- && e < (ngx_uint_t) range[i].end)
- {
- /* split the range and insert the new one */
-
- range = ngx_array_push(a);
- if (range == NULL) {
- return NGX_CONF_ERROR;
- }
-
- range = ngx_array_push(a);
- if (range == NULL) {
- return NGX_CONF_ERROR;
- }
-
- range = a->elts;
-
- ngx_memmove(&range[i + 3], &range[i + 1],
- (a->nelts - 3 - i) * sizeof(ngx_stream_geo_range_t));
-
- range[i + 2].start = (u_short) (e + 1);
- range[i + 2].end = range[i].end;
- range[i + 2].value = range[i].value;
-
- range[i + 1].start = (u_short) s;
- range[i + 1].end = (u_short) e;
- range[i + 1].value = ctx->value;
-
- range[i].end = (u_short) (s - 1);
-
- goto next;
- }
-
- if (s == (ngx_uint_t) range[i].start
- && e < (ngx_uint_t) range[i].end)
- {
- /* shift the range start and insert the new range */
-
- range = ngx_array_push(a);
- if (range == NULL) {
- return NGX_CONF_ERROR;
- }
-
- range = a->elts;
-
- ngx_memmove(&range[i + 1], &range[i],
- (a->nelts - 1 - i) * sizeof(ngx_stream_geo_range_t));
-
- range[i + 1].start = (u_short) (e + 1);
-
- range[i].start = (u_short) s;
- range[i].end = (u_short) e;
- range[i].value = ctx->value;
-
- goto next;
- }
-
- if (s > (ngx_uint_t) range[i].start
- && e == (ngx_uint_t) range[i].end)
- {
- /* shift the range end and insert the new range */
-
- range = ngx_array_push(a);
- if (range == NULL) {
- return NGX_CONF_ERROR;
- }
-
- range = a->elts;
-
- ngx_memmove(&range[i + 2], &range[i + 1],
- (a->nelts - 2 - i) * sizeof(ngx_stream_geo_range_t));
-
- range[i + 1].start = (u_short) s;
- range[i + 1].end = (u_short) e;
- range[i + 1].value = ctx->value;
-
- range[i].end = (u_short) (s - 1);
-
- goto next;
- }
-
- s = (ngx_uint_t) range[i].start;
- e = (ngx_uint_t) range[i].end;
-
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "range \"%V\" overlaps \"%d.%d.%d.%d-%d.%d.%d.%d\"",
- ctx->net,
- h >> 8, h & 0xff, s >> 8, s & 0xff,
- h >> 8, h & 0xff, e >> 8, e & 0xff);
-
- return NGX_CONF_ERROR;
- }
-
- /* add the first range */
-
- range = ngx_array_push(a);
- if (range == NULL) {
- return NGX_CONF_ERROR;
- }
-
- range = a->elts;
-
- ngx_memmove(&range[1], &range[0],
- (a->nelts - 1) * sizeof(ngx_stream_geo_range_t));
-
- range[0].start = (u_short) s;
- range[0].end = (u_short) e;
- range[0].value = ctx->value;
-
- next:
-
- if (h == 0xffff) {
- break;
- }
- }
-
- return NGX_CONF_OK;
-}
-
-
-static ngx_uint_t
-ngx_stream_geo_delete_range(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx,
- in_addr_t start, in_addr_t end)
-{
- in_addr_t n;
- ngx_uint_t h, i, s, e, warn;
- ngx_array_t *a;
- ngx_stream_geo_range_t *range;
-
- warn = 0;
-
- for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) {
-
- h = n >> 16;
-
- if (n == start) {
- s = n & 0xffff;
- } else {
- s = 0;
- }
-
- if ((n | 0xffff) > end) {
- e = end & 0xffff;
-
- } else {
- e = 0xffff;
- }
-
- a = (ngx_array_t *) ctx->high.low[h];
-
- if (a == NULL || a->nelts == 0) {
- warn = 1;
- goto next;
- }
-
- range = a->elts;
- for (i = 0; i < a->nelts; i++) {
-
- if (s == (ngx_uint_t) range[i].start
- && e == (ngx_uint_t) range[i].end)
- {
- ngx_memmove(&range[i], &range[i + 1],
- (a->nelts - 1 - i) * sizeof(ngx_stream_geo_range_t));
-
- a->nelts--;
-
- break;
- }
-
- if (i == a->nelts - 1) {
- warn = 1;
- }
- }
-
- next:
-
- if (h == 0xffff) {
- break;
- }
- }
-
- return warn;
-}
-
-
-static char *
-ngx_stream_geo_cidr(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx,
- ngx_str_t *value)
-{
- char *rv;
- ngx_int_t rc, del;
- ngx_str_t *net;
- ngx_cidr_t cidr;
-
- if (ctx->tree == NULL) {
- ctx->tree = ngx_radix_tree_create(ctx->pool, -1);
- if (ctx->tree == NULL) {
- return NGX_CONF_ERROR;
- }
- }
-
-#if (NGX_HAVE_INET6)
- if (ctx->tree6 == NULL) {
- ctx->tree6 = ngx_radix_tree_create(ctx->pool, -1);
- if (ctx->tree6 == NULL) {
- return NGX_CONF_ERROR;
- }
- }
-#endif
-
- if (ngx_strcmp(value[0].data, "default") == 0) {
- cidr.family = AF_INET;
- cidr.u.in.addr = 0;
- cidr.u.in.mask = 0;
-
- rv = ngx_stream_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]);
-
- if (rv != NGX_CONF_OK) {
- return rv;
- }
-
-#if (NGX_HAVE_INET6)
- cidr.family = AF_INET6;
- ngx_memzero(&cidr.u.in6, sizeof(ngx_in6_cidr_t));
-
- rv = ngx_stream_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]);
-
- if (rv != NGX_CONF_OK) {
- return rv;
- }
-#endif
-
- return NGX_CONF_OK;
- }
-
- if (ngx_strcmp(value[0].data, "delete") == 0) {
- net = &value[1];
- del = 1;
-
- } else {
- net = &value[0];
- del = 0;
- }
-
- if (ngx_stream_geo_cidr_value(cf, net, &cidr) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
-
- if (cidr.family == AF_INET) {
- cidr.u.in.addr = ntohl(cidr.u.in.addr);
- cidr.u.in.mask = ntohl(cidr.u.in.mask);
- }
-
- if (del) {
- switch (cidr.family) {
-
-#if (NGX_HAVE_INET6)
- case AF_INET6:
- rc = ngx_radix128tree_delete(ctx->tree6,
- cidr.u.in6.addr.s6_addr,
- cidr.u.in6.mask.s6_addr);
- break;
-#endif
-
- default: /* AF_INET */
- rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr,
- cidr.u.in.mask);
- break;
- }
-
- if (rc != NGX_OK) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "no network \"%V\" to delete", net);
- }
-
- return NGX_CONF_OK;
- }
-
- return ngx_stream_geo_cidr_add(cf, ctx, &cidr, &value[1], net);
-}
-
-
-static char *
-ngx_stream_geo_cidr_add(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx,
- ngx_cidr_t *cidr, ngx_str_t *value, ngx_str_t *net)
-{
- ngx_int_t rc;
- ngx_stream_variable_value_t *val, *old;
-
- val = ngx_stream_geo_value(cf, ctx, value);
-
- if (val == NULL) {
- return NGX_CONF_ERROR;
- }
-
- switch (cidr->family) {
-
-#if (NGX_HAVE_INET6)
- case AF_INET6:
- rc = ngx_radix128tree_insert(ctx->tree6, cidr->u.in6.addr.s6_addr,
- cidr->u.in6.mask.s6_addr,
- (uintptr_t) val);
-
- if (rc == NGX_OK) {
- return NGX_CONF_OK;
- }
-
- if (rc == NGX_ERROR) {
- return NGX_CONF_ERROR;
- }
-
- /* rc == NGX_BUSY */
-
- old = (ngx_stream_variable_value_t *)
- ngx_radix128tree_find(ctx->tree6,
- cidr->u.in6.addr.s6_addr);
-
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
- net, val, old);
-
- rc = ngx_radix128tree_delete(ctx->tree6,
- cidr->u.in6.addr.s6_addr,
- cidr->u.in6.mask.s6_addr);
-
- if (rc == NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
- return NGX_CONF_ERROR;
- }
-
- rc = ngx_radix128tree_insert(ctx->tree6, cidr->u.in6.addr.s6_addr,
- cidr->u.in6.mask.s6_addr,
- (uintptr_t) val);
-
- break;
-#endif
-
- default: /* AF_INET */
- rc = ngx_radix32tree_insert(ctx->tree, cidr->u.in.addr,
- cidr->u.in.mask, (uintptr_t) val);
-
- if (rc == NGX_OK) {
- return NGX_CONF_OK;
- }
-
- if (rc == NGX_ERROR) {
- return NGX_CONF_ERROR;
- }
-
- /* rc == NGX_BUSY */
-
- old = (ngx_stream_variable_value_t *)
- ngx_radix32tree_find(ctx->tree, cidr->u.in.addr);
-
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "duplicate network \"%V\", value: \"%v\", old value: \"%v\"",
- net, val, old);
-
- rc = ngx_radix32tree_delete(ctx->tree,
- cidr->u.in.addr, cidr->u.in.mask);
-
- if (rc == NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree");
- return NGX_CONF_ERROR;
- }
-
- rc = ngx_radix32tree_insert(ctx->tree, cidr->u.in.addr,
- cidr->u.in.mask, (uintptr_t) val);
-
- break;
- }
-
- if (rc == NGX_OK) {
- return NGX_CONF_OK;
- }
-
- return NGX_CONF_ERROR;
-}
-
-
-static ngx_stream_variable_value_t *
-ngx_stream_geo_value(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx,
- ngx_str_t *value)
-{
- uint32_t hash;
- ngx_stream_variable_value_t *val;
- ngx_stream_geo_variable_value_node_t *gvvn;
-
- hash = ngx_crc32_long(value->data, value->len);
-
- gvvn = (ngx_stream_geo_variable_value_node_t *)
- ngx_str_rbtree_lookup(&ctx->rbtree, value, hash);
-
- if (gvvn) {
- return gvvn->value;
- }
-
- val = ngx_palloc(ctx->pool, sizeof(ngx_stream_variable_value_t));
- if (val == NULL) {
- return NULL;
- }
-
- val->len = value->len;
- val->data = ngx_pstrdup(ctx->pool, value);
- if (val->data == NULL) {
- return NULL;
- }
-
- val->valid = 1;
- val->no_cacheable = 0;
- val->not_found = 0;
-
- gvvn = ngx_palloc(ctx->temp_pool,
- sizeof(ngx_stream_geo_variable_value_node_t));
- if (gvvn == NULL) {
- return NULL;
- }
-
- gvvn->sn.node.key = hash;
- gvvn->sn.str.len = val->len;
- gvvn->sn.str.data = val->data;
- gvvn->value = val;
- gvvn->offset = 0;
-
- ngx_rbtree_insert(&ctx->rbtree, &gvvn->sn.node);
-
- ctx->data_size += ngx_align(sizeof(ngx_stream_variable_value_t)
- + value->len, sizeof(void *));
-
- return val;
-}
-
-
-static ngx_int_t
-ngx_stream_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr)
-{
- ngx_int_t rc;
-
- if (ngx_strcmp(net->data, "255.255.255.255") == 0) {
- cidr->family = AF_INET;
- cidr->u.in.addr = 0xffffffff;
- cidr->u.in.mask = 0xffffffff;
-
- return NGX_OK;
- }
-
- rc = ngx_ptocidr(net, cidr);
-
- if (rc == NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net);
- return NGX_ERROR;
- }
-
- if (rc == NGX_DONE) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "low address bits of %V are meaningless", net);
- }
-
- return NGX_OK;
-}
-
-
-static char *
-ngx_stream_geo_include(ngx_conf_t *cf, ngx_stream_geo_conf_ctx_t *ctx,
- ngx_str_t *name)
-{
- char *rv;
- ngx_str_t file;
-
- file.len = name->len + 4;
- file.data = ngx_pnalloc(ctx->temp_pool, name->len + 5);
- if (file.data == NULL) {
- return NGX_CONF_ERROR;
- }
-
- ngx_sprintf(file.data, "%V.bin%Z", name);
-
- if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
-
- if (ctx->ranges) {
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
-
- switch (ngx_stream_geo_include_binary_base(cf, ctx, &file)) {
- case NGX_OK:
- return NGX_CONF_OK;
- case NGX_ERROR:
- return NGX_CONF_ERROR;
- default:
- break;
- }
- }
-
- file.len -= 4;
- file.data[file.len] = '\0';
-
- ctx->include_name = file;
-
- if (ctx->outside_entries) {
- ctx->allow_binary_include = 0;
- }
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data);
-
- rv = ngx_conf_parse(cf, &file);
-
- ctx->includes++;
- ctx->outside_entries = 0;
-
- return rv;
-}
-
-
-static ngx_int_t
-ngx_stream_geo_include_binary_base(ngx_conf_t *cf,
- ngx_stream_geo_conf_ctx_t *ctx, ngx_str_t *name)
-{
- u_char *base, ch;
- time_t mtime;
- size_t size, len;
- ssize_t n;
- uint32_t crc32;
- ngx_err_t err;
- ngx_int_t rc;
- ngx_uint_t i;
- ngx_file_t file;
- ngx_file_info_t fi;
- ngx_stream_geo_range_t *range, **ranges;
- ngx_stream_geo_header_t *header;
- ngx_stream_variable_value_t *vv;
-
- ngx_memzero(&file, sizeof(ngx_file_t));
- file.name = *name;
- file.log = cf->log;
-
- file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
-
- if (file.fd == NGX_INVALID_FILE) {
- err = ngx_errno;
- if (err != NGX_ENOENT) {
- ngx_conf_log_error(NGX_LOG_CRIT, cf, err,
- ngx_open_file_n " \"%s\" failed", name->data);
- }
- return NGX_DECLINED;
- }
-
- if (ctx->outside_entries) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "binary geo range base \"%s\" cannot be mixed with usual entries",
- name->data);
- rc = NGX_ERROR;
- goto done;
- }
-
- if (ctx->binary_include) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "second binary geo range base \"%s\" cannot be mixed with \"%s\"",
- name->data, ctx->include_name.data);
- rc = NGX_ERROR;
- goto done;
- }
-
- if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
- ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", name->data);
- goto failed;
- }
-
- size = (size_t) ngx_file_size(&fi);
- mtime = ngx_file_mtime(&fi);
-
- ch = name->data[name->len - 4];
- name->data[name->len - 4] = '\0';
-
- if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) {
- ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
- ngx_file_info_n " \"%s\" failed", name->data);
- goto failed;
- }
-
- name->data[name->len - 4] = ch;
-
- if (mtime < ngx_file_mtime(&fi)) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "stale binary geo range base \"%s\"", name->data);
- goto failed;
- }
-
- base = ngx_palloc(ctx->pool, size);
- if (base == NULL) {
- goto failed;
- }
-
- n = ngx_read_file(&file, base, size, 0);
-
- if (n == NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
- ngx_read_file_n " \"%s\" failed", name->data);
- goto failed;
- }
-
- if ((size_t) n != size) {
- ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
- ngx_read_file_n " \"%s\" returned only %z bytes instead of %z",
- name->data, n, size);
- goto failed;
- }
-
- header = (ngx_stream_geo_header_t *) base;
-
- if (size < 16 || ngx_memcmp(&ngx_stream_geo_header, header, 12) != 0) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "incompatible binary geo range base \"%s\"", name->data);
- goto failed;
- }
-
- ngx_crc32_init(crc32);
-
- vv = (ngx_stream_variable_value_t *)
- (base + sizeof(ngx_stream_geo_header_t));
-
- while (vv->data) {
- len = ngx_align(sizeof(ngx_stream_variable_value_t) + vv->len,
- sizeof(void *));
- ngx_crc32_update(&crc32, (u_char *) vv, len);
- vv->data += (size_t) base;
- vv = (ngx_stream_variable_value_t *) ((u_char *) vv + len);
- }
- ngx_crc32_update(&crc32, (u_char *) vv,
- sizeof(ngx_stream_variable_value_t));
- vv++;
-
- ranges = (ngx_stream_geo_range_t **) vv;
-
- for (i = 0; i < 0x10000; i++) {
- ngx_crc32_update(&crc32, (u_char *) &ranges[i], sizeof(void *));
- if (ranges[i]) {
- ranges[i] = (ngx_stream_geo_range_t *)
- ((u_char *) ranges[i] + (size_t) base);
- }
- }
-
- range = (ngx_stream_geo_range_t *) &ranges[0x10000];
-
- while ((u_char *) range < base + size) {
- while (range->value) {
- ngx_crc32_update(&crc32, (u_char *) range,
- sizeof(ngx_stream_geo_range_t));
- range->value = (ngx_stream_variable_value_t *)
- ((u_char *) range->value + (size_t) base);
- range++;
- }
- ngx_crc32_update(&crc32, (u_char *) range, sizeof(void *));
- range = (ngx_stream_geo_range_t *) ((u_char *) range + sizeof(void *));
- }
-
- ngx_crc32_final(crc32);
-
- if (crc32 != header->crc32) {
- ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
- "CRC32 mismatch in binary geo range base \"%s\"", name->data);
- goto failed;
- }
-
- ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0,
- "using binary geo range base \"%s\"", name->data);
-
- ctx->include_name = *name;
- ctx->binary_include = 1;
- ctx->high.low = ranges;
- rc = NGX_OK;
-
- goto done;
-
-failed:
-
- rc = NGX_DECLINED;
-
-done:
-
- if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", name->data);
- }
-
- return rc;
-}
-
-
-static void
-ngx_stream_geo_create_binary_base(ngx_stream_geo_conf_ctx_t *ctx)
-{
- u_char *p;
- uint32_t hash;
- ngx_str_t s;
- ngx_uint_t i;
- ngx_file_mapping_t fm;
- ngx_stream_geo_range_t *r, *range, **ranges;
- ngx_stream_geo_header_t *header;
- ngx_stream_geo_variable_value_node_t *gvvn;
-
- fm.name = ngx_pnalloc(ctx->temp_pool, ctx->include_name.len + 5);
- if (fm.name == NULL) {
- return;
- }
-
- ngx_sprintf(fm.name, "%V.bin%Z", &ctx->include_name);
-
- fm.size = ctx->data_size;
- fm.log = ctx->pool->log;
-
- ngx_log_error(NGX_LOG_NOTICE, fm.log, 0,
- "creating binary geo range base \"%s\"", fm.name);
-
- if (ngx_create_file_mapping(&fm) != NGX_OK) {
- return;
- }
-
- p = ngx_cpymem(fm.addr, &ngx_stream_geo_header,
- sizeof(ngx_stream_geo_header_t));
-
- p = ngx_stream_geo_copy_values(fm.addr, p, ctx->rbtree.root,
- ctx->rbtree.sentinel);
-
- p += sizeof(ngx_stream_variable_value_t);
-
- ranges = (ngx_stream_geo_range_t **) p;
-
- p += 0x10000 * sizeof(ngx_stream_geo_range_t *);
-
- for (i = 0; i < 0x10000; i++) {
- r = ctx->high.low[i];
- if (r == NULL) {
- continue;
- }
-
- range = (ngx_stream_geo_range_t *) p;
- ranges[i] = (ngx_stream_geo_range_t *) (p - (u_char *) fm.addr);
-
- do {
- s.len = r->value->len;
- s.data = r->value->data;
- hash = ngx_crc32_long(s.data, s.len);
- gvvn = (ngx_stream_geo_variable_value_node_t *)
- ngx_str_rbtree_lookup(&ctx->rbtree, &s, hash);
-
- range->value = (ngx_stream_variable_value_t *) gvvn->offset;
- range->start = r->start;
- range->end = r->end;
- range++;
-
- } while ((++r)->value);
-
- range->value = NULL;
-
- p = (u_char *) range + sizeof(void *);
- }
-
- header = fm.addr;
- header->crc32 = ngx_crc32_long((u_char *) fm.addr
- + sizeof(ngx_stream_geo_header_t),
- fm.size - sizeof(ngx_stream_geo_header_t));
-
- ngx_close_file_mapping(&fm);
-}
-
-
-static u_char *
-ngx_stream_geo_copy_values(u_char *base, u_char *p, ngx_rbtree_node_t *node,
- ngx_rbtree_node_t *sentinel)
-{
- ngx_stream_variable_value_t *vv;
- ngx_stream_geo_variable_value_node_t *gvvn;
-
- if (node == sentinel) {
- return p;
- }
-
- gvvn = (ngx_stream_geo_variable_value_node_t *) node;
- gvvn->offset = p - base;
-
- vv = (ngx_stream_variable_value_t *) p;
- *vv = *gvvn->value;
- p += sizeof(ngx_stream_variable_value_t);
- vv->data = (u_char *) (p - base);
-
- p = ngx_cpymem(p, gvvn->sn.str.data, gvvn->sn.str.len);
-
- p = ngx_align_ptr(p, sizeof(void *));
-
- p = ngx_stream_geo_copy_values(base, p, node->left, sentinel);
-
- return ngx_stream_geo_copy_values(base, p, node->right, sentinel);
-}