summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--accel-pppd/accel-ppp.conf3
-rw-r--r--accel-pppd/accel-ppp.conf.510
-rw-r--r--accel-pppd/ctrl/pppoe/cli.c1
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.c107
-rw-r--r--accel-pppd/ctrl/pppoe/pppoe.h6
5 files changed, 120 insertions, 7 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf
index b6427c20..ee01891c 100644
--- a/accel-pppd/accel-ppp.conf
+++ b/accel-pppd/accel-ppp.conf
@@ -55,13 +55,14 @@ verbose=1
[pppoe]
interface=eth0
-interface=eth1
+#interface=eth1,padi-limit=1000
#ac-name=xxx
#service-name=yyy
#pado-delay=0
#pado-delay=0,100:100,200:200,-1:500
#ifname-in-sid=called-sid
#tr101=1
+#padi-limit=0
verbose=1
[l2tp]
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index 42749652..1a16d771 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -230,10 +230,12 @@ Timeout waiting reply from client in seconds (default 5).
.br
Configuration of PPPoE module.
.TP
-.BI "interface=" ethX
+.BI "interface=" ethX[,padi-limit=n]
Specifies interface name to listen/send discovery packets. You may specify multiple
.B interface
-options.
+options. Optional
+.B padi-limit
+parameter specifies limit of PADI packets to reply on this interface in 1 second period.
.TP
.BI "ac-name=" ac-name
Specifies AC-Name tag value. If absent tag will not be sent.
@@ -260,10 +262,12 @@ If this option is given and
.B n
is greater of zero then pppoe module will produce verbose logging.
.TP
-.TP
.BI "tr101=" 0|1
Specifies whether to handle TR101 tags.
.TP
+.BI "padi-limit=" n
+Specifies overall limit of PADI packets to reply in 1 second period (default 0 - unlimited). Rate of per-mac PADI packets is limited to no more than 1 packet per second.
+.TP
.SH [l2tp]
.br
Configuration of L2TP module.
diff --git a/accel-pppd/ctrl/pppoe/cli.c b/accel-pppd/ctrl/pppoe/cli.c
index 37aec3a2..847b8547 100644
--- a/accel-pppd/ctrl/pppoe/cli.c
+++ b/accel-pppd/ctrl/pppoe/cli.c
@@ -69,6 +69,7 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt,
cli_sendv(client, " active: %u\r\n", stat_active);
cli_sendv(client, " delayed PADO: %u\r\n", stat_delayed_pado);
cli_sendv(client, " recv PADI: %lu\r\n", stat_PADI_recv);
+ cli_sendv(client, " drop PADI: %lu\r\n", stat_PADI_drop);
cli_sendv(client, " sent PADO: %lu\r\n", stat_PADO_sent);
cli_sendv(client, " recv PADR(dup): %lu(%lu)\r\n", stat_PADR_recv, stat_PADR_dup_recv);
cli_sendv(client, " sent PADS: %lu\r\n", stat_PADS_sent);
diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c
index 4d04f07f..ec61cfe0 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.c
+++ b/accel-pppd/ctrl/pppoe/pppoe.c
@@ -64,24 +64,35 @@ struct delayed_pado_t
struct pppoe_tag *service_name;
};
+struct padi_t
+{
+ struct list_head entry;
+ struct timespec ts;
+ uint8_t addr[ETH_ALEN];
+};
+
int conf_verbose;
char *conf_service_name;
char *conf_ac_name;
int conf_ifname_in_sid;
char *conf_pado_delay;
int conf_tr101 = 1;
+int conf_padi_limit = 1000;
static mempool_t conn_pool;
static mempool_t pado_pool;
+static mempool_t padi_pool;
unsigned int stat_starting;
unsigned int stat_active;
unsigned int stat_delayed_pado;
unsigned long stat_PADI_recv;
+unsigned long stat_PADI_drop;
unsigned long stat_PADO_sent;
unsigned long stat_PADR_recv;
unsigned long stat_PADR_dup_recv;
unsigned long stat_PADS_sent;
+unsigned int total_padi_cnt;
pthread_rwlock_t serv_lock = PTHREAD_RWLOCK_INITIALIZER;
LIST_HEAD(serv_list);
@@ -693,6 +704,51 @@ static void pado_timer(struct triton_timer_t *t)
free_delayed_pado(pado);
}
+static int check_padi_limit(struct pppoe_serv_t *serv, uint8_t *addr)
+{
+ struct padi_t *padi;
+ struct timespec ts;
+
+ if (serv->padi_limit == 0)
+ return 0;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ while (!list_empty(&serv->padi_list)) {
+ padi = list_entry(serv->padi_list.next, typeof(*padi), entry);
+ if ((ts.tv_sec - padi->ts.tv_sec) * 1000 + (ts.tv_nsec - padi->ts.tv_nsec) / 1000000 > 1000) {
+ list_del(&padi->entry);
+ mempool_free(padi);
+ __sync_sub_and_fetch(&total_padi_cnt, 1);
+ } else
+ break;
+ }
+
+ if (serv->padi_cnt == serv->padi_limit)
+ return -1;
+
+ if (conf_padi_limit && total_padi_cnt >= conf_padi_limit)
+ return -1;
+
+ list_for_each_entry(padi, &serv->padi_list, entry) {
+ if (memcmp(padi->addr, addr, ETH_ALEN) == 0)
+ return -1;
+ }
+
+ padi = mempool_alloc(padi_pool);
+ if (!padi)
+ return -1;
+
+ padi->ts = ts;
+ memcpy(padi->addr, addr, ETH_ALEN);
+ list_add_tail(&padi->entry, &serv->padi_list);
+ serv->padi_cnt++;
+
+ __sync_add_and_fetch(&total_padi_cnt, 1);
+
+ return 0;
+}
+
static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size)
{
struct ethhdr *ethhdr = (struct ethhdr *)pack;
@@ -709,6 +765,11 @@ static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size)
if (ppp_shutdown || pado_delay == -1)
return;
+ if (check_padi_limit(serv, ethhdr->h_source)) {
+ __sync_add_and_fetch(&stat_PADI_drop, 1);
+ return;
+ }
+
if (hdr->sid) {
log_warn("pppoe: discarding PADI packet (sid is not zero)\n");
return;
@@ -1024,13 +1085,46 @@ static void pppoe_serv_close(struct triton_context_t *ctx)
pthread_mutex_unlock(&serv->lock);
}
-void pppoe_server_start(const char *ifname, void *cli)
+static int parse_server(const char *opt, char **ifname, int *padi_limit)
+{
+ char *str = _strdup(opt);
+ char *ptr1, *ptr2, *endptr;
+
+ ptr1 = strchr(str, ',');
+ if (ptr1) {
+ ptr2 = strstr(ptr1, ",padi-limit=");
+ *padi_limit = strtol(ptr2 + 12, &endptr, 10);
+ if (*endptr != 0 && *endptr != ',')
+ goto out_err;
+
+ *ptr1 = 0;
+ }
+
+ *ifname = str;
+
+ return 0;
+
+out_err:
+ _free(str);
+ return -1;
+}
+
+void pppoe_server_start(const char *opt, void *cli)
{
struct pppoe_serv_t *serv;
int sock;
- int opt = 1;
+ int f = 1;
struct ifreq ifr;
struct sockaddr_ll sa;
+ char *ifname;
+ int padi_limit = conf_padi_limit;
+
+ if (parse_server(opt, &ifname, &padi_limit)) {
+ if (cli)
+ cli_sendv(cli, "failed to parse '%s'\r\n", opt);
+ else
+ log_error("pppoe: failed to parse '%s'\r\n", opt);
+ }
pthread_rwlock_rdlock(&serv_lock);
list_for_each_entry(serv, &serv_list, entry) {
@@ -1062,7 +1156,7 @@ void pppoe_server_start(const char *ifname, void *cli)
return;
}
- if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt))) {
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &f, sizeof(f))) {
if (cli)
cli_sendv(cli, "setsockopt(SO_BROADCAST): %s\r\n", strerror(errno));
log_emerg("pppoe: setsockopt(SO_BROADCAST): %s\n", strerror(errno));
@@ -1141,6 +1235,8 @@ void pppoe_server_start(const char *ifname, void *cli)
INIT_LIST_HEAD(&serv->conn_list);
INIT_LIST_HEAD(&serv->pado_list);
+ INIT_LIST_HEAD(&serv->padi_list);
+ serv->padi_limit = padi_limit;
triton_context_register(&serv->ctx, NULL);
triton_md_register_handler(&serv->ctx, &serv->hnd);
@@ -1298,6 +1394,10 @@ static void load_config(void)
opt = conf_get_opt("pppoe", "tr101");
if (opt)
conf_tr101 = atoi(opt);
+
+ opt = conf_get_opt("pppoe", "padi-limit");
+ if (opt)
+ conf_padi_limit = atoi(opt);
}
static void pppoe_init(void)
@@ -1307,6 +1407,7 @@ static void pppoe_init(void)
conn_pool = mempool_create(sizeof(struct pppoe_conn_t));
pado_pool = mempool_create(sizeof(struct delayed_pado_t));
+ padi_pool = mempool_create(sizeof(struct padi_t));
if (!s) {
log_emerg("pppoe: no configuration, disabled...\n");
diff --git a/accel-pppd/ctrl/pppoe/pppoe.h b/accel-pppd/ctrl/pppoe/pppoe.h
index b8c7281d..ff0fc788 100644
--- a/accel-pppd/ctrl/pppoe/pppoe.h
+++ b/accel-pppd/ctrl/pppoe/pppoe.h
@@ -81,7 +81,12 @@ struct pppoe_serv_t
unsigned int conn_cnt;
struct list_head conn_list;
+
struct list_head pado_list;
+
+ struct list_head padi_list;
+ int padi_cnt;
+ int padi_limit;
};
extern int conf_verbose;
@@ -96,6 +101,7 @@ extern unsigned long stat_PADO_sent;
extern unsigned long stat_PADR_recv;
extern unsigned long stat_PADR_dup_recv;
extern unsigned long stat_PADS_sent;
+extern unsigned long stat_PADI_drop;
extern pthread_rwlock_t serv_lock;
extern struct list_head serv_list;