aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/include/ndpi_private.h14
-rw-r--r--src/include/ndpi_typedefs.h19
-rw-r--r--src/lib/ndpi_main.c96
-rw-r--r--src/lib/ndpi_utils.c70
-rw-r--r--src/lib/protocols/ssdp.c147
-rw-r--r--tests/cfgs/default/pcap/ssdp.pcapngbin0 -> 1260 bytes
-rw-r--r--tests/cfgs/default/result/ssdp.pcapng.out27
7 files changed, 363 insertions, 10 deletions
diff --git a/src/include/ndpi_private.h b/src/include/ndpi_private.h
index c96b64d93..accafdcd2 100644
--- a/src/include/ndpi_private.h
+++ b/src/include/ndpi_private.h
@@ -126,6 +126,20 @@ struct ndpi_packet_struct {
struct ndpi_int_one_line_struct upgrade_line;
struct ndpi_int_one_line_struct http_response; /* the first "word" in this pointer is the
response code in the packet (200, etc) */
+ struct ndpi_int_one_line_struct bootid;
+ struct ndpi_int_one_line_struct usn;
+ struct ndpi_int_one_line_struct cache_controle;
+ struct ndpi_int_one_line_struct location;
+ struct ndpi_int_one_line_struct household_smart_speaker_audio;
+ struct ndpi_int_one_line_struct rincon_household;
+ struct ndpi_int_one_line_struct rincon_bootseq;
+ struct ndpi_int_one_line_struct rincon_wifimode;
+ struct ndpi_int_one_line_struct rincon_variant;
+ struct ndpi_int_one_line_struct sonos_securelocation;
+ struct ndpi_int_one_line_struct securelocation_upnp;
+ struct ndpi_int_one_line_struct location_smart_speaker_audio;
+ struct ndpi_int_one_line_struct nt;
+ struct ndpi_int_one_line_struct nts;
u_int16_t l3_packet_len;
u_int16_t payload_packet_len;
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index c1c57bb6f..30b208441 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1577,6 +1577,25 @@ struct ndpi_flow_struct {
u_int32_t ipv4_addr, uptime;
struct ndpi_in6_addr ipv6_addr;
} mikrotik;
+
+ struct {
+ char *method;
+ char *bootid;
+ char *usn;
+ char *cache_controle;
+ char *location;
+ char *household_smart_speaker_audio;
+ char *rincon_household;
+ char *rincon_bootseq;
+ char *rincon_wifimode;
+ char *rincon_variant;
+ char *sonos_securelocation;
+ char *securelocation_upnp;
+ char *location_smart_speaker_audio;
+ char *nt;
+ char *nts;
+ char *server;
+ } ssdp;
} protos;
/* **Packet** metadata for flows where monitoring is enabled. It is reset after each packet! */
diff --git a/src/lib/ndpi_main.c b/src/lib/ndpi_main.c
index b3e7b264e..8dba3f920 100644
--- a/src/lib/ndpi_main.c
+++ b/src/lib/ndpi_main.c
@@ -6858,6 +6858,56 @@ void ndpi_free_flow_data(struct ndpi_flow_struct* flow) {
ndpi_free(flow->protos.sip.to);
}
+ if (flow_is_proto(flow, NDPI_PROTOCOL_SSDP)) {
+ if(flow->protos.ssdp.bootid)
+ ndpi_free(flow->protos.ssdp.bootid);
+
+ if(flow->protos.ssdp.usn)
+ ndpi_free(flow->protos.ssdp.usn);
+
+ if(flow->protos.ssdp.cache_controle)
+ ndpi_free(flow->protos.ssdp.cache_controle);
+
+ if(flow->protos.ssdp.location)
+ ndpi_free(flow->protos.ssdp.location);
+
+ if(flow->protos.ssdp.household_smart_speaker_audio)
+ ndpi_free(flow->protos.ssdp.household_smart_speaker_audio);
+
+ if(flow->protos.ssdp.rincon_household)
+ ndpi_free(flow->protos.ssdp.rincon_household);
+
+ if(flow->protos.ssdp.rincon_bootseq)
+ ndpi_free(flow->protos.ssdp.rincon_bootseq);
+
+ if(flow->protos.ssdp.rincon_wifimode)
+ ndpi_free(flow->protos.ssdp.rincon_wifimode);
+
+ if(flow->protos.ssdp.rincon_variant)
+ ndpi_free(flow->protos.ssdp.rincon_variant);
+
+ if(flow->protos.ssdp.sonos_securelocation)
+ ndpi_free(flow->protos.ssdp.sonos_securelocation);
+
+ if(flow->protos.ssdp.securelocation_upnp)
+ ndpi_free(flow->protos.ssdp.securelocation_upnp);
+
+ if(flow->protos.ssdp.location_smart_speaker_audio)
+ ndpi_free(flow->protos.ssdp.location_smart_speaker_audio);
+
+ if(flow->protos.ssdp.nt)
+ ndpi_free(flow->protos.ssdp.nt);
+
+ if(flow->protos.ssdp.nts)
+ ndpi_free(flow->protos.ssdp.nts);
+
+ if(flow->protos.ssdp.server)
+ ndpi_free(flow->protos.ssdp.server);
+
+ if(flow->protos.ssdp.method)
+ ndpi_free(flow->protos.ssdp.method);
+ }
+
if(flow->tls_quic.message[0].buffer)
ndpi_free(flow->tls_quic.message[0].buffer);
if(flow->tls_quic.message[1].buffer)
@@ -8485,7 +8535,21 @@ static void ndpi_reset_packet_line_info(struct ndpi_packet_struct *packet) {
packet->server_line.len = 0, packet->http_method.ptr = NULL, packet->http_method.len = 0,
packet->http_response.ptr = NULL, packet->http_response.len = 0,
packet->forwarded_line.ptr = NULL, packet->forwarded_line.len = 0;
- packet->upgrade_line.ptr = NULL, packet->upgrade_line.len = 0;
+ packet->upgrade_line.ptr = NULL, packet->upgrade_line.len = 0;
+ packet->bootid.ptr = NULL, packet->bootid.len = 0;
+ packet->usn.ptr = NULL, packet->usn.len = 0;
+ packet->cache_controle.ptr = NULL, packet->cache_controle.len = 0;
+ packet->location.ptr = NULL, packet->location.len = 0;
+ packet->household_smart_speaker_audio.ptr = NULL, packet->household_smart_speaker_audio.len = 0;
+ packet->rincon_household.ptr = NULL, packet->rincon_household.len = 0;
+ packet->rincon_bootseq.ptr = NULL, packet->rincon_bootseq.len = 0;
+ packet->rincon_wifimode.ptr = NULL, packet->rincon_wifimode.len = 0;
+ packet->rincon_variant.ptr = NULL, packet->rincon_variant.len = 0;
+ packet->sonos_securelocation.ptr = NULL, packet->sonos_securelocation.len = 0;
+ packet->securelocation_upnp.ptr = NULL, packet->securelocation_upnp.len = 0;
+ packet->location_smart_speaker_audio.ptr = NULL, packet->location_smart_speaker_audio.len = 0;
+ packet->nt.ptr = NULL, packet->nt.len = 0;
+ packet->nts.ptr = NULL, packet->nts.len = 0;
}
/* ********************************************************************************* */
@@ -9229,23 +9293,39 @@ static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_s
struct header_line headers_a[] = { { "Accept:", &packet->accept_line },
{ "Authorization:", &packet->authorization_line },
{ NULL, NULL} };
+ struct header_line headers_b[] = { { "BOOTID.UPNP.ORG:", &packet->bootid},
+ { NULL, NULL} };
struct header_line headers_u[] = { { "User-agent:", &packet->user_agent_line },
{ "Upgrade:", &packet->upgrade_line },
+ { "USN:", &packet->usn },
{ NULL, NULL} };
struct header_line headers_c[] = { { "Content-Disposition:", &packet->content_disposition_line },
{ "Content-type:", &packet->content_line },
+ { "CACHE-CONTROL:", &packet->cache_controle},
{ NULL, NULL} };
struct header_line headers_o[] = { { "Origin:", &packet->http_origin },
{ NULL, NULL} };
struct header_line headers_h[] = { { "Host:", &packet->host_line },
+ { "HOUSEHOLD.SMARTSPEAKER.AUDIO:", &packet->household_smart_speaker_audio },
{ NULL, NULL} };
struct header_line headers_x[] = { { "X-Forwarded-For:", &packet->forwarded_line },
+ { "X-RINCON-HOUSEHOLD:", &packet->rincon_household },
+ { "X-RINCON-BOOTSEQ:", &packet->rincon_bootseq },
+ { "X-RINCON-WIFIMODE:", &packet->rincon_wifimode },
+ { "X-RINCON-VARIANT:", &packet->rincon_variant },
+ { "X-SONOS-HHSECURELOCATION:", &packet->sonos_securelocation },
{ NULL, NULL} };
struct header_line headers_r[] = { { "Referer:", &packet->referer_line },
{ NULL, NULL} };
struct header_line headers_s[] = { { "Server:", &packet->server_line },
+ { "SECURELOCATION.UPNP.ORG:", &packet->securelocation_upnp },
{ NULL, NULL} };
-
+ struct header_line headers_l[] = { { "LOCATION:", &packet->location },
+ { "LOCATION.SMARTSPEAKER.AUDIO:", &packet->location_smart_speaker_audio },
+ { NULL, NULL}};
+ struct header_line headers_n[] = { { "NT:", &packet->nt },
+ { "NTS:", &packet->nts },
+ { NULL, NULL}};
line = &packet->line[packet->parsed_lines];
if(line->len == 0)
@@ -9274,6 +9354,10 @@ static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_s
case 'A':
hs = headers_a;
break;
+ case 'b':
+ case 'B':
+ hs = headers_b;
+ break;
case 'c':
case 'C':
hs = headers_c;
@@ -9302,6 +9386,14 @@ static void parse_single_packet_line(struct ndpi_detection_module_struct *ndpi_s
case 'X':
hs = headers_x;
break;
+ case 'l':
+ case 'L':
+ hs = headers_l;
+ break;
+ case 'n':
+ case 'N':
+ hs = headers_n;
+ break;
default:
return;
}
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index 64c6c2d6d..0a3babe3f 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -1592,6 +1592,76 @@ int ndpi_dpi2json(struct ndpi_detection_module_struct *ndpi_struct,
}
break;
+ case NDPI_PROTOCOL_SSDP:
+ ndpi_serialize_start_of_block(serializer, "ssdp");
+
+ if (flow->protos.ssdp.method) {
+ ndpi_serialize_string_string(serializer, "METHOD", flow->protos.ssdp.method);
+ }
+
+ if (flow->protos.ssdp.cache_controle) {
+ ndpi_serialize_string_string(serializer, "CACHE-CONTROL", flow->protos.ssdp.cache_controle);
+ }
+
+ if (flow->protos.ssdp.location) {
+ ndpi_serialize_string_string(serializer, "LOCATION", flow->protos.ssdp.location);
+ }
+
+ if (flow->protos.ssdp.nt) {
+ ndpi_serialize_string_string(serializer, "NT", flow->protos.ssdp.nt);
+ }
+
+ if (flow->protos.ssdp.nts) {
+ ndpi_serialize_string_string(serializer, "NTS", flow->protos.ssdp.nts);
+ }
+
+ if (flow->protos.ssdp.server) {
+ ndpi_serialize_string_string(serializer, "SERVER", flow->protos.ssdp.server);
+ }
+
+ if (flow->protos.ssdp.usn) {
+ ndpi_serialize_string_string(serializer, "USN", flow->protos.ssdp.usn);
+ }
+
+ if (flow->protos.ssdp.rincon_household) {
+ ndpi_serialize_string_string(serializer, "X-RINCON-HOUSEHOLD", flow->protos.ssdp.rincon_household);
+ }
+
+ if (flow->protos.ssdp.rincon_bootseq) {
+ ndpi_serialize_string_string(serializer, "X-RINCON-BOOTSEQ", flow->protos.ssdp.rincon_bootseq);
+ }
+
+ if (flow->protos.ssdp.bootid) {
+ ndpi_serialize_string_string(serializer, "BOOTID.UPNP.ORG", flow->protos.ssdp.bootid);
+ }
+
+ if (flow->protos.ssdp.rincon_wifimode) {
+ ndpi_serialize_string_string(serializer, "X-RINCON-WIFIMODE", flow->protos.ssdp.rincon_wifimode);
+ }
+
+ if (flow->protos.ssdp.rincon_variant) {
+ ndpi_serialize_string_string(serializer, "X-RINCON-VARIANT", flow->protos.ssdp.rincon_variant);
+ }
+
+ if (flow->protos.ssdp.household_smart_speaker_audio) {
+ ndpi_serialize_string_string(serializer, "HOUSEHOLD.SMARTSPEAKER.AUDIO", flow->protos.ssdp.household_smart_speaker_audio);
+ }
+
+ if (flow->protos.ssdp.location_smart_speaker_audio) {
+ ndpi_serialize_string_string(serializer, "LOCATION.SMARTSPEAKER.AUDIO", flow->protos.ssdp.location_smart_speaker_audio);
+ }
+
+ if (flow->protos.ssdp.securelocation_upnp) {
+ ndpi_serialize_string_string(serializer, "SECURELOCATION.UPNP.ORG", flow->protos.ssdp.securelocation_upnp);
+ }
+
+ if (flow->protos.ssdp.sonos_securelocation) {
+ ndpi_serialize_string_string(serializer, "X-SONOS-HHSECURELOCATION", flow->protos.ssdp.sonos_securelocation);
+ }
+
+ ndpi_serialize_end_of_block(serializer);
+ break;
+
case NDPI_PROTOCOL_DISCORD:
if (l7_protocol.proto.master_protocol != NDPI_PROTOCOL_TLS) {
ndpi_serialize_start_of_block(serializer, "discord");
diff --git a/src/lib/protocols/ssdp.c b/src/lib/protocols/ssdp.c
index 949ff8bb3..acaf14e47 100644
--- a/src/lib/protocols/ssdp.c
+++ b/src/lib/protocols/ssdp.c
@@ -29,6 +29,13 @@
#include "ndpi_api.h"
#include "ndpi_private.h"
+static struct SSDP {
+ const char *detection_line;
+ const char *method;
+} SSDP_METHODS[] = {
+ { "M-SEARCH * HTTP/1.1", "M-SEARCH" },
+ { "NOTIFY * HTTP/1.1", "NOTIFY" }
+};
static void ssdp_parse_lines(struct ndpi_detection_module_struct
*ndpi_struct, struct ndpi_flow_struct *flow)
@@ -49,6 +56,126 @@ static void ssdp_parse_lines(struct ndpi_detection_module_struct
if (packet->host_line.ptr != NULL && packet->host_line.len > 0) {
ndpi_hostname_sni_set(flow, packet->host_line.ptr, packet->host_line.len, NDPI_HOSTNAME_NORM_ALL);
}
+
+ if (packet->bootid.ptr != NULL && packet->bootid.len > 0) {
+ flow->protos.ssdp.bootid = ndpi_malloc(packet->bootid.len + 1);
+ if (flow->protos.ssdp.bootid) {
+ memcpy(flow->protos.ssdp.bootid, packet->bootid.ptr, packet->bootid.len);
+ flow->protos.ssdp.bootid[packet->bootid.len] = '\0';
+ }
+ }
+
+ if (packet->usn.ptr != NULL && packet->usn.len > 0) {
+ flow->protos.ssdp.usn = ndpi_malloc(packet->usn.len + 1);
+ if (flow->protos.ssdp.usn) {
+ memcpy(flow->protos.ssdp.usn, packet->usn.ptr, packet->usn.len);
+ flow->protos.ssdp.usn[packet->usn.len] = '\0';
+ }
+ }
+
+ if (packet->cache_controle.ptr != NULL && packet->cache_controle.len > 0) {
+ flow->protos.ssdp.cache_controle = ndpi_malloc(packet->cache_controle.len + 1);
+ if (flow->protos.ssdp.cache_controle) {
+ memcpy(flow->protos.ssdp.cache_controle, packet->cache_controle.ptr, packet->cache_controle.len);
+ flow->protos.ssdp.cache_controle[packet->cache_controle.len] = '\0';
+ }
+ }
+
+ if (packet->location.ptr != NULL && packet->location.len > 0) {
+ flow->protos.ssdp.location = ndpi_malloc(packet->location.len + 1);
+ if (flow->protos.ssdp.location) {
+ memcpy(flow->protos.ssdp.location, packet->location.ptr, packet->location.len);
+ flow->protos.ssdp.location[packet->location.len] = '\0';
+ }
+ }
+
+ if (packet->household_smart_speaker_audio.ptr != NULL && packet->household_smart_speaker_audio.len > 0) {
+ flow->protos.ssdp.household_smart_speaker_audio = ndpi_malloc(packet->household_smart_speaker_audio.len + 1);
+ if (flow->protos.ssdp.household_smart_speaker_audio) {
+ memcpy(flow->protos.ssdp.household_smart_speaker_audio, packet->household_smart_speaker_audio.ptr, packet->household_smart_speaker_audio.len);
+ flow->protos.ssdp.household_smart_speaker_audio[packet->household_smart_speaker_audio.len] = '\0';
+ }
+ }
+
+ if (packet->rincon_household.ptr != NULL && packet->rincon_household.len > 0) {
+ flow->protos.ssdp.rincon_household = ndpi_malloc(packet->rincon_household.len + 1);
+ if (flow->protos.ssdp.rincon_household) {
+ memcpy(flow->protos.ssdp.rincon_household, packet->rincon_household.ptr, packet->rincon_household.len);
+ flow->protos.ssdp.rincon_household[packet->rincon_household.len] = '\0';
+ }
+ }
+
+ if (packet->rincon_bootseq.ptr != NULL && packet->rincon_bootseq.len > 0) {
+ flow->protos.ssdp.rincon_bootseq = ndpi_malloc(packet->rincon_bootseq.len + 1);
+ if (flow->protos.ssdp.rincon_bootseq) {
+ memcpy(flow->protos.ssdp.rincon_bootseq, packet->rincon_bootseq.ptr, packet->rincon_bootseq.len);
+ flow->protos.ssdp.rincon_bootseq[packet->rincon_bootseq.len] = '\0';
+ }
+ }
+
+ if (packet->rincon_wifimode.ptr != NULL && packet->rincon_wifimode.len > 0) {
+ flow->protos.ssdp.rincon_wifimode = ndpi_malloc(packet->rincon_wifimode.len + 1);
+ if (flow->protos.ssdp.rincon_wifimode) {
+ memcpy(flow->protos.ssdp.rincon_wifimode, packet->rincon_wifimode.ptr, packet->rincon_wifimode.len);
+ flow->protos.ssdp.rincon_wifimode[packet->rincon_wifimode.len] = '\0';
+ }
+ }
+
+ if (packet->rincon_variant.ptr != NULL && packet->rincon_variant.len > 0) {
+ flow->protos.ssdp.rincon_variant = ndpi_malloc(packet->rincon_variant.len + 1);
+ if (flow->protos.ssdp.rincon_variant) {
+ memcpy(flow->protos.ssdp.rincon_variant, packet->rincon_variant.ptr, packet->rincon_variant.len);
+ flow->protos.ssdp.rincon_variant[packet->rincon_variant.len] = '\0';
+ }
+ }
+
+ if (packet->sonos_securelocation.ptr != NULL && packet->sonos_securelocation.len > 0) {
+ flow->protos.ssdp.sonos_securelocation = ndpi_malloc(packet->sonos_securelocation.len + 1);
+ if (flow->protos.ssdp.sonos_securelocation) {
+ memcpy(flow->protos.ssdp.sonos_securelocation, packet->sonos_securelocation.ptr, packet->sonos_securelocation.len);
+ flow->protos.ssdp.sonos_securelocation[packet->sonos_securelocation.len] = '\0';
+ }
+ }
+
+ if (packet->securelocation_upnp.ptr != NULL && packet->securelocation_upnp.len > 0) {
+ flow->protos.ssdp.securelocation_upnp = ndpi_malloc(packet->securelocation_upnp.len + 1);
+ if (flow->protos.ssdp.securelocation_upnp) {
+ memcpy(flow->protos.ssdp.securelocation_upnp, packet->securelocation_upnp.ptr, packet->securelocation_upnp.len);
+ flow->protos.ssdp.securelocation_upnp[packet->securelocation_upnp.len] = '\0';
+ }
+ }
+
+ if (packet->location_smart_speaker_audio.ptr != NULL && packet->location_smart_speaker_audio.len > 0) {
+ flow->protos.ssdp.location_smart_speaker_audio = ndpi_malloc(packet->location_smart_speaker_audio.len + 1);
+ if (flow->protos.ssdp.location_smart_speaker_audio) {
+ memcpy(flow->protos.ssdp.location_smart_speaker_audio, packet->location_smart_speaker_audio.ptr, packet->location_smart_speaker_audio.len);
+ flow->protos.ssdp.location_smart_speaker_audio[packet->location_smart_speaker_audio.len] = '\0';
+ }
+ }
+
+ if (packet->nt.ptr != NULL && packet->nt.len > 0) {
+ flow->protos.ssdp.nt = ndpi_malloc(packet->nt.len + 1);
+ if (flow->protos.ssdp.nt) {
+ memcpy(flow->protos.ssdp.nt, packet->nt.ptr, packet->nt.len);
+ flow->protos.ssdp.nt[packet->nt.len] = '\0';
+ }
+ }
+
+ if (packet->nts.ptr != NULL && packet->nts.len > 0) {
+ flow->protos.ssdp.nts = ndpi_malloc(packet->nts.len + 1);
+ if (flow->protos.ssdp.nts) {
+ memcpy(flow->protos.ssdp.nts, packet->nts.ptr, packet->nts.len);
+ flow->protos.ssdp.nts[packet->nts.len] = '\0';
+ }
+ }
+
+ if (packet->server_line.ptr != NULL && packet->server_line.len > 0) {
+ flow->protos.ssdp.server = ndpi_malloc(packet->server_line.len + 1);
+ if (flow->protos.ssdp.server) {
+ memcpy(flow->protos.ssdp.server, packet->server_line.ptr, packet->server_line.len);
+ flow->protos.ssdp.server[packet->server_line.len] = '\0';
+ }
+ }
}
static void ndpi_int_ssdp_add_connection(struct ndpi_detection_module_struct
@@ -67,14 +194,18 @@ static void ndpi_search_ssdp(struct ndpi_detection_module_struct *ndpi_struct, s
if (packet->udp != NULL) {
if (packet->payload_packet_len >= 19) {
- if ((memcmp(packet->payload, "M-SEARCH * HTTP/1.1", 19) == 0)
- || memcmp(packet->payload, "NOTIFY * HTTP/1.1", 17) == 0) {
-
-
- NDPI_LOG_INFO(ndpi_struct, "found ssdp\n");
- ndpi_int_ssdp_add_connection(ndpi_struct, flow);
- return;
- }
+ for (unsigned int i=0; i < sizeof(SSDP_METHODS)/sizeof(SSDP_METHODS[0]); i++) {
+ if(memcmp(packet->payload, SSDP_METHODS[i].detection_line, strlen(SSDP_METHODS[i].detection_line)) == 0) {
+ flow->protos.ssdp.method = ndpi_malloc(strlen(SSDP_METHODS[i].detection_line) + 1);
+ if (flow->protos.ssdp.method) {
+ memcpy(flow->protos.ssdp.method, SSDP_METHODS[i].method, strlen(SSDP_METHODS[i].method));
+ flow->protos.ssdp.method[strlen(SSDP_METHODS[i].method)] = '\0';
+ }
+ NDPI_LOG_INFO(ndpi_struct, "found ssdp\n");
+ ndpi_int_ssdp_add_connection(ndpi_struct, flow);
+ return;
+ }
+ }
#define SSDP_HTTP "HTTP/1.1 200 OK\r\n"
if(memcmp(packet->payload, SSDP_HTTP, strlen(SSDP_HTTP)) == 0) {
diff --git a/tests/cfgs/default/pcap/ssdp.pcapng b/tests/cfgs/default/pcap/ssdp.pcapng
new file mode 100644
index 000000000..bdaafb544
--- /dev/null
+++ b/tests/cfgs/default/pcap/ssdp.pcapng
Binary files differ
diff --git a/tests/cfgs/default/result/ssdp.pcapng.out b/tests/cfgs/default/result/ssdp.pcapng.out
new file mode 100644
index 000000000..77e8af8c6
--- /dev/null
+++ b/tests/cfgs/default/result/ssdp.pcapng.out
@@ -0,0 +1,27 @@
+DPI Packets (UDP): 1 (1.00 pkts/flow)
+Confidence DPI : 1 (flows)
+Num dissector calls: 25 (25.00 diss/flow)
+LRU cache ookla: 0/0/0 (insert/search/found)
+LRU cache bittorrent: 0/0/0 (insert/search/found)
+LRU cache stun: 0/0/0 (insert/search/found)
+LRU cache tls_cert: 0/0/0 (insert/search/found)
+LRU cache mining: 0/0/0 (insert/search/found)
+LRU cache msteams: 0/0/0 (insert/search/found)
+LRU cache fpc_dns: 0/0/0 (insert/search/found)
+Automa host: 0/0 (search/found)
+Automa domain: 0/0 (search/found)
+Automa tls cert: 0/0 (search/found)
+Automa risk mask: 0/0 (search/found)
+Automa common alpns: 0/0 (search/found)
+Patricia risk mask: 0/0 (search/found)
+Patricia risk mask IPv6: 0/0 (search/found)
+Patricia risk: 0/0 (search/found)
+Patricia risk IPv6: 0/0 (search/found)
+Patricia protocols: 2/0 (search/found)
+Patricia protocols IPv6: 0/0 (search/found)
+
+SSDP 1 848 1
+
+Acceptable 1 848 1
+
+ 1 UDP 192.168.1.173:58006 -> 239.255.255.250:1900 [proto: 12/SSDP][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 12/SSDP, Confidence: DPI][DPI packets: 1][cat: System/18][1 pkts/848 bytes -> 0 pkts/0 bytes][Goodput ratio: 95/0][< 1 sec][Hostname/SNI: 239.255.255.250:1900][PLAIN TEXT (ENOTIFY )][Plen Bins: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]