aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorToni <matzeton@googlemail.com>2022-09-21 18:24:04 +0200
committerGitHub <noreply@github.com>2022-09-21 18:24:04 +0200
commit644ad34962365fa794b8f58e01a7290496f3d6ef (patch)
tree6585447ab509e90ce4733066c8182f8e930ebc36 /src
parentd6701e8979292834cd50abc78e8beafea7c7be8c (diff)
Improved NATPMP dissection. (#1745)
Signed-off-by: Toni Uhlig <matzeton@googlemail.com> Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/ndpi_typedefs.h7
-rw-r--r--src/lib/ndpi_utils.c10
-rw-r--r--src/lib/protocols/natpmp.c130
3 files changed, 120 insertions, 27 deletions
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 18a53911d..c5cd96ade 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1475,6 +1475,13 @@ struct ndpi_flow_struct {
char platform[32];
char services[48];
} tivoconnect;
+
+ struct {
+ u_int16_t result_code;
+ u_int16_t internal_port;
+ u_int16_t external_port;
+ ndpi_ip_addr_t external_address;
+ } natpmp;
} protos;
/*** ALL protocol specific 64 bit variables here ***/
diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c
index 1d5ba1ee3..7a34b0b76 100644
--- a/src/lib/ndpi_utils.c
+++ b/src/lib/ndpi_utils.c
@@ -1327,6 +1327,16 @@ int ndpi_dpi2json(struct ndpi_detection_module_struct *ndpi_struct,
ndpi_serialize_end_of_block(serializer);
break;
+ case NDPI_PROTOCOL_NATPMP:
+ ndpi_serialize_start_of_block(serializer, "natpmp");
+ ndpi_serialize_string_uint32(serializer, "result", flow->protos.natpmp.result_code);
+ ndpi_serialize_string_uint32(serializer, "internal_port", flow->protos.natpmp.internal_port);
+ ndpi_serialize_string_uint32(serializer, "external_port", flow->protos.natpmp.external_port);
+ inet_ntop(AF_INET, &flow->protos.natpmp.external_address.ipv4, buf, sizeof(buf));
+ ndpi_serialize_string_string(serializer, "external_address", buf);
+ ndpi_serialize_end_of_block(serializer);
+ break;
+
case NDPI_PROTOCOL_STUN:
ndpi_serialize_start_of_block(serializer, "stun");
ndpi_serialize_string_uint32(serializer, "num_pkts", flow->stun.num_pkts);
diff --git a/src/lib/protocols/natpmp.c b/src/lib/protocols/natpmp.c
index 87b788bea..994ee1d6a 100644
--- a/src/lib/protocols/natpmp.c
+++ b/src/lib/protocols/natpmp.c
@@ -31,11 +31,14 @@ enum natpmp_type {
NATPMP_REQUEST_ADDRESS = 0x00,
NATPMP_REQUEST_UDP_MAPPING = 0x01,
NATPMP_REQUEST_TCP_MAPPING = 0x02,
- NATPMP_RESPONSE_ADRESS = 0x80,
+ NATPMP_RESPONSE_ADDRESS = 0x80,
NATPMP_RESPONSE_UDP_MAPPING = 0x81,
NATPMP_RESPONSE_TCP_MAPPING = 0x82
};
+static int ndpi_search_natpmp_extra(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow);
+
static void ndpi_int_natpmp_add_connection(struct ndpi_detection_module_struct * const ndpi_struct,
struct ndpi_flow_struct * const flow)
{
@@ -44,70 +47,143 @@ static void ndpi_int_natpmp_add_connection(struct ndpi_detection_module_struct *
NDPI_PROTOCOL_NATPMP,
NDPI_PROTOCOL_UNKNOWN,
NDPI_CONFIDENCE_DPI);
+ if (flow->extra_packets_func == NULL)
+ {
+ flow->max_extra_packets_to_check = 5;
+ flow->extra_packets_func = ndpi_search_natpmp_extra;
+ }
}
-void ndpi_search_natpmp(struct ndpi_detection_module_struct *ndpi_struct,
- struct ndpi_flow_struct *flow)
+static void natpmp_disable_extra_dissection(struct ndpi_flow_struct * const flow)
{
- struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
- enum natpmp_type natpmp_type;
+ flow->max_extra_packets_to_check = 0;
+ flow->extra_packets_func = NULL;
+}
- NDPI_LOG_DBG(ndpi_struct, "search nat-pmp\n");
+static int natpmp_is_common_header(struct ndpi_packet_struct const * const packet)
+{
+ return packet->payload_packet_len >= 2 && packet->payload[0] == 0x00 /* Protocol version: 0x00 */;
+}
- if (packet->payload_packet_len < 2 || packet->payload[0] != 0x00 /* Protocol version: 0x00 */)
+static int natpmp_is_valid(struct ndpi_packet_struct const * const packet, enum natpmp_type * const natpmp_type)
+{
+ if (natpmp_is_common_header(packet) == 0)
{
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
+ return 0;
}
- natpmp_type = packet->payload[1];
- switch (natpmp_type)
+ *natpmp_type = packet->payload[1];
+ switch (*natpmp_type)
{
case NATPMP_REQUEST_ADDRESS:
if (packet->payload_packet_len != 2)
{
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return 0;
}
- return;
-
+ break;
case NATPMP_REQUEST_UDP_MAPPING:
case NATPMP_REQUEST_TCP_MAPPING:
if (packet->payload_packet_len != 12 || get_u_int16_t(packet->payload, 2) != 0x0000)
{
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
+ return 0;
}
break;
-
- case NATPMP_RESPONSE_ADRESS:
+ case NATPMP_RESPONSE_ADDRESS:
case NATPMP_RESPONSE_UDP_MAPPING:
case NATPMP_RESPONSE_TCP_MAPPING:
- if ((natpmp_type == NATPMP_RESPONSE_ADRESS && packet->payload_packet_len != 12) ||
- (natpmp_type != NATPMP_RESPONSE_ADRESS && packet->payload_packet_len != 16))
+ if ((*natpmp_type == NATPMP_RESPONSE_ADDRESS && packet->payload_packet_len != 12) ||
+ (*natpmp_type != NATPMP_RESPONSE_ADDRESS && packet->payload_packet_len != 16))
{
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
+ return 0;
}
{
u_int16_t result_code = ntohs(get_u_int16_t(packet->payload, 2));
if (result_code > 5)
{
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
+ return 0;
}
}
break;
default:
- NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
- return;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int ndpi_search_natpmp_extra(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
+ enum natpmp_type natpmp_type;
+
+ if (natpmp_is_valid(packet, &natpmp_type) == 0)
+ {
+ ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Invalid NATPMP Header");
+ return 0;
+ }
+
+ switch (natpmp_type)
+ {
+ case NATPMP_REQUEST_ADDRESS:
+ return 1; // Nothing to do here.
+ case NATPMP_REQUEST_UDP_MAPPING:
+ case NATPMP_REQUEST_TCP_MAPPING:
+ flow->protos.natpmp.internal_port = ntohs(get_u_int16_t(packet->payload, 4));
+ flow->protos.natpmp.external_port = ntohs(get_u_int16_t(packet->payload, 6));
+ if (flow->protos.natpmp.internal_port == 0)
+ {
+ ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Request Port Mapping: Internal port must not 0");
+ }
+ break;
+ case NATPMP_RESPONSE_ADDRESS:
+ flow->protos.natpmp.result_code = ntohs(get_u_int16_t(packet->payload, 2));
+ flow->protos.natpmp.external_address.ipv4 = get_u_int32_t(packet->payload, 8);
+ if (flow->protos.natpmp.result_code != 0 && flow->protos.natpmp.external_address.ipv4 != 0)
+ {
+ ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Address Response: Result code indicates an error, but External IPv4 Address is set");
+ }
+ break;
+ case NATPMP_RESPONSE_UDP_MAPPING:
+ case NATPMP_RESPONSE_TCP_MAPPING:
+ {
+ flow->protos.natpmp.internal_port = ntohs(get_u_int16_t(packet->payload, 8));
+ flow->protos.natpmp.external_port = ntohs(get_u_int16_t(packet->payload, 12));
+ if (flow->protos.natpmp.internal_port == 0 || flow->protos.natpmp.external_port == 0)
+ {
+ ndpi_set_risk(ndpi_struct, flow, NDPI_MALFORMED_PACKET, "Port Mapping Response: Internal/External port must not 0");
+ }
+ break;
+ }
+ }
+
+ return 1;
+}
+
+void ndpi_search_natpmp(struct ndpi_detection_module_struct *ndpi_struct,
+ struct ndpi_flow_struct *flow)
+{
+ struct ndpi_packet_struct const * const packet = &ndpi_struct->packet;
+ enum natpmp_type natpmp_type;
+
+ NDPI_LOG_DBG(ndpi_struct, "search nat-pmp\n");
+
+ if (natpmp_is_valid(packet, &natpmp_type) == 0)
+ {
+ NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
+ return;
}
- if (flow->packet_counter > 2 ||
+ if ((flow->packet_counter > 2 && natpmp_type != NATPMP_REQUEST_ADDRESS) ||
ntohs(packet->udp->source) == NATPMP_PORT || ntohs(packet->udp->dest) == NATPMP_PORT)
{
ndpi_int_natpmp_add_connection(ndpi_struct, flow);
+ if (ndpi_search_natpmp_extra(ndpi_struct, flow) == 0)
+ {
+ natpmp_disable_extra_dissection(flow);
+ }
}
}