diff options
-rw-r--r-- | Makefile | 17 | ||||
-rw-r--r-- | dependencies/nDPIsrvd.h | 121 | ||||
-rw-r--r-- | examples/c-captured/c-captured.c | 60 | ||||
-rwxr-xr-x | examples/py-flow-info/flow-info.py | 13 | ||||
-rwxr-xr-x | examples/py-schema-validation/py-schema-validation.py | 6 | ||||
-rw-r--r-- | nDPId.c | 59 | ||||
-rw-r--r-- | nDPIsrvd.c | 179 | ||||
-rw-r--r-- | schema/basic_event_schema.json | 3 | ||||
-rw-r--r-- | schema/daemon_event_schema.json | 2 | ||||
-rw-r--r-- | schema/flow_event_schema.json | 43 | ||||
-rw-r--r-- | schema/packet_event_schema.json | 3 |
11 files changed, 268 insertions, 238 deletions
@@ -1,8 +1,7 @@ CC = gcc PROJECT_CFLAGS += -Wall -Wextra $(EXTRA_CFLAGS) -I. -JSMN_CFLAGS := -DJSMN_STATIC=1 -DJSMN_STRICT=1 -Idependencies -UTHASH_CFLAGS := -Idependencies/uthash/src -LIBS += -pthread -lpcap -lm +DEPS_CFLAGS := -DJSMN_STATIC=1 -DJSMN_STRICT=1 -Idependencies -Idependencies/uthash/src +LIBS += -pthread -lpcap -lm -lmaxminddb GOCC = GOFLAGS = -ldflags='-s -w' @@ -41,7 +40,7 @@ endif # PKG_CONFIG_BIN ifeq ($(ENABLE_MEMORY_PROFILING),yes) PROJECT_CFLAGS += -DENABLE_MEMORY_PROFILING=1 -UTHASH_CFLAGS += -Duthash_malloc=nDPIsrvd_uthash_malloc -Duthash_free=nDPIsrvd_uthash_free +DEPS_CFLAGS += -Duthash_malloc=nDPIsrvd_uthash_malloc -Duthash_free=nDPIsrvd_uthash_free endif ifeq ($(ENABLE_DEBUG),yes) @@ -72,16 +71,16 @@ all: help nDPId nDPIsrvd examples examples: examples/c-captured/c-captured examples/c-json-stdout/c-json-stdout examples/go-dashboard/go-dashboard nDPId: nDPId.c utils.c - $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $(PC_CFLAGS) $^ -o $@ $(LDFLAGS) $(PC_LDFLAGS) $(STATIC_NDPI_LIB) $(LIBS) + $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $(PC_CFLAGS) $(UTHASH_CFLAGS) $^ -o $@ $(LDFLAGS) $(PC_LDFLAGS) $(STATIC_NDPI_LIB) $(LIBS) nDPIsrvd: nDPIsrvd.c utils.c - $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(STATIC_NDPI_LIB) $(LIBS) + $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $(DEPS_CFLAGS) $^ -o $@ $(LDFLAGS) $(STATIC_NDPI_LIB) $(LIBS) examples/c-captured/c-captured: examples/c-captured/c-captured.c - $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $(JSMN_CFLAGS) $(UTHASH_CFLAGS) $@.c -o $@ $(LDFLAGS) $(LIBS) + $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $(DEPS_CFLAGS) $@.c -o $@ $(LDFLAGS) $(LIBS) examples/c-json-stdout/c-json-stdout: examples/c-json-stdout/c-json-stdout.c - $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $(JSMN_CFLAGS) $@.c -o $@ $(LDFLAGS) $(LIBS) + $(CC) $(PROJECT_CFLAGS) $(CFLAGS) $(DEPS_CFLAGS) $@.c -o $@ $(LDFLAGS) $(LIBS) examples/go-dashboard/go-dashboard: $(GO_DASHBOARD_SRCS) ifneq ($(GOCC),) @@ -154,7 +153,7 @@ run-raw-out: nc -U $(UNIX_SOCK_DISTRIBUTOR) run-nDPIsrvd: nDPIsrvd - ./nDPIsrvd -l -c $(UNIX_SOCK_COLLECTOR) -S $(UNIX_SOCK_DISTRIBUTOR) + ./nDPIsrvd -l -c $(UNIX_SOCK_COLLECTOR) -s $(UNIX_SOCK_DISTRIBUTOR) run-nDPId: nDPId sudo ./nDPId -l -c $(UNIX_SOCK_COLLECTOR) -a run-test -u $(shell id -u -n) diff --git a/dependencies/nDPIsrvd.h b/dependencies/nDPIsrvd.h index d02c46499..fa4425410 100644 --- a/dependencies/nDPIsrvd.h +++ b/dependencies/nDPIsrvd.h @@ -35,7 +35,6 @@ enum nDPIsrvd_connect_return { CONNECT_OK = FIRST_ENUM_VALUE, CONNECT_ERROR_SOCKET, - CONNECT_ERROR_PTON, CONNECT_ERROR, CONNECT_LAST_ENUM_VALUE }; @@ -115,27 +114,27 @@ typedef enum nDPIsrvd_callback_return (*json_callback)(struct nDPIsrvd_socket * typedef void (*flow_end_callback)(struct nDPIsrvd_socket * const sock, struct nDPIsrvd_flow * const flow); +struct nDPIsrvd_address +{ + socklen_t size; + union { + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr raw; + }; +}; + struct nDPIsrvd_socket { int fd; - int socket_family; + struct nDPIsrvd_address address; + size_t flow_user_data_size; struct nDPIsrvd_flow * flow_table; json_callback json_callback; flow_end_callback flow_end_callback; - union { - struct - { - char const * dst_ip; - unsigned short dst_port; - } ip_socket; - struct - { - char * path; - } unix_socket; - } address; - struct { char raw[NETWORK_BUFFER_MAX_SIZE]; @@ -244,7 +243,6 @@ static inline char const * nDPIsrvd_enum_to_string(int enum_value) { static char const * const enum_str[] = {"CONNECT_OK", "CONNECT_ERROR_SOCKET", - "CONNECT_ERROR_PTON", "CONNECT_ERROR", "READ_OK", "READ_PEER_DISCONNECT", @@ -291,7 +289,7 @@ static inline struct nDPIsrvd_socket * nDPIsrvd_init(size_t global_user_data_siz memset(sock, 0, sizeof(*sock)); sock->fd = -1; - sock->socket_family = -1; + sock->address.raw.sa_family = -1; sock->flow_user_data_size = flow_user_data_size; sock->json_callback = json_cb; @@ -357,53 +355,82 @@ static inline void nDPIsrvd_free(struct nDPIsrvd_socket ** const sock) *sock = NULL; } -static inline enum nDPIsrvd_connect_return nDPIsrvd_connect_ip(struct nDPIsrvd_socket * const sock, - char const * dst_ip, - unsigned short dst_port) +static inline int nDPIsrvd_setup_address(struct nDPIsrvd_address * const address, char const * const destination) { - struct sockaddr_in remote_addr = {}; + size_t len = strlen(destination); + char * first_colon = strchr(destination, ':'); + char * last_colon = strrchr(destination, ':'); - sock->socket_family = remote_addr.sin_family = AF_INET; - sock->fd = socket(sock->socket_family, SOCK_STREAM, 0); + memset(address, 0, sizeof(*address)); - if (sock->fd < 0) - { - return CONNECT_ERROR_SOCKET; - } + if (last_colon == NULL) { + address->raw.sa_family = AF_UNIX; + address->size = sizeof(address->un); + if (snprintf(address->un.sun_path, sizeof(address->un.sun_path), "%s", destination) <= 0) + { + return 1; + } + } else { + char addr_buf[INET6_ADDRSTRLEN]; + char const * address_start = destination; + char const * address_end = last_colon; + void * sock_addr; - if (inet_pton(sock->socket_family, &dst_ip[0], &remote_addr.sin_addr) != 1) - { - return CONNECT_ERROR_PTON; - } - remote_addr.sin_port = htons(dst_port); + if (first_colon == last_colon) + { + address->raw.sa_family = AF_INET; + address->size = sizeof(address->in); + address->in.sin_port = htons(atoi(last_colon + 1)); + sock_addr = &address->in.sin_addr; - if (connect(sock->fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) != 0) - { - return CONNECT_ERROR; + if (len < 7) + { + return 1; + } + } else { + address->raw.sa_family = AF_INET6; + address->size = sizeof(address->in6); + address->in6.sin6_port = htons(atoi(last_colon + 1)); + sock_addr = &address->in6.sin6_addr; + + if (len < 2) + { + return 1; + } + if (destination[0] == '[') + { + if (*(last_colon - 1) != ']') + { + return 1; + } + address_start++; + address_end--; + } + } + + if (snprintf(addr_buf, sizeof(addr_buf), "%.*s", (int)(address_end - address_start), address_start) <= 0) + { + return 1; + } + if (inet_pton(address->raw.sa_family, addr_buf, sock_addr) != 1) + { + return 1; + } } - return CONNECT_OK; + return 0; } -static inline enum nDPIsrvd_connect_return nDPIsrvd_connect_unix(struct nDPIsrvd_socket * const sock, - char const * const path) +static inline enum nDPIsrvd_connect_return nDPIsrvd_connect(struct nDPIsrvd_socket * const sock) { - struct sockaddr_un remote_addr = {}; - - sock->socket_family = remote_addr.sun_family = AF_UNIX; - sock->fd = socket(sock->socket_family, SOCK_STREAM, 0); + sock->fd = socket(sock->address.raw.sa_family, SOCK_STREAM, 0); if (sock->fd < 0) { return CONNECT_ERROR_SOCKET; } - if (snprintf(remote_addr.sun_path, sizeof(remote_addr.sun_path), "%s", path) <= 0) - { - return CONNECT_ERROR_SOCKET; - } - - if (connect(sock->fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) != 0) + if (connect(sock->fd, &sock->address.raw, sock->address.size) != 0) { return CONNECT_ERROR; } diff --git a/examples/c-captured/c-captured.c b/examples/c-captured/c-captured.c index 36695e131..688b3d6ea 100644 --- a/examples/c-captured/c-captured.c +++ b/examples/c-captured/c-captured.c @@ -13,6 +13,7 @@ #include <time.h> #include <unistd.h> +#include "config.h" #include "nDPIsrvd.h" #include "utarray.h" @@ -41,12 +42,12 @@ struct flow_user_data UT_array * packets; }; -static int daemonize = 0; struct nDPIsrvd_socket * sock = NULL; static int main_thread_shutdown = 0; -static char const serv_listen_path[] = DISTRIBUTOR_UNIX_SOCKET; -static char const serv_listen_addr[INET_ADDRSTRLEN] = DISTRIBUTOR_HOST; -static uint16_t const serv_listen_port = DISTRIBUTOR_PORT; + +static int daemonize = 0; +static char * pidfile = NULL; +static char * serv_optarg = NULL; #ifdef pcap_dump_open_append static time_t pcap_filename_rotation = 600; static time_t pcap_filename_last_rotation = 0; @@ -408,18 +409,20 @@ static int parse_options(int argc, char ** argv) static char const usage[] = "Usage: %s " - "[-d] [-s host] [-S host] [-R rotate-every-n-seconds] [-g] [-u]\n"; + "[-d] [-p pidfile] [-s host] [-R rotate-every-n-seconds] [-g] [-u]\n"; - while ((opt = getopt(argc, argv, "hds:R:gu")) != -1) + while ((opt = getopt(argc, argv, "hdp:s:R:g:u:")) != -1) { switch (opt) { case 'd': daemonize = 1; break; - case 's': + case 'p': break; - case 'S': + case 's': + free(serv_optarg); + serv_optarg = strdup(optarg); break; case 'R': break; @@ -433,6 +436,17 @@ static int parse_options(int argc, char ** argv) } } + if (serv_optarg == NULL) + { + serv_optarg = strdup(DISTRIBUTOR_UNIX_SOCKET); + } + + if (nDPIsrvd_setup_address(&sock->address, serv_optarg) != 0) + { + fprintf(stderr, "%s: Could not parse address `%s'\n", argv[0], serv_optarg); + return 1; + } + if (optind < argc) { fprintf(stderr, "Unexpected argument after options\n\n"); @@ -452,35 +466,23 @@ int main(int argc, char ** argv) return 1; } + if (parse_options(argc, argv) != 0) + { + fprintf(stderr, "%s: Could not parse command line arguments.\n", argv[0]); + return 1; + } + signal(SIGINT, sighandler); signal(SIGTERM, sighandler); signal(SIGPIPE, sighandler); - enum nDPIsrvd_connect_return connect_ret = CONNECT_ERROR; - printf("Recv buffer size: %u\n", NETWORK_BUFFER_MAX_SIZE); - if (argc == 2) - { - printf("Connecting to UNIX socket: %s\n", argv[1]); - connect_ret = nDPIsrvd_connect_unix(sock, argv[1]); - } - else if (argc == 1) - { - if (access(serv_listen_path, R_OK) == 0) - { - printf("Connecting to %s\n", serv_listen_path); - connect_ret = nDPIsrvd_connect_unix(sock, serv_listen_path); - } - else - { - printf("Connecting to %s:%u\n", serv_listen_addr, serv_listen_port); - connect_ret = nDPIsrvd_connect_ip(sock, serv_listen_addr, serv_listen_port); - } - } + printf("Connecting to `%s'..\n", serv_optarg); + enum nDPIsrvd_connect_return connect_ret = nDPIsrvd_connect(sock); if (connect_ret != CONNECT_OK) { - fprintf(stderr, "%s: nDPIsrvd socket connect failed!\n", argv[0]); + fprintf(stderr, "%s: nDPIsrvd socket connect to %s failed!\n", argv[0], serv_optarg); nDPIsrvd_free(&sock); return 1; } diff --git a/examples/py-flow-info/flow-info.py b/examples/py-flow-info/flow-info.py index 62e43f74b..a98b0743e 100755 --- a/examples/py-flow-info/flow-info.py +++ b/examples/py-flow-info/flow-info.py @@ -11,11 +11,16 @@ def prettifyEvent(color_list, whitespaces, text): term_attrs = str() for color in color_list: term_attrs += str(color) - return '{}{:>' + str(whitespaces) + '}{}'.format(term_attrs, text, TermColor.END) + fmt = '{}{:>' + str(whitespaces) + '}{}' + return fmt.format(term_attrs, text, TermColor.END) def onJsonLineRecvd(json_dict, current_flow, global_user_data): + instance_and_source = '' + instance_and_source += '[{}]'.format(TermColor.setColorByString(json_dict['alias'])) + instance_and_source += '[{}]'.format(TermColor.setColorByString(json_dict['source'])) + if 'basic_event_id' in json_dict: - print('{}: {}'.format(prettifyEvent([TermColor.WARNING, TermColor.BLINK], 16, 'BASIC-EVENT'), json_dict['basic_event_name'])) + print('{} {}: {}'.format(instance_and_source, prettifyEvent([TermColor.WARNING, TermColor.BLINK], 16, 'BASIC-EVENT'), json_dict['basic_event_name'])) return True elif 'flow_event_id' not in json_dict: return True @@ -40,10 +45,6 @@ def onJsonLineRecvd(json_dict, current_flow, global_user_data): else TermColor.FAIL + TermColor.BOLD + TermColor.BLINK + 'RISK' + TermColor.END, ndpi_frisk[:-2]) - instance_and_source = '' - instance_and_source += '[{}]'.format(TermColor.setColorByString(json_dict['alias'])) - instance_and_source += '[{}]'.format(TermColor.setColorByString(json_dict['source'])) - line_suffix = '' flow_event_name = '' if json_dict['flow_event_name'] == 'guessed' or json_dict['flow_event_name'] == 'not-detected': diff --git a/examples/py-schema-validation/py-schema-validation.py b/examples/py-schema-validation/py-schema-validation.py index 407c7b814..ca269e0c3 100755 --- a/examples/py-schema-validation/py-schema-validation.py +++ b/examples/py-schema-validation/py-schema-validation.py @@ -10,7 +10,7 @@ from nDPIsrvd import nDPIsrvdSocket, TermColor class Stats: lines_processed = 0 print_dot_every = 10 - next_lines_print = print_dot_every + print_nmb_every = print_dot_every * 5 def onJsonLineRecvd(json_dict, current_flow, global_user_data): validation_done = nDPIsrvd.validateAgainstSchema(json_dict) @@ -19,8 +19,8 @@ def onJsonLineRecvd(json_dict, current_flow, global_user_data): if global_user_data.lines_processed % global_user_data.print_dot_every == 0: sys.stdout.write('.') sys.stdout.flush() - if global_user_data.lines_processed == global_user_data.next_lines_print: - global_user_data.next_lines_print *= 2 + print_nmb_every = global_user_data.print_nmb_every + (len(str(global_user_data.lines_processed)) * global_user_data.print_dot_every) + if global_user_data.lines_processed % print_nmb_every == 0: sys.stdout.write(str(global_user_data.lines_processed)) sys.stdout.flush() @@ -36,7 +36,8 @@ enum nDPId_l3_type L3_IP6 }; -union nDPId_ip { +union nDPId_ip +{ struct { uint32_t ip; @@ -60,8 +61,8 @@ enum nDPId_flow_type struct nDPId_flow_basic { enum nDPId_flow_type type; - uint64_t hashval; enum nDPId_l3_type l3_type; + uint64_t hashval; union nDPId_ip src; union nDPId_ip dst; uint8_t l4_protocol; @@ -97,17 +98,20 @@ struct nDPId_flow_info struct ndpi_proto detected_l7_protocol; struct ndpi_proto guessed_l7_protocol; - union { + union + { uint8_t ndpi_flow_raw[SIZEOF_FLOW_STRUCT]; struct ndpi_flow_struct ndpi_flow; }; - union { + union + { uint8_t ndpi_src_raw[SIZEOF_ID_STRUCT]; struct ndpi_id_struct ndpi_src; }; - union { + union + { uint8_t ndpi_dst_raw[SIZEOF_ID_STRUCT]; struct ndpi_id_struct ndpi_dst; }; @@ -212,9 +216,8 @@ enum daemon_event DAEMON_EVENT_COUNT }; -static char const * const packet_event_name_table[PACKET_EVENT_COUNT] = {[PACKET_EVENT_INVALID] = "invalid", - [PACKET_EVENT_PAYLOAD] = "packet", - [PACKET_EVENT_PAYLOAD_FLOW] = "packet-flow"}; +static char const * const packet_event_name_table[PACKET_EVENT_COUNT] = { + [PACKET_EVENT_INVALID] = "invalid", [PACKET_EVENT_PAYLOAD] = "packet", [PACKET_EVENT_PAYLOAD_FLOW] = "packet-flow"}; static char const * const flow_event_name_table[FLOW_EVENT_COUNT] = {[FLOW_EVENT_INVALID] = "invalid", [FLOW_EVENT_NEW] = "new", @@ -273,6 +276,8 @@ static int log_to_stderr = 0; static char pidfile[UNIX_PATH_MAX] = nDPId_PIDFILE; static char * user = "nobody"; static char * group = NULL; +static char * custom_protocols_file = NULL; +static char * custom_categories_file = NULL; static char json_sockpath[UNIX_PATH_MAX] = COLLECTOR_UNIX_SOCKET; /* subopts */ @@ -584,8 +589,18 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device) NDPI_PROTOCOL_BITMASK protos; NDPI_BITMASK_SET_ALL(protos); ndpi_set_protocol_detection_bitmask2(workflow->ndpi_struct, &protos); + if (custom_protocols_file != NULL) + { + ndpi_load_protocols_file(workflow->ndpi_struct, custom_protocols_file); + } + if (custom_categories_file != NULL) + { + ndpi_load_categories_file(workflow->ndpi_struct, custom_categories_file); + } ndpi_finalize_initalization(workflow->ndpi_struct); + ndpi_set_detection_preferences(workflow->ndpi_struct, ndpi_pref_enable_tls_block_dissection, 1); + if (ndpi_init_serializer_ll(&workflow->ndpi_serializer, ndpi_serialization_format_json, NETWORK_BUFFER_MAX_SIZE) != 1) { @@ -2618,11 +2633,16 @@ static int parse_options(int argc, char ** argv) int opt; static char const usage[] = + "(C) 2020-2021 Toni Uhlig\n" + "Please report any BUG to toni@impl.cc\n\n" "Usage: %s " - "[-i pcap-file/interface] [-I] [-E] [-P bpf-filter]" + "[-i pcap-file/interface] [-I] [-E] [-B bpf-filter]\n" + "\t \t" "[-l] [-c path-to-unix-sock] " - "[-d] [-p pidfile] " + "[-d] [-p pidfile]\n" + "\t \t" "[-u user] [-g group] " + "[-P path] [-C path] " "[-a instance-alias] " "[-o subopt=value]\n\n" "\t-i\tInterface or file from where to read packets from.\n" @@ -2630,19 +2650,21 @@ static int parse_options(int argc, char ** argv) "\t \tis part of the interface subnet. (Internal mode)\n" "\t-E\tProcess only packets where the source address of the first packet\n" "\t \tis *NOT* part of the interface subnet. (External mode)\n" - "\t-P\tSet an optional berkeley packet filter.\n" - "\t-l\tLog all messages to stderr as well.\n" + "\t-B\tSet an optional PCAP filter string. (BPF format)\n" + "\t-l\tLog all messages to stderr as well. Logging via Syslog is always enabled.\n" "\t-c\tPath to the Collector UNIX socket which acts as the JSON sink.\n" "\t-d\tForking into background after initialization.\n" "\t-p\tWrite the daemon PID to the given file path.\n" "\t-u\tChange UID to the numeric value of user.\n" "\t-g\tChange GID to the numeric value of group.\n" + "\t-P\tLoad a nDPI custom protocols file.\n" + "\t-C\tLoad a nDPI custom categories file.\n" "\t-a\tSet an alias name of this daemon instance which will be part of every JSON message.\n" "\t \tThis value is required for correct flow handling of multiple instances and should be unique.\n" "\t \tDefaults to your hostname.\n" "\t-o\t(Carefully) Tune some daemon options. See subopts below.\n\n"; - while ((opt = getopt(argc, argv, "hi:IEP:lc:dp:u:g:a:o:")) != -1) + while ((opt = getopt(argc, argv, "hi:IEB:lc:dp:u:g:P:C:a:o:")) != -1) { switch (opt) { @@ -2655,7 +2677,7 @@ static int parse_options(int argc, char ** argv) case 'E': process_external_initial_direction = 1; break; - case 'P': + case 'B': bpf_str = strdup(optarg); break; case 'l': @@ -2685,6 +2707,12 @@ static int parse_options(int argc, char ** argv) case 'g': group = strdup(optarg); break; + case 'P': + custom_protocols_file = strdup(optarg); + break; + case 'C': + custom_categories_file = strdup(optarg); + break; case 'a': instance_alias = strdup(optarg); break; @@ -2903,13 +2931,11 @@ int main(int argc, char ** argv) if (setup_reader_threads() != 0) { - syslog(LOG_DAEMON | LOG_ERR, "setup_reader_threads failed"); return 1; } if (start_reader_threads() != 0) { - syslog(LOG_DAEMON | LOG_ERR, "start_reader_threads failed"); return 1; } @@ -2924,7 +2950,6 @@ int main(int argc, char ** argv) if (main_thread_shutdown == 1 && stop_reader_threads() != 0) { - syslog(LOG_DAEMON | LOG_ERR, "stop_reader_threads"); return 1; } free_reader_threads(); diff --git a/nDPIsrvd.c b/nDPIsrvd.c index d9d3e3777..2e19c115a 100644 --- a/nDPIsrvd.c +++ b/nDPIsrvd.c @@ -2,7 +2,6 @@ #include <errno.h> #include <fcntl.h> #include <netdb.h> -#include <linux/un.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -15,6 +14,7 @@ #include <unistd.h> #include "config.h" +#include "nDPIsrvd.h" #include "utils.h" struct io_buffer @@ -58,12 +58,10 @@ static struct remotes static int main_thread_shutdown = 0; static int log_to_stderr = 0; -static char pidfile[UNIX_PATH_MAX] = nDPIsrvd_PIDFILE; -static char json_sockpath[UNIX_PATH_MAX] = COLLECTOR_UNIX_SOCKET; -static enum { SERV_LISTEN_NONE, SERV_LISTEN_TCP, SERV_LISTEN_UNIX } serv_type = SERV_LISTEN_NONE; -static char serv_listen_addr[INET_ADDRSTRLEN] = DISTRIBUTOR_HOST; -static char serv_listen_path[UNIX_PATH_MAX] = DISTRIBUTOR_UNIX_SOCKET; -static uint16_t serv_listen_port = DISTRIBUTOR_PORT; +static char * pidfile = NULL; +static char * json_sockpath = NULL; +static char * serv_optarg = NULL; +static struct nDPIsrvd_address serv_address = { .raw.sa_family = 0xFFFF, }; static int json_sockfd; static int serv_sockfd; static char * user = NULL; @@ -72,7 +70,7 @@ static char * group = NULL; static int create_listen_sockets(void) { json_sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - serv_sockfd = socket((serv_type == SERV_LISTEN_TCP ? AF_INET : AF_UNIX), SOCK_STREAM, 0); + serv_sockfd = socket(serv_address.raw.sa_family, SOCK_STREAM, 0); if (json_sockfd < 0 || serv_sockfd < 0) { syslog(LOG_DAEMON | LOG_ERR, "Error opening socket: %s", strerror(errno)); @@ -95,66 +93,18 @@ static int create_listen_sockets(void) return 1; } - struct sockaddr * addr; - socklen_t addrlen; - struct sockaddr_in serv_addr_in; - struct sockaddr_un serv_addr_un; - - switch (serv_type) - { - case SERV_LISTEN_TCP: - memset(&serv_addr_in, 0, sizeof(serv_addr_in)); - serv_addr_in.sin_family = AF_INET; - if (inet_pton(AF_INET, &serv_listen_addr[0], &serv_addr_in.sin_addr) != 1) - { - syslog(LOG_DAEMON | LOG_ERR, "Error converting an internet address: %s", strerror(errno)); - return 1; - } - serv_addr_in.sin_port = htons(serv_listen_port); - addr = (struct sockaddr *)&serv_addr_in; - addrlen = sizeof(serv_addr_in); - break; - case SERV_LISTEN_NONE: - case SERV_LISTEN_UNIX: - memset(&serv_addr_un, 0, sizeof(serv_addr_un)); - serv_addr_un.sun_family = AF_UNIX; - if (snprintf(serv_addr_un.sun_path, sizeof(serv_addr_un.sun_path), "%s", serv_listen_path) <= 0) - { - syslog(LOG_DAEMON | LOG_ERR, "snprintf failed: %s", strerror(errno)); - return 1; - } - addr = (struct sockaddr *)&serv_addr_un; - addrlen = sizeof(serv_addr_un); - break; - } - if (bind(json_sockfd, (struct sockaddr *)&json_addr, sizeof(json_addr)) < 0) { unlink(json_sockpath); - syslog(LOG_DAEMON | LOG_ERR, "Error on binding the UNIX socket to %s: %s", json_sockpath, strerror(errno)); + syslog(LOG_DAEMON | LOG_ERR, "Error on binding UNIX socket (collector) to %s: %s", json_sockpath, strerror(errno)); return 1; } - if (bind(serv_sockfd, addr, addrlen) < 0) + if (bind(serv_sockfd, &serv_address.raw, serv_address.size) < 0) { + syslog(LOG_DAEMON | LOG_ERR, + "Error on binding socket (distributor) to %s: %s", serv_optarg, strerror(errno)); unlink(json_sockpath); - switch (serv_type) - { - case SERV_LISTEN_TCP: - syslog(LOG_DAEMON | LOG_ERR, - "Error on binding the INET socket to %s:%u: %s", - serv_listen_addr, - serv_listen_port, - strerror(errno)); - break; - case SERV_LISTEN_NONE: - case SERV_LISTEN_UNIX: - syslog(LOG_DAEMON | LOG_ERR, - "Error on binding the UNIX socket to %s: %s", - serv_listen_path, - strerror(errno)); - break; - } return 1; } @@ -241,7 +191,7 @@ static int parse_options(int argc, char ** argv) { int opt; - while ((opt = getopt(argc, argv, "hlc:dp:s:S:u:g:")) != -1) + while ((opt = getopt(argc, argv, "hlc:dp:s:u:g:")) != -1) { switch (opt) { @@ -249,73 +199,64 @@ static int parse_options(int argc, char ** argv) log_to_stderr = 1; break; case 'c': - snprintf(json_sockpath, sizeof(json_sockpath), "%s", optarg); + free(json_sockpath); + json_sockpath = strdup(optarg); break; case 'd': daemonize_enable(); break; case 'p': - snprintf(pidfile, sizeof(pidfile), "%s", optarg); + free(pidfile); + pidfile = strdup(optarg); break; case 's': - { - if (serv_type != SERV_LISTEN_NONE) - { - fprintf(stderr, "%s: -s / -S already set\n", argv[0]); - return 1; - } - - char * delim = strchr(optarg, ':'); - if (delim != NULL) - { - char * endptr = NULL; - errno = 0; - serv_listen_port = strtoul(delim + 1, &endptr, 10); - if (endptr == delim + 1 || errno != 0) - { - fprintf(stderr, "%s: invalid port number \"%s\"\n", argv[0], delim + 1); - return 1; - } - } - size_t len = (delim != NULL ? (size_t)(delim - optarg) : strlen(optarg)) + 1; - snprintf(serv_listen_addr, - (len < sizeof(serv_listen_addr) ? len : sizeof(serv_listen_addr)), - "%s", - optarg); - serv_type = SERV_LISTEN_TCP; - break; - } - case 'S': - { - if (serv_type != SERV_LISTEN_NONE) - { - fprintf(stderr, "%s: -s / -S already set\n", argv[0]); - return 1; - } - - size_t len = strlen(optarg) + 1; - snprintf(serv_listen_path, - (len < sizeof(serv_listen_path) ? len : sizeof(serv_listen_path)), - "%s", - optarg); - serv_type = SERV_LISTEN_UNIX; + free(serv_optarg); + serv_optarg = strdup(optarg); break; - } case 'u': + free(user); user = strdup(optarg); break; case 'g': + free(group); group = strdup(optarg); break; default: fprintf(stderr, - "Usage: %s [-l] [-c path-to-unix-sock] [-d] [-p pidfile] [-s distributor-host:port] " - "[-S path-to-unix-socket] [-u user] [-g group]\n", + "Usage: %s [-l] [-c path-to-unix-sock] [-d] [-p pidfile] " + "[-s path-to-unix-socket|distributor-host:port] [-u user] [-g group]\n", argv[0]); return 1; } } + if (pidfile == NULL) + { + pidfile = strdup(nDPIsrvd_PIDFILE); + } + + if (json_sockpath == NULL) + { + json_sockpath = strdup(COLLECTOR_UNIX_SOCKET); + } + + if (serv_optarg == NULL) + { + serv_optarg = strdup(DISTRIBUTOR_UNIX_SOCKET); + } + + if (nDPIsrvd_setup_address(&serv_address, serv_optarg) != 0) + { + fprintf(stderr, "%s: Could not parse address `%s'\n", argv[0], serv_optarg); + return 1; + } + + if (optind < argc) + { + fprintf(stderr, "%s: Unexpected argument after options\n", argv[0]); + return 1; + } + return 0; } @@ -368,26 +309,24 @@ int main(int argc, char ** argv) goto error; } syslog(LOG_DAEMON, "collector listen on %s", json_sockpath); - switch (serv_type) - { - case SERV_LISTEN_TCP: - syslog(LOG_DAEMON, - "distributor listen on %.*s:%u", - (int)sizeof(serv_listen_addr), - serv_listen_addr, - serv_listen_port); + switch (serv_address.raw.sa_family) + { + default: + goto error; + case AF_INET: + case AF_INET6: + syslog(LOG_DAEMON, "distributor listen on %s", serv_optarg); syslog(LOG_DAEMON | LOG_ERR, "Please keep in mind that using a TCP Socket may leak sensitive information to " "everyone with access to the device/network. You've been warned!"); break; - case SERV_LISTEN_NONE: - case SERV_LISTEN_UNIX: - syslog(LOG_DAEMON, "distributor listen on %s", serv_listen_path); + case AF_UNIX: + syslog(LOG_DAEMON, "distributor listen on %s", json_sockpath); break; } errno = 0; - if (change_user_group(user, group, pidfile, json_sockpath, serv_listen_path) != 0) + if (change_user_group(user, group, pidfile, json_sockpath, (serv_address.raw.sa_family == AF_UNIX ? serv_optarg : NULL)) != 0) { if (errno != 0) { @@ -761,7 +700,7 @@ error: closelog(); unlink(json_sockpath); - unlink(serv_listen_path); + unlink(serv_optarg); return 0; } diff --git a/schema/basic_event_schema.json b/schema/basic_event_schema.json index 626602ad2..958b4316c 100644 --- a/schema/basic_event_schema.json +++ b/schema/basic_event_schema.json @@ -19,7 +19,8 @@ "type": "number" }, "packet_id": { - "type": "number" + "type": "number", + "minimum": 0 }, "basic_event_id": { "type": "number", diff --git a/schema/daemon_event_schema.json b/schema/daemon_event_schema.json index 020b55161..7a40a6ca0 100644 --- a/schema/daemon_event_schema.json +++ b/schema/daemon_event_schema.json @@ -22,7 +22,7 @@ }, "packet_id": { "type": "number", - "minimum": 1 + "minimum": 0 }, "daemon_event_id": { "type": "number", diff --git a/schema/flow_event_schema.json b/schema/flow_event_schema.json index 6ed7c4615..60d36a4de 100644 --- a/schema/flow_event_schema.json +++ b/schema/flow_event_schema.json @@ -35,7 +35,7 @@ }, "packet_id": { "type": "number", - "minimum": 1 + "minimum": 0 }, "flow_event_id": { "type": "number", @@ -100,7 +100,7 @@ "type": "string", "oneOf": [ { - "pattern": "[0-9]+" + "pattern": "^[0-9]+$" }, { "enum": [ @@ -118,10 +118,18 @@ "maximum": 1 }, "src_ip": { - "type": "string" + "type": "string", + "anyOf" : [ + { "format": "ipv4" }, + { "format": "ipv6" } + ] }, "dst_ip": { - "type": "string" + "type": "string", + "anyOf" : [ + { "format": "ipv4" }, + { "format": "ipv6" } + ] }, "src_port": { "type": "number", @@ -136,21 +144,48 @@ "ndpi": { "type": "object" }, + "dhcp": { + "type": "object" + }, + "bittorrent": { + "type": "object" + }, + "mdns": { + "type": "object" + }, + "ubntac2": { + "type": "object" + }, + "kerberos": { + "type": "object" + }, + "telnet": { + "type": "object" + }, "tls": { "type": "object" }, "quic": { "type": "object" }, + "imap": { + "type": "object" + }, "http": { "type": "object" }, + "pop": { + "type": "object" + }, "smtp": { "type": "object" }, "dns": { "type": "object" }, + "ftp": { + "type": "object" + }, "ssh": { "type": "object" } diff --git a/schema/packet_event_schema.json b/schema/packet_event_schema.json index d3f5a77d9..6f722bf6f 100644 --- a/schema/packet_event_schema.json +++ b/schema/packet_event_schema.json @@ -19,7 +19,8 @@ "type": "number" }, "packet_id": { - "type": "number" + "type": "number", + "minimum": 0 }, "packet_event_id": { "type": "number", |