diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-01-18 18:29:52 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-01-18 18:29:52 +0400 |
commit | b463f4f2559a6f0180ba09fb1cb43d51144e95f0 (patch) | |
tree | 10a01cbfeb1893219d4f98a8f33fb14e9421892a /accel-pppd | |
parent | 010a21c48d1a9cc560e7d46e02acab80c79eae10 (diff) | |
download | accel-ppp-b463f4f2559a6f0180ba09fb1cb43d51144e95f0.tar.gz accel-ppp-b463f4f2559a6f0180ba09fb1cb43d51144e95f0.zip |
implemented connlimit module which can be used to reduce system overload due to flood of connections
Diffstat (limited to 'accel-pppd')
-rw-r--r-- | accel-pppd/accel-ppp.conf | 15 | ||||
-rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 12 | ||||
-rw-r--r-- | accel-pppd/ctrl/l2tp/l2tp.c | 5 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.c | 8 | ||||
-rw-r--r-- | accel-pppd/ctrl/pptp/pptp.c | 7 | ||||
-rw-r--r-- | accel-pppd/extra/CMakeLists.txt | 3 | ||||
-rw-r--r-- | accel-pppd/extra/connlimit.c | 169 |
7 files changed, 215 insertions, 4 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index 0e7960d..282d5de 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -4,23 +4,30 @@ log_file #log_syslog #log_tcp #log_pgsql + pptp +l2tp #pppoe -#l2tp + auth_mschap_v2 auth_mschap_v1 auth_chap_md5 auth_pap + radius ippool sigchld pppd_compat + #shaper_tbf #chap-secrets #net-snmp +#logwtmp +#connlimit + #ipv6_nd #ipv6_dhcp -#logwtmp +#ipv6pool [core] log-error=/var/log/accel-ppp/core.log @@ -152,6 +159,10 @@ tcp=127.0.0.1:2001 master=0 agent-name=accel-ppp +[connlimit] +limit=10/min +burst=3 +timeout=60 [ipv6-pool] fc00:0:1::/48,64 diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5 index 1a16d77..e4435a0 100644 --- a/accel-pppd/accel-ppp.conf.5 +++ b/accel-pppd/accel-ppp.conf.5 @@ -515,3 +515,15 @@ fc00:0:1:ffff::/64 .BI "delegate=" ipv6prefix/mask,prefix_len Specifies range of prefixes to delegate to clients through DHCPv6 prefix delegation (rfc3633). Format is same as described above. +.TP +.SH [connlimit] +.br +This module limits connection rate from single source. +.TP +.BI "limit=" count/time +Specifies acceptable rate of connections, for example limit=1/s or limit=10/m. +.TP +.BI "burst=" count +.TP +.BI "timeout=" n +Specifies timeout in seconds after which module doesn't check rate until burst number of connections will be arrived. diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index af617ba..9cde03e 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -24,6 +24,8 @@ #include "iprange.h" #include "cli.h" +#include "connlimit.h" + #include "memdebug.h" #include "l2tp.h" @@ -622,6 +624,9 @@ static int l2tp_recv_SCCRQ(struct l2tp_serv_t *serv, struct l2tp_packet_t *pack, if (ppp_shutdown) return 0; + + if (triton_module_loaded("connlimit") && connlimit_check(cl_key_from_ipv4(pack->addr.sin_addr.s_addr))) + return 0; list_for_each_entry(attr, &pack->attrs, entry) { switch (attr->attr->id) { diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c index 3742c87..a5a8eb6 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.c +++ b/accel-pppd/ctrl/pppoe/pppoe.c @@ -26,6 +26,8 @@ #include "radius.h" #endif +#include "connlimit.h" + #include "pppoe.h" #include "memdebug.h" @@ -712,7 +714,7 @@ static int check_padi_limit(struct pppoe_serv_t *serv, uint8_t *addr) struct timespec ts; if (serv->padi_limit == 0) - return 0; + goto connlimit_check; clock_gettime(CLOCK_MONOTONIC, &ts); @@ -748,6 +750,10 @@ static int check_padi_limit(struct pppoe_serv_t *serv, uint8_t *addr) __sync_add_and_fetch(&total_padi_cnt, 1); +connlimit_check: + if (triton_module_loaded("connlimit") && connlimit_check(cl_key_from_mac(addr))) + return -1; + return 0; } diff --git a/accel-pppd/ctrl/pptp/pptp.c b/accel-pppd/ctrl/pptp/pptp.c index b9930f3..b785b1f 100644 --- a/accel-pppd/ctrl/pptp/pptp.c +++ b/accel-pppd/ctrl/pptp/pptp.c @@ -23,6 +23,8 @@ #include "utils.h" #include "cli.h" +#include "connlimit.h" + #include "memdebug.h" #define STATE_IDLE 0 @@ -629,6 +631,11 @@ static int pptp_connect(struct triton_md_handler_t *h) continue; } + if (triton_module_loaded("connlimit") && connlimit_check(cl_key_from_ipv4(addr.sin_addr.s_addr))) { + close(sock); + return 0; + } + log_info2("pptp: new connection from %s\n", inet_ntoa(addr.sin_addr)); if (iprange_client_check(addr.sin_addr.s_addr)) { diff --git a/accel-pppd/extra/CMakeLists.txt b/accel-pppd/extra/CMakeLists.txt index d251345..365f542 100644 --- a/accel-pppd/extra/CMakeLists.txt +++ b/accel-pppd/extra/CMakeLists.txt @@ -5,8 +5,9 @@ ADD_LIBRARY(sigchld SHARED sigchld.c) ADD_LIBRARY(chap-secrets SHARED chap-secrets.c) ADD_LIBRARY(logwtmp SHARED logwtmp.c) TARGET_LINK_LIBRARIES(logwtmp util) +ADD_LIBRARY(connlimit SHARED connlimit.c) -INSTALL(TARGETS pppd_compat ippool ipv6pool sigchld chap-secrets logwtmp +INSTALL(TARGETS pppd_compat ippool ipv6pool sigchld chap-secrets logwtmp connlimit LIBRARY DESTINATION lib/accel-ppp ) diff --git a/accel-pppd/extra/connlimit.c b/accel-pppd/extra/connlimit.c new file mode 100644 index 0000000..56a0895 --- /dev/null +++ b/accel-pppd/extra/connlimit.c @@ -0,0 +1,169 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> + +#include "ppp.h" +#include "events.h" +#include "triton.h" +#include "log.h" + +#include "memdebug.h" + +struct item +{ + struct list_head entry; + uint64_t key; + struct timespec ts; + int count; +}; + +static int conf_burst = 3; +static int conf_burst_timeout = 60 * 1000; +static int conf_limit_timeout = 5000; + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static LIST_HEAD(items); + +int __export connlimit_check(uint64_t key) +{ + struct item *it; + struct timespec ts; + unsigned int d; + struct list_head *pos, *n; + LIST_HEAD(tmp_list); + int r = 1; + + + clock_gettime(CLOCK_MONOTONIC, &ts); + + pthread_mutex_lock(&lock); + log_debug("connlimit: check entry %llu\n", key); + list_for_each_safe(pos, n, &items) { + it = list_entry(pos, typeof(*it), entry); + + d = (ts.tv_sec - it->ts.tv_sec) * 1000 + (ts.tv_nsec - it->ts.tv_nsec) / 1000000; + + if (it->key == key) { + it->count++; + if (it->count >= conf_burst) { + if (d >= conf_limit_timeout) { + it->ts = ts; + list_move(&it->entry, &items); + r = 0; + } else + r = -1; + } else { + if (d >= conf_burst_timeout) { + it->ts = ts; + list_move(&it->entry, &items); + } + r = 0; + } + break; + } + + if (d > conf_burst_timeout) { + log_debug("connlimit: remove %llu\n", it->key); + list_move(&it->entry, &tmp_list); + } + } + pthread_mutex_unlock(&lock); + + if (r == 1) { + it = _malloc(sizeof(*it)); + memset(it, 0, sizeof(*it)); + it->ts = ts; + it->key = key; + + log_debug("connlimit: add entry %llu\n", key); + + pthread_mutex_lock(&lock); + list_add(&it->entry, &items); + pthread_mutex_unlock(&lock); + + r = 0; + } + + if (r == 0) + log_debug("connlimit: accept %llu\n", key); + else + log_debug("connlimit: drop %llu\n", key); + + + while (!list_empty(&tmp_list)) { + it = list_entry(tmp_list.next, typeof(*it), entry); + list_del(&it->entry); + _free(it); + } + + return r; +} + +static int parse_limit(const char *opt, int *limit, int *time) +{ + char *endptr; + + *limit = strtol(opt, &endptr, 10); + + if (!*endptr) { + *time = 1; + return 0; + } + + if (*endptr != '/') + goto out_err; + + opt = endptr + 1; + *time = strtol(opt, &endptr, 10); + + if (endptr == opt) + *time = 1; + + if (*endptr == 's') + return 0; + + if (*endptr == 'm') { + *time *= 60; + return 0; + } + + if (*endptr == 'h') { + *time *= 3600; + return 0; + } + +out_err: + log_error("connlimit: failed to parse '%s'\n", opt); + return -1; +} + +static void load_config() +{ + const char *opt; + int n,t; + + opt = conf_get_opt("connlimit", "limit"); + if (opt) { + if (parse_limit(opt, &n, &t)) + return; + conf_limit_timeout = t * 1000 / n; + } + + opt = conf_get_opt("connlimit", "burst"); + if (opt) + conf_burst = atoi(opt); + + opt = conf_get_opt("connlimit", "timeout"); + if (opt) + conf_burst_timeout = atoi(opt) * 1000; +} + +static void init() +{ + load_config(); + + triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); +} + +DEFINE_INIT(200, init); |