Skip to content

Commit

Permalink
Add Service Location Protocol dissector.
Browse files Browse the repository at this point in the history
Signed-off-by: Toni Uhlig <[email protected]>
  • Loading branch information
utoni committed Jul 7, 2023
1 parent bdd295b commit bbb27de
Show file tree
Hide file tree
Showing 79 changed files with 2,311 additions and 1,995 deletions.
15 changes: 15 additions & 0 deletions example/reader_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -1198,6 +1198,21 @@ void process_ndpi_collected_info(struct ndpi_workflow * workflow, struct ndpi_fl
ndpi_snprintf(flow->softether.fqdn, sizeof(flow->softether.fqdn), "%s",
flow->ndpi_flow->protos.softether.fqdn);
}
/* SERVICE_LOCATION */
else if(is_ndpi_proto(flow, NDPI_PROTOCOL_SERVICE_LOCATION)) {
flow->info_type = INFO_GENERIC;
flow->info[0] = 0;
if (flow->ndpi_flow->protos.slp.url_count > 0)
strncat(flow->info, "URL: ", sizeof(flow->info));
for (size_t i = 0; i < flow->ndpi_flow->protos.slp.url_count; ++i) {
size_t length = strlen(flow->info);
strncat(flow->info + length, flow->ndpi_flow->protos.slp.url[i],
sizeof(flow->info) - length);
length = strlen(flow->info);
if (i < (size_t)flow->ndpi_flow->protos.slp.url_count - 1)
strncat(flow->info + length, ", ", sizeof(flow->info) - length);
}
}
/* NATPMP */
else if(is_ndpi_proto(flow, NDPI_PROTOCOL_NATPMP)) {
flow->info_type = INFO_NATPMP;
Expand Down
1 change: 1 addition & 0 deletions src/include/ndpi_protocol_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ typedef enum {
NDPI_PROTOCOL_BITCOIN = 343,
NDPI_PROTOCOL_PROTONVPN = 344,
NDPI_PROTOCOL_APACHE_THRIFT = 345,
NDPI_PROTOCOL_SERVICE_LOCATION = 346,

#ifdef CUSTOM_NDPI_PROTOCOLS
#include "../../../nDPI-custom/custom_ndpi_protocol_ids.h"
Expand Down
1 change: 1 addition & 0 deletions src/include/ndpi_protocols.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ void init_oicq_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int
void init_epicgames_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id);
void init_bitcoin_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id);
void init_apache_thrift_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id);
void init_slp_dissector(struct ndpi_detection_module_struct *ndpi_struct, u_int32_t *id);

/* ndpi_main.c */
extern u_int32_t ndpi_ip_port_hash_funct(u_int32_t ip, u_int16_t port);
Expand Down
5 changes: 5 additions & 0 deletions src/include/ndpi_typedefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,11 @@ struct ndpi_flow_struct {
u_int8_t message_type;
char method[64];
} thrift;

struct {
u_int8_t url_count;
char url[4][48];
} slp;
} protos;

/*** ALL protocol specific 64 bit variables here ***/
Expand Down
7 changes: 7 additions & 0 deletions src/lib/ndpi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2102,6 +2102,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, 1 /* cleartext */, 0 /* nw proto */, NDPI_PROTOCOL_ACCEPTABLE, NDPI_PROTOCOL_SERVICE_LOCATION,
"Service Location Protocol", NDPI_PROTOCOL_CATEGORY_RPC,
ndpi_build_default_ports(ports_a, 427, 0, 0, 0, 0) /* TCP */,
ndpi_build_default_ports(ports_b, 427, 0, 0, 0, 0) /* UDP */);


