diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h index 8ce77bf54d0..ee66116c819 100644 --- a/src/include/ndpi_typedefs.h +++ b/src/include/ndpi_typedefs.h @@ -1447,8 +1447,12 @@ struct ndpi_flow_struct { } dns; struct { - u_int8_t version; - u_int8_t mode; + u_int8_t leap_indicator: 2, version: 3, mode: 3; + u_int8_t stratum; + int8_t ppol, precision; + float root_delay, root_dispersion; + char ref_id[20]; + uint64_t ref_time, org_time, rec_time, trans_time; } ntp; struct { diff --git a/src/lib/ndpi_utils.c b/src/lib/ndpi_utils.c index 2c215feefd9..c51d340bb30 100644 --- a/src/lib/ndpi_utils.c +++ b/src/lib/ndpi_utils.c @@ -23,7 +23,7 @@ #include #include #include - +#include #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_UNKNOWN @@ -76,8 +76,38 @@ typedef struct { UT_hash_handle hh; } ndpi_str_hash_priv; +typedef struct { + uint32_t seconds; + uint32_t fraction; +} ntp_t; + +#define NTP_DELTA 2208988800UL + /* ****************************************** */ +// https://tickelton.gitlab.io/articles/ntp-timestamps/ +void ntp_ts_to_string(uint64_t timestamp, char *buffer, size_t buffer_size) { + + if (timestamp == 0) { + buffer[0] = '\0'; + return; + } + + ntp_t ntp; + + memcpy(&ntp, ×tamp, sizeof(uint64_t)); + + struct timeval tv; + + tv.tv_sec = ntohl(ntp.seconds) - NTP_DELTA; + tv.tv_usec = (uint32_t)((double)ntohl(ntp.fraction) * 1.0e9 / (double)(1LL << 32)); + + struct tm *tm = gmtime(&tv.tv_sec); + size_t offset = strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", tm); + snprintf(buffer + offset, buffer_size - offset, ".%ld", tv.tv_usec); +} + + /* implementation of the punycode check function */ int ndpi_check_punycode_string(char * buffer , int len) { int i = 0; @@ -1380,8 +1410,26 @@ int ndpi_dpi2json(struct ndpi_detection_module_struct *ndpi_struct, case NDPI_PROTOCOL_NTP: ndpi_serialize_start_of_block(serializer, "ntp"); + ndpi_serialize_string_uint32(serializer, "leap_indicator", flow->protos.ntp.leap_indicator); ndpi_serialize_string_uint32(serializer, "version", flow->protos.ntp.version); ndpi_serialize_string_uint32(serializer, "mode", flow->protos.ntp.mode); + ndpi_serialize_string_uint32(serializer, "stratum", flow->protos.ntp.stratum); + ndpi_serialize_string_int32(serializer, "ppol", flow->protos.ntp.ppol); + ndpi_serialize_string_int32(serializer, "precision", flow->protos.ntp.precision); + ndpi_serialize_string_float(serializer, "root_delay", flow->protos.ntp.root_delay, "%f"); + ndpi_serialize_string_float(serializer, "root_dispersion", flow->protos.ntp.root_dispersion, "%f"); + ndpi_serialize_string_string(serializer, "ref_id", flow->protos.ntp.ref_id); + + + char timestamp[64]; + ntp_ts_to_string(flow->protos.ntp.ref_time, timestamp, sizeof timestamp); + ndpi_serialize_string_string(serializer, "ref_time", timestamp); + ntp_ts_to_string(flow->protos.ntp.org_time, timestamp, sizeof timestamp); + ndpi_serialize_string_string(serializer, "org_time", timestamp); + ntp_ts_to_string(flow->protos.ntp.rec_time, timestamp, sizeof timestamp); + ndpi_serialize_string_string(serializer, "rec_time", timestamp); + ntp_ts_to_string(flow->protos.ntp.trans_time, timestamp, sizeof timestamp); + ndpi_serialize_string_string(serializer, "trans_time", timestamp); ndpi_serialize_end_of_block(serializer); break; diff --git a/src/lib/protocols/ntp.c b/src/lib/protocols/ntp.c index 1804fdceb49..ff2373598a3 100644 --- a/src/lib/protocols/ntp.c +++ b/src/lib/protocols/ntp.c @@ -29,6 +29,7 @@ #include "ndpi_api.h" #include "ndpi_private.h" + static void ndpi_int_ntp_add_connection(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow) { @@ -49,11 +50,46 @@ static void ndpi_search_ntp_udp(struct ndpi_detection_module_struct *ndpi_struct if (version <= 4) { flow->protos.ntp.version = version; flow->protos.ntp.mode = packet->payload[0] & 7; - + flow->protos.ntp.leap_indicator = (packet->payload[0] & 192) >> 6; + + if (packet->payload_packet_len >= 48) { + u_int32_t tmp = 0; + flow->protos.ntp.stratum = packet->payload[1]; + flow->protos.ntp.ppol = (int8_t)packet->payload[2]; + flow->protos.ntp.precision = (int8_t)packet->payload[3]; + + // https://github.com/wireshark/wireshark/blob/c383ce5173cb15463259ca862cd5b469c2a3aab8/epan/dissectors/packet-ntp.c#L1574 + tmp = ntohl(get_u_int32_t(packet->payload, 4)); + flow->protos.ntp.root_delay = (tmp >> 16) + (tmp & 0xffff) / 65536.0; + tmp = ntohl(get_u_int32_t(packet->payload, 8)); + flow->protos.ntp.root_dispersion = (tmp >> 16) + (tmp & 0xffff) / 65536.0; + + if (flow->protos.ntp.stratum == 0 || flow->protos.ntp.stratum == 1) { + ndpi_snprintf(flow->protos.ntp.ref_id, sizeof(flow->protos.ntp.ref_id), "%c.%c.%c.%c", packet->payload[12], + packet->payload[13], + packet->payload[14], + packet->payload[15]); + } else { + if(packet->iph) { + tmp = get_u_int32_t(packet->payload, 12); + inet_ntop(AF_INET, &tmp, flow->protos.ntp.ref_id, sizeof(flow->protos.ntp.ref_id)); + } else { + ndpi_snprintf(flow->protos.ntp.ref_id, sizeof(flow->protos.ntp.ref_id), "%c:%c:%c:%c", packet->payload[12], + packet->payload[13], + packet->payload[14], + packet->payload[15]); + } + } + flow->protos.ntp.ref_time = get_u_int64_t(packet->payload, 16); + flow->protos.ntp.org_time = get_u_int64_t(packet->payload, 24); + flow->protos.ntp.rec_time = get_u_int64_t(packet->payload, 32); + flow->protos.ntp.trans_time = get_u_int64_t(packet->payload, 40); + } + } + NDPI_LOG_INFO(ndpi_struct, "found NTP\n"); ndpi_int_ntp_add_connection(ndpi_struct, flow); return; - } } NDPI_EXCLUDE_PROTO(ndpi_struct, flow);