diff options
author | Toni <matzeton@googlemail.com> | 2022-09-21 18:24:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-21 18:24:04 +0200 |
commit | 644ad34962365fa794b8f58e01a7290496f3d6ef (patch) | |
tree | 6585447ab509e90ce4733066c8182f8e930ebc36 /src | |
parent | d6701e8979292834cd50abc78e8beafea7c7be8c (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.h | 7 | ||||
-rw-r--r-- | src/lib/ndpi_utils.c | 10 | ||||
-rw-r--r-- | src/lib/protocols/natpmp.c | 130 |
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); + } } } |