diff options
Diffstat (limited to 'accel-pppd/ctrl/pppoe')
-rw-r--r-- | accel-pppd/ctrl/pppoe/cli.c | 1 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.c | 107 | ||||
-rw-r--r-- | accel-pppd/ctrl/pppoe/pppoe.h | 6 |
3 files changed, 111 insertions, 3 deletions
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; |