diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/ndpi_protocol_ids.h | 1 | ||||
-rw-r--r-- | src/include/ndpi_typedefs.h | 3 | ||||
-rw-r--r-- | src/lib/inc_generated/ndpi_asn_roblox.c.inc | 31 | ||||
-rw-r--r-- | src/lib/ndpi_content_match.c.inc | 3 | ||||
-rw-r--r-- | src/lib/ndpi_main.c | 6 | ||||
-rw-r--r-- | src/lib/protocols/raknet.c | 97 |
6 files changed, 118 insertions, 23 deletions
diff --git a/src/include/ndpi_protocol_ids.h b/src/include/ndpi_protocol_ids.h index 7f9bb7c50..099127dff 100644 --- a/src/include/ndpi_protocol_ids.h +++ b/src/include/ndpi_protocol_ids.h @@ -374,6 +374,7 @@ typedef enum { NDPI_PROTOCOL_BITCOIN = 343, NDPI_PROTOCOL_PROTONVPN = 344, NDPI_PROTOCOL_APACHE_THRIFT = 345, + NDPI_PROTOCOL_ROBLOX = 346, #ifdef CUSTOM_NDPI_PROTOCOLS #include "../../../nDPI-custom/custom_ndpi_protocol_ids.h" diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 9c1f353c6..08ba99ef0 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -862,6 +862,9 @@ struct ndpi_flow_udp_struct { u_int32_t epicgames_stage:1; u_int32_t epicgames_word; + /* NDPI_PROTOCOL_RAKNET */ + u_int32_t raknet_custom:1; + /* NDPI_PROTOCOL_SKYPE */ u_int8_t skype_crc[4]; diff --git a/src/lib/inc_generated/ndpi_asn_roblox.c.inc b/src/lib/inc_generated/ndpi_asn_roblox.c.inc new file mode 100644 index 000000000..402b65690 --- /dev/null +++ b/src/lib/inc_generated/ndpi_asn_roblox.c.inc @@ -0,0 +1,31 @@ +/* + * + * This file is generated automatically and part of nDPI + * + * 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/>. + * + */ + +/* ****************************************************** */ + + +static ndpi_network ndpi_protocol_roblox_protocol_list[] = { + { 0x678C1C00 /* 103.140.28.0/23 */, 23, NDPI_PROTOCOL_ROBLOX }, + { 0x80740000 /* 128.116.0.0/17 */, 17, NDPI_PROTOCOL_ROBLOX }, + { 0x8DC10300 /* 141.193.3.0/24 */, 24, NDPI_PROTOCOL_ROBLOX }, + { 0xCDC93E00 /* 205.201.62.0/24 */, 24, NDPI_PROTOCOL_ROBLOX }, + { 0xD1CE2800 /* 209.206.40.0/21 */, 21, NDPI_PROTOCOL_ROBLOX }, + /* End */ + { 0x0, 0, 0 } +}; diff --git a/src/lib/ndpi_content_match.c.inc b/src/lib/ndpi_content_match.c.inc index f3731bfbf..f6faf72ca 100644 --- a/src/lib/ndpi_content_match.c.inc +++ b/src/lib/ndpi_content_match.c.inc @@ -1396,6 +1396,9 @@ static ndpi_protocol_match host_match[] = { "proton.me", "ProtonVPN", NDPI_PROTOCOL_PROTONVPN, NDPI_PROTOCOL_CATEGORY_VPN, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DEFAULT_LEVEL }, { "protonvpn.com", "ProtonVPN", NDPI_PROTOCOL_PROTONVPN, NDPI_PROTOCOL_CATEGORY_VPN, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_DEFAULT_LEVEL }, + { "roblox.com", "Roblox", NDPI_PROTOCOL_ROBLOX, NDPI_PROTOCOL_CATEGORY_GAME, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_DEFAULT_LEVEL }, + { "rbxcdn.com", "Roblox", NDPI_PROTOCOL_ROBLOX, NDPI_PROTOCOL_CATEGORY_GAME, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_DEFAULT_LEVEL }, + /* ADS/tracking/analytic */ diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c index 65257593e..83c3b786e 100644 --- a/src/lib/ndpi_main.c +++ b/src/lib/ndpi_main.c @@ -110,6 +110,7 @@ #include "inc_generated/ndpi_asn_hulu.c.inc" #include "inc_generated/ndpi_asn_epicgames.c.inc" #include "inc_generated/ndpi_asn_nvidia.c.inc" +#include "inc_generated/ndpi_asn_roblox.c.inc" /* Third party libraries */ #include "third_party/include/ndpi_patricia.h" @@ -2108,6 +2109,10 @@ static void ndpi_init_protocol_defaults(struct ndpi_detection_module_struct *ndp "Thrift", NDPI_PROTOCOL_CATEGORY_RPC, ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); + ndpi_set_proto_defaults(ndpi_str, 0 /* encrypted */, 1 /* app proto */, NDPI_PROTOCOL_FUN, NDPI_PROTOCOL_ROBLOX, + "Roblox", NDPI_PROTOCOL_CATEGORY_GAME, + ndpi_build_default_ports(ports_a, 0, 0, 0, 0, 0) /* TCP */, + ndpi_build_default_ports(ports_b, 0, 0, 0, 0, 0) /* UDP */); #ifdef CUSTOM_NDPI_PROTOCOLS @@ -2874,6 +2879,7 @@ struct ndpi_detection_module_struct *ndpi_init_detection_module(ndpi_init_prefs ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, ndpi_protocol_hulu_protocol_list); ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, ndpi_protocol_epicgames_protocol_list); ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, ndpi_protocol_nvidia_protocol_list); + ndpi_init_ptree_ipv4(ndpi_str, ndpi_str->protocols_ptree, ndpi_protocol_roblox_protocol_list); } if(prefs & ndpi_track_flow_payload) diff --git a/src/lib/protocols/raknet.c b/src/lib/protocols/raknet.c index d1deaec22..49db3cc55 100644 --- a/src/lib/protocols/raknet.c +++ b/src/lib/protocols/raknet.c @@ -46,6 +46,43 @@ static size_t raknet_dissect_ip(struct ndpi_packet_struct * const packet, size_t return (packet->payload[offset] == 0x04 ? 4 : 16); } +static int is_custom_version(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ + struct ndpi_packet_struct *packet = &ndpi_struct->packet; + unsigned char magic[] = { 0x00, 0xFF, 0xFF, 0x00, 0xFE, 0xFE, 0xFE, 0xFE, + 0xFD, 0xFD, 0xFD, 0xFD, 0x12, 0x34, 0x56, 0x78 }; + + if (packet->payload_packet_len >= 1200) /* Full MTU packet */ + { + /* Offset 32 has been found only in the traces; the other ones are present + also in the Raknet heuristic in Wireshark */ + if (memcmp(magic, &packet->payload[1], sizeof(magic)) == 0 || + memcmp(magic, &packet->payload[9], sizeof(magic)) == 0 || + memcmp(magic, &packet->payload[17], sizeof(magic)) == 0 || + memcmp(magic, &packet->payload[32], sizeof(magic)) == 0) + { + return 1; + } + } + return 0; +} + +static void exclude_proto(struct ndpi_detection_module_struct *ndpi_struct, + struct ndpi_flow_struct *flow) +{ + if (flow->l4.udp.raknet_custom == 1) + { + NDPI_LOG_INFO(ndpi_struct, "found RakNet (custom version)\n"); + /* Classify as Raknet or as Roblox? + This pattern ha been observed with Roblox games but it might be used by + other protocols too. Keep the generic classification, for the time being */ + ndpi_int_raknet_add_connection(ndpi_struct, flow); + } else { + NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + } +} + /* Reference: https://wiki.vg/Raknet_Protocol */ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) @@ -55,9 +92,23 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, NDPI_LOG_DBG(ndpi_struct, "search RakNet\n"); - if (packet->udp == NULL || packet->payload_packet_len < 7) + /* There are two "versions" of Raknet: + * plaintext one: we need multiple packets for classification and for extracting metadata + * custom/encrypted one: an extension used by Roblox games (and others?). + Only the first pkt is required. + The main issue is that these two versions "overlap", i.e. some plaintext flows might be wrongly + identified as encrypted one (losing their metadata). + Solution: check for the custoom/encrypted version, cache the result and use it only if/when the + standard detection ends. + */ + if (flow->packet_counter == 1) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + flow->l4.udp.raknet_custom = is_custom_version(ndpi_struct, flow); + } + + if (packet->payload_packet_len < 7) + { + exclude_proto(ndpi_struct, flow); return; } @@ -68,7 +119,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, case 0x00: /* Connected Ping */ if (packet->payload_packet_len != 8) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } required_packets = 6; @@ -78,7 +129,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, case 0x02: /* Unconnected Ping */ if (packet->payload_packet_len != 32) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } required_packets = 6; @@ -87,7 +138,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, case 0x03: /* Connected Pong */ if (packet->payload_packet_len != 16) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } required_packets = 6; @@ -97,7 +148,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, if (packet->payload_packet_len < 18 || packet->payload[17] > 10 /* maximum supported protocol version */) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } required_packets = 6; @@ -107,7 +158,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, if (packet->payload_packet_len != 28 || packet->payload[25] > 0x01 /* connection uses encryption: bool -> 0x00 or 0x01 */) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } @@ -115,7 +166,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t mtu_size = ntohs(get_u_int16_t(packet->payload, 26)); if (mtu_size > 1500 /* Max. supported MTU, see: http://www.jenkinssoftware.com/raknet/manual/programmingtips.html */) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } } @@ -128,7 +179,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, !((ip_addr_offset == 16 && packet->payload_packet_len == 46) || (ip_addr_offset == 4 && packet->payload_packet_len == 34))) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } @@ -136,7 +187,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t mtu_size = ntohs(get_u_int16_t(packet->payload, 20 + ip_addr_offset)); if (mtu_size > 1500 /* Max. supported MTU, see: http://www.jenkinssoftware.com/raknet/manual/programmingtips.html */) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } } @@ -148,7 +199,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, !((ip_addr_offset == 16 && packet->payload_packet_len == 47) || (ip_addr_offset == 4 && packet->payload_packet_len == 35))) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } @@ -156,7 +207,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, u_int16_t mtu_size = ntohs(get_u_int16_t(packet->payload, 28 + ip_addr_offset)); if (mtu_size > 1500 /* Max. supported MTU, see: http://www.jenkinssoftware.com/raknet/manual/programmingtips.html */) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } } @@ -179,7 +230,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, ip_addr_offset += 16; if (ip_addr_offset != packet->payload_packet_len) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } } @@ -207,7 +258,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, u_int8_t msg_flags = get_u_int8_t(packet->payload, frame_offset); if ((msg_flags & 0x0F) != 0) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } @@ -215,7 +266,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, msg_size /= 8; if (msg_size == 0) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); break; } @@ -245,7 +296,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, { ndpi_int_raknet_add_connection(ndpi_struct, flow); } else { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); } return; } @@ -254,7 +305,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, case 0x09: /* Connection Request */ if (packet->payload_packet_len != 16) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } required_packets = 6; @@ -268,7 +319,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, if (packet->payload_packet_len != 25 || packet->payload[17] > 10) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } break; @@ -276,7 +327,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, case 0x1c: /* Unconnected Pong */ if (packet->payload_packet_len < 35) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } @@ -285,7 +336,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, if (motd_len == 0 || motd_len + 35 != packet->payload_packet_len) { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } } @@ -305,7 +356,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, { record_offset += 4; } else { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } } while (++record_index < record_count && @@ -315,7 +366,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, { ndpi_int_raknet_add_connection(ndpi_struct, flow); } else { - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); } return; } @@ -326,7 +377,7 @@ static void ndpi_search_raknet(struct ndpi_detection_module_struct *ndpi_struct, break; default: /* Invalid RakNet packet */ - NDPI_EXCLUDE_PROTO(ndpi_struct, flow); + exclude_proto(ndpi_struct, flow); return; } |