details: http://hg.nginx.org/nginx/rev/0dcef374b8bb branches: changeset: 6197:0dcef374b8bb user: Vladimir Homutov <v...@nginx.com> date: Thu Jun 18 14:17:30 2015 +0300 description: Stream: connection limiting module.
stream { limit_conn_zone $binary_remote_addr zone=perip:1m; limit_conn_log_level error; server { ... limit_conn perip 1; } } diffstat: auto/modules | 5 + auto/options | 4 + auto/sources | 3 + src/stream/ngx_stream.h | 1 + src/stream/ngx_stream_handler.c | 9 + src/stream/ngx_stream_limit_conn_module.c | 632 ++++++++++++++++++++++++++++++ 6 files changed, 654 insertions(+), 0 deletions(-) diffs (truncated from 722 to 300 lines): diff -r c3ec43580a48 -r 0dcef374b8bb auto/modules --- a/auto/modules Wed Jun 17 17:57:34 2015 +0300 +++ b/auto/modules Thu Jun 18 14:17:30 2015 +0300 @@ -514,6 +514,11 @@ if [ $STREAM = YES ]; then STREAM_SRCS="$STREAM_SRCS $STREAM_SSL_SRCS" fi + if [ $STREAM_LIMIT_CONN = YES ]; then + modules="$modules $STREAM_LIMIT_CONN_MODULE" + STREAM_SRCS="$STREAM_SRCS $STREAM_LIMIT_CONN_SRCS" + fi + if [ $STREAM_ACCESS = YES ]; then modules="$modules $STREAM_ACCESS_MODULE" STREAM_SRCS="$STREAM_SRCS $STREAM_ACCESS_SRCS" diff -r c3ec43580a48 -r 0dcef374b8bb auto/options --- a/auto/options Wed Jun 17 17:57:34 2015 +0300 +++ b/auto/options Thu Jun 18 14:17:30 2015 +0300 @@ -113,6 +113,7 @@ MAIL_SMTP=YES STREAM=NO STREAM_SSL=NO +STREAM_LIMIT_CONN=YES STREAM_ACCESS=YES STREAM_UPSTREAM_HASH=YES STREAM_UPSTREAM_LEAST_CONN=YES @@ -283,6 +284,8 @@ use the \"--with-mail_ssl_module\" optio --with-stream) STREAM=YES ;; --with-stream_ssl_module) STREAM_SSL=YES ;; + --without-stream_limit_conn_module) + STREAM_LIMIT_CONN=NO ;; --without-stream_access_module) STREAM_ACCESS=NO ;; --without-stream_upstream_hash_module) STREAM_UPSTREAM_HASH=NO ;; @@ -452,6 +455,7 @@ cat << END --with-stream enable TCP proxy module --with-stream_ssl_module enable ngx_stream_ssl_module + --without-stream_limit_conn_module disable ngx_stream_limit_conn_module --without-stream_access_module disable ngx_stream_access_module --without-stream_upstream_hash_module disable ngx_stream_upstream_hash_module diff -r c3ec43580a48 -r 0dcef374b8bb auto/sources --- a/auto/sources Wed Jun 17 17:57:34 2015 +0300 +++ b/auto/sources Thu Jun 18 14:17:30 2015 +0300 @@ -568,6 +568,9 @@ STREAM_SSL_MODULE="ngx_stream_ssl_module STREAM_SSL_DEPS="src/stream/ngx_stream_ssl_module.h" STREAM_SSL_SRCS="src/stream/ngx_stream_ssl_module.c" +STREAM_LIMIT_CONN_MODULE=ngx_stream_limit_conn_module +STREAM_LIMIT_CONN_SRCS=src/stream/ngx_stream_limit_conn_module.c + STREAM_ACCESS_MODULE=ngx_stream_access_module STREAM_ACCESS_SRCS=src/stream/ngx_stream_access_module.c diff -r c3ec43580a48 -r 0dcef374b8bb src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h Wed Jun 17 17:57:34 2015 +0300 +++ b/src/stream/ngx_stream.h Thu Jun 18 14:17:30 2015 +0300 @@ -118,6 +118,7 @@ typedef ngx_int_t (*ngx_stream_access_pt typedef struct { ngx_array_t servers; /* ngx_stream_core_srv_conf_t */ ngx_array_t listen; /* ngx_stream_listen_t */ + ngx_stream_access_pt limit_conn_handler; ngx_stream_access_pt access_handler; } ngx_stream_core_main_conf_t; diff -r c3ec43580a48 -r 0dcef374b8bb src/stream/ngx_stream_handler.c --- a/src/stream/ngx_stream_handler.c Wed Jun 17 17:57:34 2015 +0300 +++ b/src/stream/ngx_stream_handler.c Thu Jun 18 14:17:30 2015 +0300 @@ -147,6 +147,15 @@ ngx_stream_init_connection(ngx_connectio cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); + if (cmcf->limit_conn_handler) { + rc = cmcf->limit_conn_handler(s); + + if (rc != NGX_DECLINED) { + ngx_stream_close_connection(c); + return; + } + } + if (cmcf->access_handler) { rc = cmcf->access_handler(s); diff -r c3ec43580a48 -r 0dcef374b8bb src/stream/ngx_stream_limit_conn_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/stream/ngx_stream_limit_conn_module.c Thu Jun 18 14:17:30 2015 +0300 @@ -0,0 +1,632 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_stream.h> + + +typedef struct { + u_char color; + u_char len; + u_short conn; + u_char data[1]; +} ngx_stream_limit_conn_node_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_rbtree_node_t *node; +} ngx_stream_limit_conn_cleanup_t; + + +typedef struct { + ngx_rbtree_t *rbtree; +} ngx_stream_limit_conn_ctx_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_uint_t conn; +} ngx_stream_limit_conn_limit_t; + + +typedef struct { + ngx_array_t limits; + ngx_uint_t log_level; +} ngx_stream_limit_conn_conf_t; + + +static ngx_rbtree_node_t *ngx_stream_limit_conn_lookup(ngx_rbtree_t *rbtree, + ngx_str_t *key, uint32_t hash); +static void ngx_stream_limit_conn_cleanup(void *data); +static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool); + +static void *ngx_stream_limit_conn_create_conf(ngx_conf_t *cf); +static char *ngx_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_stream_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_stream_limit_conn_init(ngx_conf_t *cf); + + +static ngx_conf_enum_t ngx_stream_limit_conn_log_levels[] = { + { ngx_string("info"), NGX_LOG_INFO }, + { ngx_string("notice"), NGX_LOG_NOTICE }, + { ngx_string("warn"), NGX_LOG_WARN }, + { ngx_string("error"), NGX_LOG_ERR }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_stream_limit_conn_commands[] = { + + { ngx_string("limit_conn_zone"), + NGX_STREAM_MAIN_CONF|NGX_CONF_TAKE2, + ngx_stream_limit_conn_zone, + 0, + 0, + NULL }, + + { ngx_string("limit_conn"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2, + ngx_stream_limit_conn, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("limit_conn_log_level"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_limit_conn_conf_t, log_level), + &ngx_stream_limit_conn_log_levels }, + + ngx_null_command +}; + + +static ngx_stream_module_t ngx_stream_limit_conn_module_ctx = { + ngx_stream_limit_conn_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_stream_limit_conn_create_conf, /* create server configuration */ + ngx_stream_limit_conn_merge_conf, /* merge server configuration */ +}; + + +ngx_module_t ngx_stream_limit_conn_module = { + NGX_MODULE_V1, + &ngx_stream_limit_conn_module_ctx, /* module context */ + ngx_stream_limit_conn_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 +}; + + +static ngx_int_t +ngx_stream_limit_conn_handler(ngx_stream_session_t *s) +{ + size_t n; + uint32_t hash; + ngx_str_t key; + ngx_uint_t i; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_pool_cleanup_t *cln; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + ngx_stream_limit_conn_ctx_t *ctx; + ngx_stream_limit_conn_node_t *lc; + ngx_stream_limit_conn_conf_t *lccf; + ngx_stream_limit_conn_limit_t *limits; + ngx_stream_limit_conn_cleanup_t *lccln; + + switch (s->connection->sockaddr->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) s->connection->sockaddr; + + key.len = sizeof(in_addr_t); + key.data = (u_char *) &sin->sin_addr; + + break; + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; + + key.len = sizeof(struct in6_addr); + key.data = sin6->sin6_addr.s6_addr; + + break; +#endif + + default: + return NGX_DECLINED; + } + + hash = ngx_crc32_short(key.data, key.len); + + lccf = ngx_stream_get_module_srv_conf(s, ngx_stream_limit_conn_module); + limits = lccf->limits.elts; + + for (i = 0; i < lccf->limits.nelts; i++) { + ctx = limits[i].shm_zone->data; + + shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + node = ngx_stream_limit_conn_lookup(ctx->rbtree, &key, hash); + + if (node == NULL) { + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_stream_limit_conn_node_t, data) + + key.len; + + node = ngx_slab_alloc_locked(shpool, n); + + if (node == NULL) { + ngx_shmtx_unlock(&shpool->mutex); + ngx_stream_limit_conn_cleanup_all(s->connection->pool); + return NGX_ABORT; + } + + lc = (ngx_stream_limit_conn_node_t *) &node->color; + + node->key = hash; + lc->len = (u_char) key.len; + lc->conn = 1; + ngx_memcpy(lc->data, key.data, key.len); + + ngx_rbtree_insert(ctx->rbtree, node); + + } else { + + lc = (ngx_stream_limit_conn_node_t *) &node->color; + + if ((ngx_uint_t) lc->conn >= limits[i].conn) { + + ngx_shmtx_unlock(&shpool->mutex); + _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel