diff options
author | Toni <matzeton@googlemail.com> | 2022-07-29 19:29:54 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-07-29 19:29:54 +0200 |
commit | ed4f106a0d6ba2d644e95354891b4b68f927c535 (patch) | |
tree | 9dcd51e78edaa9eb1d41149242ba37fe2eb9811d /src | |
parent | 405a52ed65c0b641b26f0571bf6a6c369c5251d7 (diff) |
Add Softether dissector. (#1679)
Signed-off-by: lns <matzeton@googlemail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_define.h.in | 4 | ||||
-rw-r--r-- | src/include/ndpi_protocols.h | 1 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 7 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 6 | ||||
-rw-r--r-- | src/lib/protocols/softether.c | 379 |
5 files changed, 395 insertions, 2 deletions
diff --git a/src/include/ndpi_define.h.in b/src/include/ndpi_define.h.in index e591f3eda..5c552c0d7 100644 --- a/src/include/ndpi_define.h.in +++ b/src/include/ndpi_define.h.in @@ -390,9 +390,9 @@ static inline u_int64_t get_u_int64_t(const u_int8_t* X, int O) #define htole32(x) (x) #define be32toh(x) ntohl(x) #define le32toh(x) (x) -#define htobe64(x) htonll(x) +#define htobe64(x) ndpi_htonll(x) #define htole64(x) (x) -#define be64toh(x) ntohll(x) +#define be64toh(x) ndpi_ntohll(x) #define le64toh(x) (x) #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ diff --git a/src/include/ndpi_protocols.h b/src/include/ndpi_protocols.h index ebd88a837..f674b2849 100644 --- a/src/include/ndpi_protocols.h +++ b/src/include/ndpi_protocols.h @@ -234,6 +234,7 @@ void init_ultrasurf_dissector(struct ndpi_detection_module_struct *ndpi_struct, void init_threema_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); void init_alicloud_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); void init_avast_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); +void init_softether_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask); /* ndpi_main.c */ extern u_int32_t ndpi_ip_port_hash_funct(u_int32_t ip, u_int16_t port); diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index f5fccfd56..24302075e 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1362,6 +1362,13 @@ struct ndpi_flow_struct { } kerberos; struct { + char ip[16]; + char port[6]; + char hostname[48]; + char fqdn[48]; + } softether; + + struct { char *server_names, *alpn, *tls_supported_versions, *issuerDN, *subjectDN; u_int32_t notBefore, notAfter; char ja3_client[33], ja3_server[33]; diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 8835a0643..3c8d91811 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -4534,6 +4534,9 @@ static int ndpi_callback_init(struct ndpi_detection_module_struct *ndpi_str) { /* AVAST */ init_avast_dissector(ndpi_str, &a, detection_bitmask); + /* Softether */ + init_softether_dissector(ndpi_str, &a, detection_bitmask); + #ifdef CUSTOM_NDPI_PROTOCOLS #include "../../../nDPI-custom/custom_ndpi_main_init.c" #endif @@ -8251,6 +8254,9 @@ u_int8_t ndpi_extra_dissection_possible(struct ndpi_detection_module_struct *ndp case NDPI_PROTOCOL_BITTORRENT: return(1); break; + + case NDPI_PROTOCOL_SOFTETHER: + return(1); } return(0); diff --git a/src/lib/protocols/softether.c b/src/lib/protocols/softether.c new file mode 100644 index 000000000..8a80e6322 --- /dev/null +++ b/src/lib/protocols/softether.c @@ -0,0 +1,379 @@ +/* + * softether.c + * + * Copyright (C) 2022 - 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_protocol_ids.h" + +#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SOFTETHER + +#include "ndpi_api.h" + +enum softether_value_type { + VALUE_INT = 0u, + VALUE_DATA = 1u, + VALUE_STR = 2u, + VALUE_UNISTR = 3u, + VALUE_INT64 = 4u +}; + +union softether_dissected_value { + int value_int; + u_int64_t value_int64; + union { + void const *raw; + u_int8_t const *value_data; + char const *value_str; + char const *value_unistr; + } ptr; +}; + +struct softether_value { + enum softether_value_type type; + union softether_dissected_value value; + u_int32_t value_size; +}; + +static int ndpi_search_softether_again(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow); + +static void ndpi_int_softether_add_connection(struct ndpi_detection_module_struct * const ndpi_struct, + struct ndpi_flow_struct * const flow) +{ + NDPI_LOG_INFO(ndpi_struct, "found softether\n"); + + flow->check_extra_packets = 1; + flow->max_extra_packets_to_check = 15; + flow->extra_packets_func = ndpi_search_softether_again; + + ndpi_set_detected_protocol(ndpi_struct, flow, + NDPI_PROTOCOL_SOFTETHER, + NDPI_PROTOCOL_UNKNOWN, + NDPI_CONFIDENCE_DPI); +} + +static size_t dissect_softether_type(enum softether_value_type t, + struct softether_value *v, + u_int8_t const *payload, + u_int16_t payload_len) +{ + size_t ret = 0; + v->type = t; + v->value_size = 0; + + switch (t) + { + case VALUE_INT: + if (payload_len < 4) + { + return 0; + } + v->value.value_int = ntohl(get_u_int32_t(payload, 0)); + v->value_size = sizeof(v->value.value_int); + ret = v->value_size; + break; + + case VALUE_DATA: + case VALUE_STR: + case VALUE_UNISTR: + if (payload_len < 4) + { + return 0; + } + v->value.ptr.raw = payload + 4; + u_int32_t siz = ntohl(get_u_int32_t(payload, 0)); + if (payload_len < siz + 3) + { + return 0; + } + if (t == VALUE_DATA) + { + siz--; + } + v->value_size = siz; + ret = siz + sizeof(siz); + break; + + case VALUE_INT64: + if (payload_len < 8) + { + return 0; + } + v->value.value_int64 = be64toh(get_u_int64_t(payload, 0)); + v->value_size = sizeof(v->value.value_int64); + ret = v->value_size; + break; + } + + if (ret > payload_len) + { + return 0; + } + + return ret; +} + +static int softether_type_to_enum(u_int32_t type, enum softether_value_type *result) +{ + switch (type) + { + case VALUE_INT: + case VALUE_DATA: + case VALUE_STR: + case VALUE_UNISTR: + case VALUE_INT64: + *result = (enum softether_value_type)type; + return 0; + } + + return 1; +} + +static size_t dissect_softether_tuples(u_int8_t const *payload, u_int16_t payload_len, + struct softether_value *first_value, + struct softether_value *second_value) +{ + enum softether_value_type first_tuple_type; + enum softether_value_type second_tuple_type; + size_t value_siz; + size_t const tuple_type_len = 8; + + if (payload_len < tuple_type_len) + { + return 0; + } + + if (softether_type_to_enum(ntohl(get_u_int32_t(payload, 0)), &first_tuple_type) != 0 || + softether_type_to_enum(ntohl(get_u_int32_t(payload, 4)), &second_tuple_type) != 0) + { + return 0; + } + + payload += tuple_type_len; + payload_len -= tuple_type_len; + + value_siz = dissect_softether_type(first_tuple_type, first_value, payload, payload_len); + + payload += value_siz; + payload_len -= value_siz; + + value_siz += dissect_softether_type(second_tuple_type, second_value, payload, payload_len); + + return value_siz + tuple_type_len; +} + +static int dissect_softether_host_fqdn(struct ndpi_flow_struct *flow, + struct ndpi_packet_struct const *packet) +{ + u_int8_t const *payload = packet->payload; + u_int16_t payload_len = packet->payload_packet_len; + u_int32_t tuple_count; + size_t value_siz; + struct softether_value val1, val2; + uint8_t got_hostname = 0, got_fqdn = 0; + + if (payload_len < 4) + { + return 1; + } + + tuple_count = ntohl(get_u_int32_t(payload, 0)); + if (tuple_count == 0 || tuple_count * 8 > payload_len) + { + return 1; + } + + payload += 4; + payload_len -= 4; + + value_siz = dissect_softether_type(VALUE_DATA, &val1, payload, payload_len); + if (value_siz == 0) + { + return 1; + } + + payload += value_siz; + payload_len -= value_siz; + + if (strncmp(val1.value.ptr.value_str, "host_name", value_siz) == 0) + { + got_hostname = 1; + } + + for (; tuple_count > 0; --tuple_count) + { + value_siz = dissect_softether_tuples(payload, payload_len, &val1, &val2); + if (value_siz == 0) + { + break; + } + + if (got_hostname == 1) + { + if (val1.type == VALUE_STR && val1.value_size > 0) + { + size_t len = ndpi_min(val1.value_size, sizeof(flow->protos.softether.hostname) - 1); + strncpy(flow->protos.softether.hostname, val1.value.ptr.value_str, len); + flow->protos.softether.hostname[len] = '\0'; + } + got_hostname = 0; + } + if (got_fqdn == 1) + { + if (val1.type == VALUE_STR && val1.value_size > 0) + { + size_t len = ndpi_min(val1.value_size, sizeof(flow->protos.softether.fqdn) - 1); + strncpy(flow->protos.softether.fqdn, val1.value.ptr.value_str, len); + flow->protos.softether.fqdn[len] = '\0'; + } + got_fqdn = 0; + } + + if (val2.type == VALUE_DATA && val2.value_size > 0 && + strncmp(val2.value.ptr.value_str, "ddns_fqdn", val2.value_size) == 0) + { + got_fqdn = 1; + } + + payload += value_siz; + payload_len -= value_siz; + } + + if (payload_len != 0) + { + return 1; + } + + return 0; +} + +static int dissect_softether_ip_port(struct ndpi_flow_struct *flow, + struct ndpi_packet_struct const *packet) +{ + char * ip_port_separator; + size_t ip_len, port_len; + + if (packet->payload_packet_len < NDPI_STATICSTRING_LEN("IP=") + + NDPI_STATICSTRING_LEN(",PORT=")) + { + return 1; + } + + if (strncmp((char *)&packet->payload[0], "IP=", NDPI_STATICSTRING_LEN("IP=")) != 0) + { + return 1; + } + + ip_port_separator = ndpi_strnstr((char const *)packet->payload + NDPI_STATICSTRING_LEN("IP="), + ",PORT=", + packet->payload_packet_len - NDPI_STATICSTRING_LEN("IP=")); + if (ip_port_separator == NULL) + { + return 1; + } + + ip_len = ndpi_min(sizeof(flow->protos.softether.ip) - 1, + ip_port_separator - (char const *)packet->payload - + NDPI_STATICSTRING_LEN("IP=")); + strncpy(flow->protos.softether.ip, (char const *)packet->payload + NDPI_STATICSTRING_LEN("IP="), + ip_len); + flow->protos.softether.ip[ip_len] = '\0'; + + port_len = ndpi_min(sizeof(flow->protos.softether.port) - 1, + ip_port_separator - (char const *)packet->payload - + NDPI_STATICSTRING_LEN("IP=") - NDPI_STATICSTRING_LEN(",PORT=")); + strncpy(flow->protos.softether.port, ip_port_separator + NDPI_STATICSTRING_LEN(",PORT="), + port_len); + flow->protos.softether.port[port_len] = '\0'; + + return 0; +} + +void ndpi_search_softether(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ + struct ndpi_packet_struct const * const packet = &ndpi_struct->packet; + + NDPI_LOG_DBG(ndpi_struct, "search softether\n"); + + if (packet->payload_packet_len == 1) + { + if (packet->payload[0] != 0x41 || + flow->packet_counter > 2) + { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + } + + return; + } + + if (packet->payload_packet_len > 9 && packet->payload_packet_len < 30) + { + if (dissect_softether_ip_port(flow, packet) == 0) + { + ndpi_int_softether_add_connection(ndpi_struct, flow); + return; + } + } + + if (packet->payload_packet_len >= 99) + { + if (dissect_softether_host_fqdn(flow, packet) == 0) + { + ndpi_int_softether_add_connection(ndpi_struct, flow); + return; + } + } + + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); +} + +static int ndpi_search_softether_again(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ + if (dissect_softether_ip_port(flow, &ndpi_struct->packet) == 0 || + dissect_softether_host_fqdn(flow, &ndpi_struct->packet) == 0) + { + if (flow->protos.softether.ip[0] != '\0' && flow->protos.softether.port[0] != '\0' && + flow->protos.softether.hostname[0] != '\0' && flow->protos.softether.fqdn[0] != '\0') + { + flow->check_extra_packets = 0; + flow->max_extra_packets_to_check = 0; + flow->extra_packets_func = NULL; + + return 0; + } + } + + return 1; +} + +void init_softether_dissector(struct ndpi_detection_module_struct *ndpi_struct, + u_int32_t *id, NDPI_PROTOCOL_BITMASK *detection_bitmask) +{ + ndpi_set_bitmask_protocol_detection("Softether", ndpi_struct, detection_bitmask, *id, + NDPI_PROTOCOL_SOFTETHER, + ndpi_search_softether, + NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_UDP_WITH_PAYLOAD, + SAVE_DETECTION_BITMASK_AS_UNKNOWN, + ADD_TO_DETECTION_BITMASK + ); + + *id += 1; +} |