diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 24d86e7..e03e26d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${ALFREDJSON_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${ZLIB_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS}) link_directories(${JANSSON_LIBRARY_DIRS} ${ZLIB_LIBRARY_DIRS}) -add_executable(alfred-json main.c output_string.c output_json.c output_binary.c zcat.c) +add_executable(alfred-json main.c output_string.c output_json.c output_binary.c zcat.c blacklist.c) set_target_properties(alfred-json PROPERTIES COMPILE_FLAGS "-std=gnu99 -Wall -pedantic" LINK_FLAGS "") target_link_libraries(alfred-json ${ZLIB_LIBRARIES} ${JANSSON_LIBRARIES}) diff --git a/src/blacklist.c b/src/blacklist.c new file mode 100644 index 0000000..3a0504f --- /dev/null +++ b/src/blacklist.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include +#include +#include +#include "blacklist.h" + +struct mac { + uint8_t data[ETH_ALEN]; +}; + +struct blacklist { + struct mac entry; + struct blacklist *next; +}; + +struct blacklist *blacklist_new() { + return calloc(sizeof(struct blacklist), 1); +} + +struct mac *mac_from_string(const char *value) { + struct mac *result = calloc(sizeof(struct mac), 1); + if (NULL == result) + return NULL; + if (6 != sscanf(value, "%02" SCNx8 ":%02" SCNx8 ":%02" SCNx8 ":%02" SCNx8 ":%02" SCNx8 ":%02" SCNx8 "", + &result->data[0], &result->data[1], + &result->data[2], &result->data[3], + &result->data[4], &result->data[5])) { + + free(result); + return NULL; + } + return result; +} + +struct mac *mac_from_data(const void *value, size_t len) { + if (len != ETH_ALEN) + return NULL; + + struct mac *result = calloc(sizeof(struct mac), 1); + if (NULL == result) + return NULL; + memcpy(result->data, value, sizeof(result->data)); + return result; +} + +bool blacklist_is_empty(const struct blacklist *blacklist) { + return NULL == blacklist->next; +} + +void blacklist_append(struct blacklist *blacklist, const struct mac *mac) { + while (true) { + if (NULL == blacklist->next) + break; + blacklist = blacklist->next; + } + blacklist->entry = *mac; + blacklist->next = blacklist_new(); +} + +static inline bool mac_equals(const struct mac *mac1, const struct mac *mac2) { + return (0 == memcmp((const void *)mac1, (const void *)mac2, sizeof(struct mac))); +} + +bool blacklist_match(const struct blacklist *blacklist, const struct mac *mac) { + while (true) { + if (NULL == blacklist->next) + break; + + if (mac_equals(mac, &blacklist->entry)) { + return true; + } + + blacklist = blacklist->next; + } + + return false; +} + +size_t blacklist_size(struct blacklist *blacklist) { + size_t result = 0; + + while (true) { + if (NULL == blacklist->next) + break; + + result++; + blacklist = blacklist->next; + } + + return result; +} diff --git a/src/blacklist.h b/src/blacklist.h new file mode 100644 index 0000000..0c1d3a1 --- /dev/null +++ b/src/blacklist.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +struct blacklist; +struct mac; + +struct mac *mac_from_string(const char *value); +struct mac *mac_from_data(const void *value, size_t len); +struct blacklist *blacklist_new(); +size_t blacklist_size(struct blacklist *blacklist); +void blacklist_append(struct blacklist*, const struct mac *mac); +bool blacklist_match(const struct blacklist *blacklist, const struct mac *mac); diff --git a/src/main.c b/src/main.c index 41693b3..2b31304 100644 --- a/src/main.c +++ b/src/main.c @@ -26,6 +26,7 @@ #include #include #include +#include "blacklist.h" #include "output.h" #include "packet.h" #include "zcat.h" @@ -40,6 +41,7 @@ static void alfred_usage(void) printf(" -f, --format output format (\"json\" (default), \"string\" or \"binary\")\n"); printf(" -s, --socket path to alfred unix socket\n"); printf(" -z, --gzip enable transparent decompression (GZip)\n"); + printf(" -i, --ignore ignore data from given MAC Address (may be repeated)"); printf(" -h, --help this help\n"); printf("\n"); } @@ -63,7 +65,7 @@ int unix_sock_open(const char* path) } int request_data(int sock, int request_type, bool gzip, - const struct output_formatter *output_formatter) + const struct output_formatter *output_formatter, struct blacklist *blacklist) { unsigned char buf[MAX_PAYLOAD], *pos; struct alfred_request_v0 *request; @@ -146,7 +148,8 @@ int request_data(int sock, int request_type, bool gzip, } } - output_formatter->push(formatter_ctx, data->source, ETH_ALEN, pos, data_len); + if (!blacklist_match(blacklist, mac_from_data(data->source, sizeof(data->source)))) + output_formatter->push(formatter_ctx, data->source, ETH_ALEN, pos, data_len); if (buffer_len > 0) free(buffer); @@ -178,6 +181,8 @@ int main(int argc, char *argv[]) bool gzip = false; char *socket_path = "/var/run/alfred.sock"; struct output_formatter output_formatter = output_formatter_json; + struct mac *blacklist_mac; + struct blacklist *blacklist = blacklist_new(); int opt, opt_ind, i; struct option long_options[] = { @@ -185,11 +190,12 @@ int main(int argc, char *argv[]) {"format", required_argument, NULL, 'f'}, {"socket", required_argument, NULL, 's'}, {"gzip", no_argument, NULL, 'z'}, + {"ignore", required_argument, NULL, 'i'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; - while ((opt = getopt_long(argc, argv, "r:f:s:hz", long_options, &opt_ind)) != -1) { + while ((opt = getopt_long(argc, argv, "r:f:s:i:hz", long_options, &opt_ind)) != -1) { switch (opt) { case 'r': i = atoi(optarg); @@ -215,6 +221,14 @@ int main(int argc, char *argv[]) case 's': socket_path = optarg; break; + case 'i': + blacklist_mac = mac_from_string(optarg); + if (NULL != blacklist_mac) { + blacklist_append(blacklist, blacklist_mac); + } else { + fprintf(stderr, "Ignoring invalid MAC address '%s'\n", optarg); + } + break; case 'z': gzip = true; break; @@ -234,7 +248,7 @@ int main(int argc, char *argv[]) if (sock < 0) return 1; - ret = request_data(sock, request, gzip, &output_formatter); + ret = request_data(sock, request, gzip, &output_formatter, blacklist); close(sock); return ret;