diff options
author | Luca Deri <deri@ntop.org> | 2020-11-30 22:01:49 +0100 |
---|---|---|
committer | Luca Deri <deri@ntop.org> | 2020-11-30 22:01:49 +0100 |
commit | eb689b2069ebd9d78e376e812af5163ad61fd7ad (patch) | |
tree | e16b8e15240a729923d87a4ad8995a5e8e96492f | |
parent | b77a4276f9c9273b9abefb76e4c5409265fe747c (diff) |
nDPI rules (work in progress) implementation
-rw-r--r-- | example/ndpiReader.c | 11 | ||||
-rw-r--r-- | rules/sample_rules.txt | 3 | ||||
-rw-r--r-- | src/include/ndpi_api.h.in | 4 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 27 | ||||
-rw-r--r-- | src/lib/ndpi_rules.c | 242 |
5 files changed, 287 insertions, 0 deletions
diff --git a/example/ndpiReader.c b/example/ndpiReader.c index fe81c2265..86dc261a1 100644 --- a/example/ndpiReader.c +++ b/example/ndpiReader.c @@ -3669,6 +3669,16 @@ void analysisUnitTest() { /* *********************************************** */ +void rulesUnitTest() { +#ifdef HAVE_JSON_H +#ifdef DEBUG_RULES + ndpi_parse_rules(ndpi_info_mod, "../rules/sample_rules.txt"); +#endif +#endif +} + +/* *********************************************** */ + /** @brief MAIN FUNCTION **/ @@ -3698,6 +3708,7 @@ int orginal_main(int argc, char **argv) { analyzeUnitTest(); ndpi_self_check_host_match(); analysisUnitTest(); + rulesUnitTest(); memset(ndpi_thread_info, 0, sizeof(ndpi_thread_info)); parseOptions(argc, argv); diff --git a/rules/sample_rules.txt b/rules/sample_rules.txt new file mode 100644 index 000000000..a941e1721 --- /dev/null +++ b/rules/sample_rules.txt @@ -0,0 +1,3 @@ +{"rule":{"id":1,"description":"dummy rule"},"network":{"transport":6,"protocol":"tls"},"client":{"ip":"192.168.0.1/24","port":1234},"server":{"ip":"0.0.0.0/0","port":25}} +{"rule":{"id":2,"description":"dummy rule"},"network":{"transport":"tcp","protocol":"tls"},"action":{"verdict":"pass","marker":1}} +{s"rule":{"id":3},"network":{"transport":"udp","protocol":"dns"}} diff --git a/src/include/ndpi_api.h.in b/src/include/ndpi_api.h.in index fbc9414a4..c0f0042de 100644 --- a/src/include/ndpi_api.h.in +++ b/src/include/ndpi_api.h.in @@ -1426,6 +1426,10 @@ extern "C" { struct ndpi_bin *centroids); u_int32_t ndpi_quick_16_byte_hash(u_int8_t *in_16_bytes_long); + + /* ******************************* */ + + ndpi_rules* ndpi_parse_rules(struct ndpi_detection_module_struct *ndpi_str, char *path); #ifdef __cplusplus } #endif diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 70fab3f75..31043b685 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1553,4 +1553,31 @@ struct ndpi_bin { } u; }; +/* **************************** */ + +typedef struct { + ndpi_ip_addr_t ip; + u_int8_t cidr; + u_int8_t ip_v6:1, _notused:7; + u_int16_t l4_port; +} ndpi_rule_peer; + +typedef enum { + rule_pass, + rule_drop +} ndpi_rule_action; + +typedef struct { + u_int16_t id; + char *description; + u_int8_t l4_proto; + ndpi_rule_action action; + ndpi_rule_peer client, server; /* Network byte order */ + u_int16_t l7_proto; +} ndpi_rule; + +typedef struct { + u_int32_t num_rules; +} ndpi_rules; + #endif /* __NDPI_TYPEDEFS_H__ */ diff --git a/src/lib/ndpi_rules.c b/src/lib/ndpi_rules.c new file mode 100644 index 000000000..8db85d7d3 --- /dev/null +++ b/src/lib/ndpi_rules.c @@ -0,0 +1,242 @@ +/* + * ndpi_rules.c + * + * Copyright (C) 2020 - ntop.org + * + * nDPI is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * nDPI is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with nDPI. If not, see <http://www.gnu.org/licenses/>. + * + */ + + +#include "ndpi_config.h" +#include "ndpi_api.h" +#include "ndpi_includes.h" + +#ifdef HAVE_JSON_H +#include "json.h" /* JSON-C */ +#include <errno.h> + +//#define DEBUG_RULES + +/* ******************************************************* */ + +static u_int8_t ndpi_l4string2value(const char *c) { + if(strcasecmp(c, "tcp") == 0) return(6); + else if(strcasecmp(c, "udp") == 0) return(17); + else if(strcasecmp(c, "icmp") == 0) return(1); + else return(0); +} + +/* ******************************************************* */ + +int ndpi_parse_rule_peer(ndpi_rule_peer *p, json_object *def) { + char *slash, numeric_ip[64]; + u_int8_t cidr = 0; + json_object *obj; + + if(json_object_object_get_ex(def, "ip", &obj)) { + const char *ip = json_object_get_string(obj); + snprintf(numeric_ip, sizeof(numeric_ip), "%s", ip); + } else + return(-1); + + if(json_object_object_get_ex(def, "port", &obj)) + p->l4_port = (u_int16_t)json_object_get_int(obj); + else + return(-2); + + if((slash = strchr(numeric_ip, '/')) != NULL) { + slash[0] = '\0'; + cidr = atoi(&slash[1]); + } + + if(strchr(numeric_ip, '.') != NULL) { + p->ip.ipv4 = inet_addr(numeric_ip); /* IPv4 */ + if(cidr == 0) cidr = 32; + } else if(strchr(numeric_ip, ':') != NULL) { + if(inet_pton(AF_INET6, numeric_ip, &p->ip.ipv6) != 1) + return(-3); + + if(cidr == 0) cidr = 128; + p->ip_v6 = 1; + } else + return(-4); + + p->cidr = cidr; + return(0); +} + +/* ******************************************************* */ + +static int ndpi_parse_line(struct ndpi_detection_module_struct *ndpi_str, + ndpi_rules *rules, u_int line_id, char *line) { + enum json_tokener_error jerr = json_tokener_success; + json_object *obj, *p = json_tokener_parse_verbose(line, &jerr); + ndpi_rule *r; + int rc = 0; + + if(!p) { +#ifdef DEBUG_RULES + printf("[JSON Error @ line %u][%s] %s\n", line_id, json_tokener_error_desc(jerr), line); +#endif + return(-1); + } + + if((r = (ndpi_rule*)calloc(1, sizeof(ndpi_rule))) == NULL) { + rc = -2; + goto parse_error; + } + + /* **************************** */ + + if(json_object_object_get_ex(p, "rule", &obj)) { + json_object *def = obj; + + if(json_object_object_get_ex(def, "id", &obj)) { + r->id = (u_int16_t)json_object_get_int(obj); + } else { +#ifdef DEBUG_RULES + printf("[JSON Error @ line %u] %s\n", line_id, "Missing rule / id"); +#endif + rc = -3; + goto parse_error; + } + + if(json_object_object_get_ex(def, "description", &obj)) { + r->description = strdup(json_object_get_string(obj)); + } else { +#ifdef DEBUG_RULES + printf("[JSON Error @ line %u] %s\n", line_id, "Missing rule / description"); +#endif + rc = -4; + goto parse_error; + } + } + + /* **************************** */ + + if(json_object_object_get_ex(p, "network", &obj)) { + json_object *def = obj; + + if(json_object_object_get_ex(def, "transport", &obj)) { + if(json_object_get_type(obj) == json_type_int) + r->l4_proto = (u_int8_t)json_object_get_int(obj); + else if(json_object_get_type(obj) == json_type_string) { + if((r->l4_proto = ndpi_l4string2value(json_object_get_string(obj))) == 0) { + rc = -5; + goto parse_error; + } + } + } + + if(json_object_object_get_ex(def, "protocol", &obj)) { + if(json_object_get_type(obj) == json_type_int) + r->l7_proto = (u_int16_t)json_object_get_int(obj); + else if(json_object_get_type(obj) == json_type_string) + r->l7_proto = ndpi_get_protocol_id(ndpi_str, + (char*)json_object_get_string(obj)); + else { + rc = -7; + goto parse_error; + } + + if((r->l7_proto == 0) || (r->l7_proto > NDPI_LAST_IMPLEMENTED_PROTOCOL)) { + rc = -8; + goto parse_error; + } + } + } + + /* **************************** */ + + if(json_object_object_get_ex(p, "client", &obj)) { + if(ndpi_parse_rule_peer(&r->client, obj) != 0) { + rc = -9; + goto parse_error; + } + } + + /* **************************** */ + + if(json_object_object_get_ex(p, "server", &obj)) { + if(ndpi_parse_rule_peer(&r->server, obj) != 0) { + rc = -10; + goto parse_error; + } + } + + /* **************************** */ + + if(json_object_object_get_ex(p, "server", &obj)) { + if(ndpi_parse_rule_peer(&r->server, obj) != 0) { + rc = -9; + goto parse_error; + } + } + +#ifdef DEBUG_RULES + printf("[JSON %3u] %s [rc: %u]\n", line_id, line, rc); +#endif + rules->num_rules++; + + parse_error: + json_object_put(p); /* Free memory */ + + return(rc); +} + +/* ******************************************************* */ + +ndpi_rules* ndpi_parse_rules(struct ndpi_detection_module_struct *ndpi_str, + char *path) { + FILE *fd = fopen(path, "r"); + char line[1024]; + u_int line_id = 0; + ndpi_rules *rules; + +#ifdef DEBUG_RULES + + if(!fd) + printf("Unable to open file %s [%u/%s]\n", path, errno, strerror(errno)); +#endif + + if((!fd) || ((rules = (ndpi_rules*)calloc(1, sizeof(ndpi_rules))) == NULL)) + return(NULL); + + while(fgets(line, sizeof(line), fd) != NULL) { + u_int len = strlen(line); + int rc; + + line_id++; + + if(len > 0) { + len--; + if(line[len] == '\n') + line[len] = '\0'; + } + + if((rc = ndpi_parse_line(ndpi_str, rules, line_id, line)) != 0) { +#ifdef DEBUG_RULES + printf("Invalid parsing of line %u [rc: %d]\n", line_id, rc); +#endif + } + } + + fclose(fd); + return(rules); +} + +/* ******************************************************* */ + +#endif /* HAVE_JSON_H */ |