diff options
| author | 2013-03-17 16:05:30 +0000 | |
|---|---|---|
| committer | 2013-03-17 16:05:30 +0000 | |
| commit | 9f3c3c8525eca9911b66de0aa79e1d7be73c5c8b (patch) | |
| tree | b011d550d41b8572004322c2189b1dff46623967 /usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c | |
| parent | Avoid namespace pollution from <powerpc/cpu.h>. (diff) | |
| download | wireguard-openbsd-9f3c3c8525eca9911b66de0aa79e1d7be73c5c8b.tar.xz wireguard-openbsd-9f3c3c8525eca9911b66de0aa79e1d7be73c5c8b.zip | |
update to 1.2.7
Diffstat (limited to 'usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c')
| -rw-r--r-- | usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c | 413 |
1 files changed, 310 insertions, 103 deletions
diff --git a/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c b/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c index fce87a8cb46..a927ab798c1 100644 --- a/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c +++ b/usr.sbin/nginx/src/http/modules/ngx_http_geo_module.c @@ -18,6 +18,14 @@ typedef struct { typedef struct { + ngx_radix_tree_t *tree; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *tree6; +#endif +} ngx_http_geo_trees_t; + + +typedef struct { ngx_http_geo_range_t **low; ngx_http_variable_value_t *default_value; } ngx_http_geo_high_ranges_t; @@ -35,6 +43,9 @@ typedef struct { ngx_str_t *net; ngx_http_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_array_t *proxies; @@ -57,7 +68,7 @@ typedef struct { typedef struct { union { - ngx_radix_tree_t *tree; + ngx_http_geo_trees_t trees; ngx_http_geo_high_ranges_t high; } u; @@ -68,8 +79,8 @@ typedef struct { } ngx_http_geo_ctx_t; -static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, - ngx_http_geo_ctx_t *ctx); +static ngx_int_t ngx_http_geo_addr(ngx_http_request_t *r, + ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr); static ngx_int_t ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr); static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -82,6 +93,8 @@ static ngx_uint_t ngx_http_geo_delete_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, in_addr_t start, in_addr_t end); static char *ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value); +static char *ngx_http_geo_cidr_add(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, + ngx_cidr_t *cidr, ngx_str_t *value, ngx_str_t *net); static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value); static char *ngx_http_geo_add_proxy(ngx_conf_t *cf, @@ -155,7 +168,7 @@ static ngx_http_geo_header_t ngx_http_geo_header = { }; -/* AF_INET only */ +/* geo range is AF_INET only */ static ngx_int_t ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, @@ -163,10 +176,56 @@ ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, { ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; + in_addr_t inaddr; + ngx_addr_t addr; + struct sockaddr_in *sin; ngx_http_variable_value_t *vv; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif + + if (ngx_http_geo_addr(r, ctx, &addr) != NGX_OK) { + vv = (ngx_http_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE); + goto done; + } + + switch (addr.sockaddr->sa_family) { - vv = (ngx_http_variable_value_t *) - ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx)); +#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_http_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + } else { + vv = (ngx_http_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_http_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + break; + } + +done: *v = *vv; @@ -183,25 +242,65 @@ ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, { ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; - in_addr_t addr; + in_addr_t inaddr; + ngx_addr_t addr; ngx_uint_t n; + struct sockaddr_in *sin; ngx_http_geo_range_t *range; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif *v = *ctx->u.high.default_value; - addr = ngx_http_geo_addr(r, ctx); + if (ngx_http_geo_addr(r, ctx, &addr) == NGX_OK) { - range = ctx->u.high.low[addr >> 16]; + switch (addr.sockaddr->sa_family) { - if (range) { - n = addr & 0xffff; - do { - if (n >= (ngx_uint_t) range->start && n <= (ngx_uint_t) range->end) - { - *v = *range->value; - break; +#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; } - } while ((++range)->value); + + 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_HTTP, r->connection->log, 0, @@ -211,54 +310,25 @@ ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, } -static in_addr_t -ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) +static ngx_int_t +ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, + ngx_addr_t *addr) { - ngx_addr_t addr; - ngx_table_elt_t *xfwd; - struct sockaddr_in *sin; + ngx_table_elt_t *xfwd; - if (ngx_http_geo_real_addr(r, ctx, &addr) != NGX_OK) { - return INADDR_NONE; + if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) { + return NGX_ERROR; } xfwd = r->headers_in.x_forwarded_for; if (xfwd != NULL && ctx->proxies != NULL) { - (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data, + (void) ngx_http_get_forwarded_addr(r, addr, xfwd->value.data, xfwd->value.len, ctx->proxies, ctx->proxy_recursive); } -#if (NGX_HAVE_INET6) - - if (addr.sockaddr->sa_family == AF_INET6) { - u_char *p; - in_addr_t inaddr; - struct in6_addr *inaddr6; - - 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]; - - return inaddr; - } - } - -#endif - - if (addr.sockaddr->sa_family != AF_INET) { - return INADDR_NONE; - } - - sin = (struct sockaddr_in *) addr.sockaddr; - return ntohl(sin->sin_addr.s_addr); + return NGX_OK; } @@ -303,7 +373,6 @@ static char * ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - void **p; size_t len; ngx_str_t *value, name; ngx_uint_t i; @@ -313,6 +382,9 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_variable_t *var; ngx_http_geo_ctx_t *geo; ngx_http_geo_conf_ctx_t ctx; +#if (NGX_HAVE_INET6) + static struct in6_addr zero; +#endif value = cf->args->elts; @@ -322,6 +394,13 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } 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++; @@ -333,6 +412,13 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } 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++; @@ -378,9 +464,9 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) geo->proxies = ctx.proxies; geo->proxy_recursive = ctx.proxy_recursive; - if (ctx.high.low) { + if (ctx.ranges) { - if (!ctx.binary_include) { + if (ctx.high.low && !ctx.binary_include) { for (i = 0; i < 0x10000; i++) { a = (ngx_array_t *) ctx.high.low[i]; @@ -395,8 +481,8 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) return NGX_CONF_ERROR; } - p = (void **) ngx_cpymem(ctx.high.low[i], a->elts, len); - *p = NULL; + ngx_memcpy(ctx.high.low[i], a->elts, len); + ctx.high.low[i][a->nelts].value = NULL; ctx.data_size += len + sizeof(void *); } @@ -429,7 +515,18 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - geo->u.tree = ctx.tree; + 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) { + return NGX_CONF_ERROR; + } + } + + geo->u.trees.tree6 = ctx.tree6; +#endif var->get_handler = ngx_http_geo_cidr_variable; var->data = (uintptr_t) geo; @@ -437,16 +534,23 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_destroy_pool(ctx.temp_pool); ngx_destroy_pool(pool); - if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) { - return rv; - } - if (ngx_radix32tree_insert(ctx.tree, 0, 0, (uintptr_t) &ngx_http_variable_null_value) == NGX_ERROR) { return NGX_CONF_ERROR; } + + /* 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_http_variable_null_value) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } +#endif } return rv; @@ -469,7 +573,12 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) if (ngx_strcmp(value[0].data, "ranges") == 0) { - if (ctx->tree) { + 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"); @@ -907,11 +1016,10 @@ static char * ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value) { - ngx_int_t rc, del; - ngx_str_t *net; - ngx_uint_t i; - ngx_cidr_t cidr; - ngx_http_variable_value_t *val, *old; + 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); @@ -920,57 +1028,146 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, } } +#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.family = AF_INET; cidr.u.in.addr = 0; cidr.u.in.mask = 0; - net = &value[0]; - } else { - if (ngx_strcmp(value[0].data, "delete") == 0) { - net = &value[1]; - del = 1; + rv = ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], &value[0]); - } else { - net = &value[0]; - del = 0; + if (rv != NGX_CONF_OK) { + return rv; } - if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) { - return NGX_CONF_ERROR; - } +#if (NGX_HAVE_INET6) + cidr.family = AF_INET6; + ngx_memzero(&cidr.u.in6, sizeof(ngx_in6_cidr_t)); - if (cidr.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"geo\" supports IPv4 only"); - return NGX_CONF_ERROR; + rv = ngx_http_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_http_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) { - if (ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, - cidr.u.in.mask) - != NGX_OK) - { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "no network \"%V\" to delete", net); - } + if (del) { + switch (cidr.family) { - return NGX_CONF_OK; +#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; } - val = ngx_http_geo_value(cf, ctx, &value[1]); + return ngx_http_geo_cidr_add(cf, ctx, &cidr, &value[1], net); +} + + +static char * +ngx_http_geo_cidr_add(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, + ngx_cidr_t *cidr, ngx_str_t *value, ngx_str_t *net) +{ + ngx_int_t rc; + ngx_http_variable_value_t *val, *old; + + val = ngx_http_geo_value(cf, ctx, value); if (val == NULL) { return NGX_CONF_ERROR; } - for (i = 2; i; i--) { - rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, cidr.u.in.mask, - (uintptr_t) val); + 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_http_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; } @@ -982,18 +1179,28 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, /* rc == NGX_BUSY */ old = (ngx_http_variable_value_t *) - ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask); + 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); + "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); + 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; |
