diff options
author | Kozlov Dmitry <dima@server> | 2010-11-11 11:45:18 +0300 |
---|---|---|
committer | Kozlov Dmitry <dima@server> | 2010-11-11 11:45:18 +0300 |
commit | dda81cb1d1ba0229aa4c9a90a6f2b2012a4e9326 (patch) | |
tree | cb59715c7ca9e0bd61d35bfccdd0b4a86fe1b4b1 | |
parent | 8c58b84d5d246db41d02ee28448d24a4bfd3c02f (diff) | |
download | accel-ppp-dda81cb1d1ba0229aa4c9a90a6f2b2012a4e9326.tar.gz accel-ppp-dda81cb1d1ba0229aa4c9a90a6f2b2012a4e9326.zip |
pppoe: implemented mac filter
-rw-r--r-- | accel-pptpd/accel-pptp.conf.5 | 6 | ||||
-rw-r--r-- | accel-pptpd/ctrl/pppoe/CMakeLists.txt | 2 | ||||
-rw-r--r-- | accel-pptpd/ctrl/pppoe/mac_filter.c | 283 | ||||
-rw-r--r-- | accel-pptpd/ctrl/pppoe/pppoe.c | 15 | ||||
-rw-r--r-- | accel-pptpd/ctrl/pppoe/pppoe.h | 2 |
5 files changed, 301 insertions, 7 deletions
diff --git a/accel-pptpd/accel-pptp.conf.5 b/accel-pptpd/accel-pptp.conf.5 index 6de19d44..40901531 100644 --- a/accel-pptpd/accel-pptp.conf.5 +++ b/accel-pptpd/accel-pptp.conf.5 @@ -161,6 +161,12 @@ Specifies Service-Name to respond. If absent any Service-Name is acceptable and .BI "pado-delay=" n Specifies delay to send PADO (ms). .TP +.BI "mac-filter=" filename,type +Specifies mac-filter filename and type, type maybe +.B allow +or +.B deny +.TP .BI "verbose=" n If this option is given and .B n diff --git a/accel-pptpd/ctrl/pppoe/CMakeLists.txt b/accel-pptpd/ctrl/pppoe/CMakeLists.txt index dd0f9cd5..54594d9c 100644 --- a/accel-pptpd/ctrl/pppoe/CMakeLists.txt +++ b/accel-pptpd/ctrl/pppoe/CMakeLists.txt @@ -1,5 +1,5 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) -ADD_LIBRARY(pppoe SHARED pppoe.c) +ADD_LIBRARY(pppoe SHARED pppoe.c mac_filter.c) INSTALL(TARGETS pppoe LIBRARY DESTINATION usr/lib/accel-pptp) diff --git a/accel-pptpd/ctrl/pppoe/mac_filter.c b/accel-pptpd/ctrl/pppoe/mac_filter.c new file mode 100644 index 00000000..537c2e51 --- /dev/null +++ b/accel-pptpd/ctrl/pppoe/mac_filter.c @@ -0,0 +1,283 @@ +#include <stdio.h> +#include <string.h> +#include <pthread.h> +#include <errno.h> +#include <netinet/in.h> +#include <net/ethernet.h> + +#include "list.h" +#include "cli.h" +#include "triton.h" +#include "log.h" +#include "memdebug.h" + +#include "pppoe.h" + +struct mac_t +{ + struct list_head entry; + uint8_t addr[ETH_ALEN]; +}; + +static LIST_HEAD(mac_list); +static int type; // -1 - disabled, 1 - allow, 0 - denied +static pthread_rwlock_t lock = PTHREAD_RWLOCK_INITIALIZER; +static const char *conf_mac_filter; + +int mac_filter_check(const uint8_t *addr) +{ + struct mac_t *mac; + int res = type; + + if (type == -1) + return 0; + + pthread_rwlock_rdlock(&lock); + list_for_each_entry(mac, &mac_list, entry) { + if (memcmp(mac->addr, addr, ETH_ALEN)) + continue; + res = !type; + break; + } + pthread_rwlock_unlock(&lock); + + return res; +} + +static int mac_filter_load(const char *opt) +{ + struct mac_t *mac; + FILE *f; + char *c; + char *name = _strdup(opt); + char *buf = _malloc(1024); + int n[ETH_ALEN]; + int i, line = 0; + + c = strstr(name, ","); + if (!c) + goto err_inval; + + *c = 0; + + if (!strcmp(c + 1, "allow")) + type = 1; + else if (!strcmp(c + 1, "deny")) + type = 0; + else + goto err_inval; + + f = fopen(name, "r"); + if (!f) { + log_emerg("pppoe: open '%s': %s\n", name, strerror(errno)); + goto err; + } + + conf_mac_filter = opt; + + pthread_rwlock_wrlock(&lock); + while (!list_empty(&mac_list)) { + mac = list_entry(mac_list.next, typeof(*mac), entry); + list_del(&mac->entry); + _free(mac); + } + + while (fgets(buf, 1024, f)) { + line++; + if (buf[0] == '#' || buf[0] == ';' || buf[0] == '\n') + continue; + if (sscanf(buf, "%x:%x:%x:%x:%x:%x", + n + 0, n + 1, n + 2, n + 3, n + 4, n + 5) != 6) { + log_warn("pppoe: mac-filter:%s:%i: address is invalid\n", name, line); + continue; + } + mac = _malloc(sizeof(*mac)); + for (i = 0; i < ETH_ALEN; i++) { + if (n[i] > 255) { + log_warn("pppoe: mac-filter:%s:%i: address is invalid\n", name, line); + _free(mac); + continue; + } + mac->addr[i] = n[i]; + } + list_add_tail(&mac->entry, &mac_list); + } + pthread_rwlock_unlock(&lock); + + fclose(f); + + _free(name); + _free(buf); + + return 0; + +err_inval: + log_emerg("pppoe: mac-filter format is invalid\n"); +err: + _free(name); + _free(buf); + return -1; +} + +static int mac_filter_add(const char *addr, void *client) +{ + int n[ETH_ALEN]; + struct mac_t *mac; + int i; + + if (sscanf(addr, "%x:%x:%x:%x:%x:%x", + n + 0, n + 1, n + 2, n + 3, n + 4, n + 5) != 6) { + return cli_send(client, "invalid format\r\n"); + } + + mac = _malloc(sizeof(*mac)); + for (i = 0; i < ETH_ALEN; i++) { + if (n[i] > 255) { + _free(mac); + return cli_send(client, "invalid format\r\n"); + } + mac->addr[i] = n[i]; + } + + pthread_rwlock_wrlock(&lock); + list_add_tail(&mac->entry, &mac_list); + pthread_rwlock_unlock(&lock); + + return 0; +} + +static int mac_filter_del(const char *addr, void *client) +{ + int n[ETH_ALEN]; + uint8_t a[ETH_ALEN]; + struct mac_t *mac; + int i; + int found = 0; + + if (sscanf(addr, "%x:%x:%x:%x:%x:%x", + n + 0, n + 1, n + 2, n + 3, n + 4, n + 5) != 6) { + return cli_send(client, "invalid format\r\n"); + } + + for (i = 0; i < ETH_ALEN; i++) { + if (n[i] > 255) { + return cli_send(client, "invalid format\r\n"); + } + a[i] = n[i]; + } + + pthread_rwlock_wrlock(&lock); + list_for_each_entry(mac, &mac_list, entry) { + if (memcmp(a, mac->addr, ETH_ALEN)) + continue; + list_del(&mac->entry); + _free(mac); + found = 1; + break; + } + pthread_rwlock_unlock(&lock); + + if (!found) + return cli_send(client, "not found\r\n"); + + return 0; +} + +static int mac_filter_show(void *client) +{ + struct mac_t *mac; + const char *filter_type; + char buf[64]; + + if (type == 0) + filter_type = "deny"; + else if (type == 1) + filter_type = "allow"; + else + filter_type = "disabled"; + + sprintf(buf, "filter type: %s\r\n", filter_type); + + if (cli_send(client, buf)) + return -1; + + pthread_rwlock_rdlock(&lock); + list_for_each_entry(mac, &mac_list, entry) { + sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\r\n", + mac->addr[0], mac->addr[1], mac->addr[2], + mac->addr[3], mac->addr[4], mac->addr[5]); + if (cli_send(client, buf)) { + pthread_rwlock_unlock(&lock); + return -1; + } + } + pthread_rwlock_unlock(&lock); + + return 0; +} + +static int cmd_help(char * const *fields, int fields_cnt, void *client); +int cmd_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) +{ + if (fields_cnt == 2) + return cmd_help(fields, fields_cnt, client); + + if (!strcmp(fields[2], "reload")) { + if (!conf_mac_filter) { + if (cli_send(client, "error: mac-filter was not specified in the config\r\n")) + return CLI_CMD_FAILED; + } else if (mac_filter_load(conf_mac_filter)) { + if (cli_send(client, "error: check logs\r\n")) + return CLI_CMD_FAILED; + } + } else if (!strcmp(fields[2], "add")) { + if (fields_cnt != 4) + return cmd_help(fields, fields_cnt, client); + if (mac_filter_add(fields[3], client)) + return CLI_CMD_FAILED; + } else if (!strcmp(fields[2], "del")) { + if (fields_cnt != 4) + return cmd_help(fields, fields_cnt, client); + if (mac_filter_del(fields[3], client)) + return CLI_CMD_FAILED; + } else if (!strcmp(fields[2], "show")) { + if (mac_filter_show(client)) + return CLI_CMD_FAILED; + } + return CLI_CMD_OK; +} + +static int cmd_help(char * const *fields, int fields_cnt, void *client) +{ + if (cli_send(client, "pppoe mac-filter reload - reload mac-filter file\r\n")) + return -1; + + if (cli_send(client, "pppoe mac-filter add <address> - add address to mac-filter list\r\n")) + return -1; + + if (cli_send(client, "pppoe mac-filter del <address> - delete address from mac-filter list\r\n")) + return -1; + + if (cli_send(client, "pppoe mac-filter show - show current mac-filter list\r\n")) + return -1; + + return 0; +} + +const char *cmd_hdr[] = {"pppoe", "mac-filter"}; +static struct cli_simple_cmd_t cmd = { + .hdr_len = 2, + .hdr = cmd_hdr, + .exec = cmd_exec, + .help = cmd_help, +}; + +static void __init init(void) +{ + const char *opt = conf_get_opt("pppoe", "mac-filter"); + if (!opt || mac_filter_load(opt)) + type = -1; + + cli_register_simple_cmd(&cmd); +} + diff --git a/accel-pptpd/ctrl/pppoe/pppoe.c b/accel-pptpd/ctrl/pppoe/pppoe.c index ef661bc4..73752920 100644 --- a/accel-pptpd/ctrl/pppoe/pppoe.c +++ b/accel-pptpd/ctrl/pppoe/pppoe.c @@ -791,34 +791,37 @@ static int pppoe_serv_read(struct triton_md_handler_t *h) if (n < ETH_HLEN + sizeof(*hdr)) { if (conf_verbose) log_warn("pppoe: short packet received (%i)\n", n); - return 0; + continue; } + if (mac_filter_check(ethhdr->h_source)) + continue; + if (memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN) && memcmp(ethhdr->h_dest, serv->hwaddr, ETH_ALEN)) - return 0; + continue; if (!memcmp(ethhdr->h_source, bc_addr, ETH_ALEN)) { if (conf_verbose) log_warn("pppoe: discarding packet (host address is broadcast)\n"); - return 0; + continue; } if ((ethhdr->h_source[0] & 1) != 0) { if (conf_verbose) log_warn("pppoe: discarding packet (host address is not unicast)\n"); - return 0; + continue; } if (n < ETH_HLEN + sizeof(*hdr) + ntohs(hdr->length)) { if (conf_verbose) log_warn("pppoe: short packet received\n"); - return 0; + continue; } if (hdr->ver != 1) { if (conf_verbose) log_warn("pppoe: discarding packet (unsupported version %i)\n", hdr->ver); - return 0; + continue; } if (hdr->type != 1) { diff --git a/accel-pptpd/ctrl/pppoe/pppoe.h b/accel-pptpd/ctrl/pppoe/pppoe.h index 05061083..f194172b 100644 --- a/accel-pptpd/ctrl/pppoe/pppoe.h +++ b/accel-pptpd/ctrl/pppoe/pppoe.h @@ -55,5 +55,7 @@ struct pppoe_packet_t struct list_head tags; }; +int mac_filter_check(const uint8_t *addr); + #endif |