summaryrefslogtreecommitdiff
path: root/accel-pppd
diff options
context:
space:
mode:
authorKozlov Dmitry <xeb@mail.ru>2012-01-18 18:29:52 +0400
committerKozlov Dmitry <xeb@mail.ru>2012-01-18 18:29:52 +0400
commitb463f4f2559a6f0180ba09fb1cb43d51144e95f0 (patch)
tree10a01cbfeb1893219d4f98a8f33fb14e9421892a /accel-pppd
parent010a21c48d1a9cc560e7d46e02acab80c79eae10 (diff)
downloadaccel-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.conf15
-rw-r--r--accel-pppd/accel-ppp.conf.512
-rw-r--r--accel-pppd/ctrl/l2tp/l2tp.c5
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.c8
-rw-r--r--accel-pppd/ctrl/pptp/pptp.c7
-rw-r--r--accel-pppd/extra/CMakeLists.txt3
-rw-r--r--accel-pppd/extra/connlimit.c169
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);