aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca Deri <deri@ntop.org>2020-11-30 22:01:49 +0100
committerLuca Deri <deri@ntop.org>2020-11-30 22:01:49 +0100
commiteb689b2069ebd9d78e376e812af5163ad61fd7ad (patch)
treee16b8e15240a729923d87a4ad8995a5e8e96492f
parentb77a4276f9c9273b9abefb76e4c5409265fe747c (diff)
nDPI rules (work in progress) implementation
-rw-r--r--example/ndpiReader.c11
-rw-r--r--rules/sample_rules.txt3
-rw-r--r--src/include/ndpi_api.h.in4
-rw-r--r--src/include/ndpi_typedefs.h27
-rw-r--r--src/lib/ndpi_rules.c242
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 */