#ifdef CUSTOM_NDPI_PROTOCOLS
Expand Down Expand Up @@ -4981,6 +4985,9 @@ static int ndpi_callback_init(struct ndpi_detection_module_struct *ndpi_str) {
/* Apache Thrift */
init_apache_thrift_dissector(ndpi_str, &a);

/* Service Location Protocol */
init_slp_dissector(ndpi_str, &a);

#ifdef CUSTOM_NDPI_PROTOCOLS
#include "../../../nDPI-custom/custom_ndpi_main_init.c"
#endif
Expand Down
286 changes: 286 additions & 0 deletions src/lib/protocols/slp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
/*
* slp.c
*
* Copyright (C) 2023 - ntop.org
*
* This file is part of nDPI, an open source deep packet inspection
* library based on the OpenDPI and PACE technology by ipoque GmbH
*
* 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_SERVICE_LOCATION

#include "ndpi_api.h"

PACK_ON
struct slp_hdr_v1 {
uint8_t version;
uint8_t function;
uint16_t length;
uint8_t flags;
uint8_t dialect;
uint16_t lang_code;
uint16_t encoding;
uint16_t xid;
} PACK_OFF;

PACK_ON
struct slp_hdr_v2 {
uint8_t version;
uint8_t function_id;
PACK_ON struct {
uint16_t high;
uint8_t low;
} PACK_OFF length;
uint16_t flags;
PACK_ON struct {
uint16_t high;
uint8_t low;
} PACK_OFF next_ext_offset;
uint16_t xid;
uint16_t lang_tag_length;
uint16_t lang_tag;
} PACK_OFF;

enum function_id {
FID_UNKNOWN = 0,
FID_SrvRqst = 1,
FID_SrvRply = 2,
FID_SrvReg = 3,
FID_SrvDeReg = 4,
FID_SrvAck = 5,
FID_AttrRqst = 6,
FID_AttrRply = 7,
FID_DAAdvert = 8,
FID_SrvTypeRqst = 9,
FID_SrvTypeRply = 10,
FID_MAX_v1 = 11,
FID_SAAdvert = 11, // Not available in version 1
FID_MAX
};

static void ndpi_int_slp_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
NDPI_LOG_INFO(ndpi_struct, "found Service Location Protocol\n");

ndpi_set_detected_protocol(ndpi_struct, flow,
NDPI_PROTOCOL_SERVICE_LOCATION, NDPI_PROTOCOL_UNKNOWN,
NDPI_CONFIDENCE_DPI);
}

static int slp_check_packet_length(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
unsigned int packet_length)
{
struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;

if (packet->payload_packet_len != packet_length) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return 1;
}

return 0;
}

static int slp_check_fid(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow,
enum function_id fid, uint8_t slp_version)
{
if (fid <= FID_UNKNOWN) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return 1;
}

switch (slp_version) {
case 0x01:
if (fid >= FID_MAX_v1) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return 1;
}
break;
case 0x02:
if (fid >= FID_MAX) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return 1;
}
break;
default:
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return 1;
}

return 0;
}

static int ndpi_search_slp_v1(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
struct slp_hdr_v1 const * const hdr = (struct slp_hdr_v1 *)&packet->payload[0];

NDPI_LOG_DBG(ndpi_struct, "search Service Location Protocol v1\n");

if (packet->payload_packet_len < sizeof(*hdr)) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return 1;
}

const unsigned int packet_length = ntohs(hdr->length);
if (slp_check_packet_length(ndpi_struct, flow, packet_length) != 0)
return 1;

if (slp_check_fid(ndpi_struct, flow, hdr->function, hdr->version) != 0)
return 1;

ndpi_int_slp_add_connection(ndpi_struct, flow);
return 0;
}

static void ndpi_dissect_slp_v1(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
// No dissection support for SLP version 1.
// TODO: Provide a PCAP file.
}

static int ndpi_search_slp_v2(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
struct slp_hdr_v2 const * const hdr = (struct slp_hdr_v2 *)&packet->payload[0];

NDPI_LOG_DBG(ndpi_struct, "search Service Location Protocol v2\n");

if (packet->payload_packet_len < sizeof(*hdr)) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return 1;
}

const unsigned int packet_length = (ntohs(hdr->length.high) << 8) | hdr->length.low;
if (slp_check_packet_length(ndpi_struct, flow, packet_length) != 0)
return 1;

if (slp_check_fid(ndpi_struct, flow, hdr->function_id, hdr->version) != 0)
return 1;

ndpi_int_slp_add_connection(ndpi_struct, flow);
return 0;
}

static void ndpi_dissect_slp_v2(struct ndpi_detection_module_struct *ndpi_struct,
struct ndpi_flow_struct *flow)
{
struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
struct slp_hdr_v2 const * const hdr = (struct slp_hdr_v2 *)&packet->payload[0];
int url_offset = -1; // Can be either an offset to <URL String> or <URL Entry>
int url_length_offset = -1; // length of <URL String>
int url_entry_count_offset = -1; // amount of <URL Entry>'s

switch (hdr->function_id) {
case FID_SrvRply:
url_entry_count_offset = 2;
url_offset = 4;
break;
case FID_SrvReg:
url_offset = 3; // contains always 1 <URL Entry>
break;
case FID_DAAdvert:
url_length_offset = 6;
url_offset = 8;
break;
case FID_SAAdvert:
url_length_offset = 0;
url_offset = 2;
break;
case FID_AttrRqst:
url_length_offset = 4;
url_offset = 6;
break;
case FID_SrvDeReg:
url_offset = 7; // contains always 1 <URL Entry>
break;
}

if (url_offset >= 0) {
uint16_t url_length_or_count = 0;

if (url_length_offset > 0 && packet->payload_packet_len >= sizeof(*hdr) + url_length_offset + 2) {
// <URL String>
url_length_or_count = ntohs(*(uint16_t *)&packet->payload[sizeof(*hdr) + url_length_offset]);
if (packet->payload_packet_len >= sizeof(*hdr) + url_length_offset + 2 + url_length_or_count) {
size_t len = ndpi_min(sizeof(flow->protos.slp.url[0]) - 1, url_length_or_count);
flow->protos.slp.url_count = 1;
strncpy(flow->protos.slp.url[0], (char *)&packet->payload[sizeof(*hdr) + url_offset + 2], len);
flow->protos.slp.url[0][len] = 0;
}
} else if (url_entry_count_offset > 0 && packet->payload_packet_len >= sizeof(*hdr) + url_entry_count_offset + 2) {
// TODO: <URL Entry>'s
// Provide a PCAP file.
//url_length_or_count = ntohs(*(uint16_t *)&packet->payload[sizeof(*hdr) + url_entry_count_offset]);
} else if (packet->payload_packet_len >= sizeof(*hdr) + url_offset + 2) {
url_length_or_count = ntohs(*(uint16_t *)&packet->payload[sizeof(*hdr) + url_offset]); // FID_SrvReg or FID_SrvDeReg
if (packet->payload_packet_len >= sizeof(*hdr) + url_length_offset + 2 + url_length_or_count) {
size_t len = ndpi_min(sizeof(flow->protos.slp.url[0]) - 1, url_length_or_count);
flow->protos.slp.url_count = 1;
strncpy(flow->protos.slp.url[0], (char *)&packet->payload[sizeof(*hdr) + url_offset + 2], len);
flow->protos.slp.url[0][len] = 0;
}
}
}
}

static void ndpi_search_slp(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 Service Location Protocol\n");

if (packet->payload_packet_len < 1) {
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
return;
}

switch (packet->payload[0]) {
case 0x01:
if (ndpi_search_slp_v1(ndpi_struct, flow) == 0)
ndpi_dissect_slp_v1(ndpi_struct, flow);
break;
case 0x02:
if (ndpi_search_slp_v2(ndpi_struct, flow) == 0)
ndpi_dissect_slp_v2(ndpi_struct, flow);
break;
default:
NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
break;
}
}

void init_slp_dissector(struct ndpi_detection_module_struct *ndpi_struct,
u_int32_t *id)
{
ndpi_set_bitmask_protocol_detection("Service Location Protocol", ndpi_struct, *id,
NDPI_PROTOCOL_SERVICE_LOCATION,
ndpi_search_slp,
NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_UDP_WITH_PAYLOAD,
SAVE_DETECTION_BITMASK_AS_UNKNOWN,
ADD_TO_DETECTION_BITMASK);

*id += 1;
}
2 changes: 1 addition & 1 deletion tests/cfgs/caches_cfg/result/teams.pcap.out
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Confidence Unknown : 1 (flows)
Confidence Match by port : 1 (flows)
Confidence DPI (partial) : 1 (flows)
Confidence DPI : 80 (flows)
Num dissector calls: 497 (5.99 diss/flow)
Num dissector calls: 498 (6.00 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/9/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
Expand Down
2 changes: 1 addition & 1 deletion tests/cfgs/default/result/1kxun.pcap.out
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ DPI Packets (UDP): 120 (1.21 pkts/flow)
Confidence Unknown : 14 (flows)
Confidence Match by port : 6 (flows)
Confidence DPI : 177 (flows)
Num dissector calls: 4520 (22.94 diss/flow)
Num dissector calls: 4534 (23.02 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/60/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
Expand Down
2 changes: 1 addition & 1 deletion tests/cfgs/default/result/4in4tunnel.pcap.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Guessed flow protos: 1

DPI Packets (UDP): 5 (5.00 pkts/flow)
Confidence Unknown : 1 (flows)
Num dissector calls: 176 (176.00 diss/flow)
Num dissector calls: 177 (177.00 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/3/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
Expand Down
2 changes: 1 addition & 1 deletion tests/cfgs/default/result/6in6tunnel.pcap.out
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Guessed flow protos: 1

DPI Packets (UDP): 2 (2.00 pkts/flow)
Confidence Unknown : 1 (flows)
Num dissector calls: 125 (125.00 diss/flow)
Num dissector calls: 126 (126.00 diss/flow)
LRU cache ookla: 0/0/0 (insert/search/found)
LRU cache bittorrent: 0/3/0 (insert/search/found)
LRU cache zoom: 0/0/0 (insert/search/found)
Expand Down
Loading

0 comments on commit bbb27de

Please sign in to comment.