Skip to content

Commit 907ac1e

Browse files
committed
added serialization for ntp timestamp fields
1 parent 545e626 commit 907ac1e

6 files changed

Lines changed: 156 additions & 72 deletions

File tree

src/include/ndpi_typedefs.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,9 @@ struct ndpi_flow_udp_struct {
10541054
/* NDPI_PROTOCOL_TFTP */
10551055
u_int16_t tftp_data_num;
10561056
u_int16_t tftp_ack_num;
1057+
1058+
/* NDPI_PROTOCOL_NTP*/
1059+
u_int8_t ntp_stage;
10571060
};
10581061

10591062
/* ************************************************** */
@@ -1716,14 +1719,14 @@ struct ndpi_flow_struct {
17161719
char ptr_domain_name[64 /* large enough but smaller than { } tls */];
17171720
} dns;
17181721

1719-
struct {
1722+
struct ntp_info {
17201723
u_int8_t leap_indicator: 2, version: 3, mode: 3;
17211724
u_int8_t stratum;
17221725
int8_t ppol, precision;
17231726
float root_delay, root_dispersion;
1724-
char ref_id[16];
1727+
char ref_id[20];
17251728
uint64_t ref_time, org_time, rec_time, trans_time;
1726-
} ntp;
1729+
} ntp[2];
17271730

17281731
struct {
17291732
char hostname[48], domain[48], username[48];

src/lib/ndpi_utils.c

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <errno.h>
2424
#include <math.h>
2525
#include <sys/types.h>
26+
#include <time.h>
2627

2728
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_UNKNOWN
2829

@@ -76,8 +77,38 @@ typedef struct {
7677
UT_hash_handle hh;
7778
} ndpi_str_hash_priv;
7879

80+
typedef struct {
81+
uint32_t seconds;
82+
uint32_t fraction;
83+
} ntp_t;
84+
85+
#define NTP_DELTA 2208988800UL
86+
7987
/* ****************************************** */
8088

89+
// https://tickelton.gitlab.io/articles/ntp-timestamps/
90+
void ntp_ts_to_string(uint64_t timestamp, char *buffer, size_t buffer_size) {
91+
92+
if (timestamp == 0) {
93+
buffer[0] = '\0';
94+
return;
95+
}
96+
97+
ntp_t ntp;
98+
99+
memcpy(&ntp, &timestamp, sizeof(uint64_t));
100+
101+
time_t sec = ntohl(ntp.seconds) - NTP_DELTA;
102+
uint32_t usec = (uint32_t)((double)ntohl(ntp.fraction) * 1.0e9 / (double)(1LL << 32));
103+
104+
struct tm tm;
105+
106+
(void)ndpi_gmtime_r(&sec, &tm);
107+
size_t offset = strftime(buffer, buffer_size, "%Y-%m-%d %H:%M:%S", &tm);
108+
snprintf(buffer + offset, buffer_size - offset, ".%d", usec);
109+
}
110+
111+
81112
/* implementation of the punycode check function */
82113
int ndpi_check_punycode_string(char * buffer , int len) {
83114
int i = 0;
@@ -1626,19 +1657,30 @@ int ndpi_dpi2json(struct ndpi_detection_module_struct *ndpi_struct,
16261657

16271658
case NDPI_PROTOCOL_NTP:
16281659
ndpi_serialize_start_of_block(serializer, "ntp");
1629-
ndpi_serialize_string_uint32(serializer, "leap_indicator", flow->protos.ntp.leap_indicator);
1630-
ndpi_serialize_string_uint32(serializer, "version", flow->protos.ntp.version);
1631-
ndpi_serialize_string_uint32(serializer, "mode", flow->protos.ntp.mode);
1632-
ndpi_serialize_string_uint32(serializer, "stratum", flow->protos.ntp.stratum);
1633-
ndpi_serialize_string_int32(serializer, "ppol", flow->protos.ntp.ppol);
1634-
ndpi_serialize_string_int32(serializer, "precision", flow->protos.ntp.precision);
1635-
ndpi_serialize_string_float(serializer, "root_delay", flow->protos.ntp.root_delay, "%f");
1636-
ndpi_serialize_string_float(serializer, "root_dispersion", flow->protos.ntp.root_dispersion, "%f");
1637-
ndpi_serialize_string_string(serializer, "ref_id", flow->protos.ntp.ref_id);
1638-
ndpi_serialize_string_uint64(serializer, "ref_time", flow->protos.ntp.ref_time);
1639-
ndpi_serialize_string_uint64(serializer, "org_time", flow->protos.ntp.org_time);
1640-
ndpi_serialize_string_uint64(serializer, "rec_time", flow->protos.ntp.rec_time);
1641-
ndpi_serialize_string_uint64(serializer, "trans_time", flow->protos.ntp.trans_time);
1660+
for (i = 0; i < 2; i++) {
1661+
ndpi_serialize_start_of_block_uint32(serializer,i);
1662+
ndpi_serialize_string_uint32(serializer, "leap_indicator", flow->protos.ntp[i].leap_indicator);
1663+
ndpi_serialize_string_uint32(serializer, "version", flow->protos.ntp[i].version);
1664+
ndpi_serialize_string_uint32(serializer, "mode", flow->protos.ntp[i].mode);
1665+
ndpi_serialize_string_uint32(serializer, "stratum", flow->protos.ntp[i].stratum);
1666+
ndpi_serialize_string_int32(serializer, "ppol", flow->protos.ntp[i].ppol);
1667+
ndpi_serialize_string_int32(serializer, "precision", flow->protos.ntp[i].precision);
1668+
ndpi_serialize_string_float(serializer, "root_delay", flow->protos.ntp[i].root_delay, "%f");
1669+
ndpi_serialize_string_float(serializer, "root_dispersion", flow->protos.ntp[i].root_dispersion, "%f");
1670+
ndpi_serialize_string_string(serializer, "ref_id", flow->protos.ntp[i].ref_id);
1671+
1672+
1673+
char timestamp[64];
1674+
ntp_ts_to_string(flow->protos.ntp[i].ref_time, timestamp, sizeof timestamp);
1675+
ndpi_serialize_string_string(serializer, "ref_time", timestamp);
1676+
ntp_ts_to_string(flow->protos.ntp[i].org_time, timestamp, sizeof timestamp);
1677+
ndpi_serialize_string_string(serializer, "org_time", timestamp);
1678+
ntp_ts_to_string(flow->protos.ntp[i].rec_time, timestamp, sizeof timestamp);
1679+
ndpi_serialize_string_string(serializer, "rec_time", timestamp);
1680+
ntp_ts_to_string(flow->protos.ntp[i].trans_time, timestamp, sizeof timestamp);
1681+
ndpi_serialize_string_string(serializer, "trans_time", timestamp);
1682+
ndpi_serialize_end_of_block(serializer);
1683+
}
16421684
ndpi_serialize_end_of_block(serializer);
16431685
break;
16441686

src/lib/protocols/ntp.c

Lines changed: 86 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*
2020
* You should have received a copy of the GNU Lesser General Public License
2121
* along with nDPI. If not, see <http://www.gnu.org/licenses/>.
22-
*
22+
*
2323
*/
2424

2525
#include "ndpi_protocol_ids.h"
@@ -30,69 +30,109 @@
3030
#include "ndpi_private.h"
3131

3232

33+
static void ndpi_search_ntp_udp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow);
34+
35+
36+
static int ndpi_search_ntp_again(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
37+
{
38+
ndpi_search_ntp_udp(ndpi_struct, flow);
39+
return 1;
40+
}
41+
42+
static void ndpi_set_extra_dissection(struct ndpi_flow_struct *flow)
43+
{
44+
flow->max_extra_packets_to_check = 1;
45+
flow->extra_packets_func = ndpi_search_ntp_again;
46+
}
47+
3348
static void ndpi_int_ntp_add_connection(struct ndpi_detection_module_struct
3449
*ndpi_struct, struct ndpi_flow_struct *flow)
3550
{
3651
ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_NTP, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
3752
}
3853

39-
static void ndpi_search_ntp_udp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
54+
static void get_ntp_info(struct ndpi_flow_struct *flow, struct ndpi_packet_struct *packet, uint8_t stage)
4055
{
41-
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
42-
43-
NDPI_LOG_DBG(ndpi_struct, "search NTP\n");
44-
45-
if (packet->udp->dest == htons(123) || packet->udp->source == htons(123)) {
46-
47-
NDPI_LOG_DBG2(ndpi_struct, "NTP port and length detected\n");
48-
uint8_t version = (packet->payload[0] & 56) >> 3;
49-
50-
if (version <= 4) {
51-
flow->protos.ntp.version = version;
52-
flow->protos.ntp.mode = packet->payload[0] & 7;
53-
flow->protos.ntp.leap_indicator = (packet->payload[0] & 192) >> 6;
54-
55-
if (packet->payload_packet_len >= 48) {
56-
u_int32_t tmp = 0;
57-
flow->protos.ntp.stratum = packet->payload[1];
58-
flow->protos.ntp.ppol = (int8_t)packet->payload[2];
59-
flow->protos.ntp.precision = (int8_t)packet->payload[3];
60-
61-
// https://github.com/wireshark/wireshark/blob/c383ce5173cb15463259ca862cd5b469c2a3aab8/epan/dissectors/packet-ntp.c#L1574
62-
tmp = ntohl(get_u_int32_t(packet->payload, 4));
63-
flow->protos.ntp.root_delay = (tmp >> 16) + (tmp & 0xffff) / 65536.0;
64-
tmp = ntohl(get_u_int32_t(packet->payload, 8));
65-
flow->protos.ntp.root_dispersion = (tmp >> 16) + (tmp & 0xffff) / 65536.0;
66-
67-
if (flow->protos.ntp.stratum == 0 || flow->protos.ntp.stratum == 1) {
68-
ndpi_snprintf(flow->protos.ntp.ref_id, sizeof(flow->protos.ntp.ref_id), "%c%c%c%c", packet->payload[12],
56+
u_int32_t tmp = 0;
57+
flow->protos.ntp[stage].ppol = (int8_t)packet->payload[2];
58+
flow->protos.ntp[stage].precision = (int8_t)packet->payload[3];
59+
60+
// https://github.com/wireshark/wireshark/blob/c383ce5173cb15463259ca862cd5b469c2a3aab8/epan/dissectors/packet-ntp.c#L1574
61+
tmp = ntohl(get_u_int32_t(packet->payload, 4));
62+
flow->protos.ntp[stage].root_delay = (tmp >> 16) + (tmp & 0xffff) / 65536.0;
63+
tmp = ntohl(get_u_int32_t(packet->payload, 8));
64+
flow->protos.ntp[stage].root_dispersion = (tmp >> 16) + (tmp & 0xffff) / 65536.0;
65+
66+
if (flow->protos.ntp[stage].stratum == 0 || flow->protos.ntp[stage].stratum == 1) {
67+
ndpi_snprintf(flow->protos.ntp[stage].ref_id, sizeof(flow->protos.ntp[stage].ref_id), "%c%c%c%c", packet->payload[12],
6968
packet->payload[13],
7069
packet->payload[14],
7170
packet->payload[15]);
72-
} else {
73-
if(packet->iph) {
74-
tmp = get_u_int32_t(packet->payload, 12);
75-
inet_ntop(AF_INET, &tmp, flow->protos.ntp.ref_id, sizeof(flow->protos.ntp.ref_id));
76-
} else {
77-
ndpi_snprintf(flow->protos.ntp.ref_id, sizeof(flow->protos.ntp.ref_id), "%c%c%c%c", packet->payload[12],
71+
} else {
72+
if(packet->iph) {
73+
tmp = get_u_int32_t(packet->payload, 12);
74+
inet_ntop(AF_INET, &tmp, flow->protos.ntp[stage].ref_id, sizeof(flow->protos.ntp[stage].ref_id));
75+
} else {
76+
ndpi_snprintf(flow->protos.ntp[stage].ref_id, sizeof(flow->protos.ntp[stage].ref_id), "%c:%c:%c:%c", packet->payload[12],
7877
packet->payload[13],
7978
packet->payload[14],
8079
packet->payload[15]);
81-
}
82-
}
83-
flow->protos.ntp.ref_time = get_u_int64_t(packet->payload, 16);
84-
flow->protos.ntp.org_time = get_u_int64_t(packet->payload, 24);
85-
flow->protos.ntp.rec_time = get_u_int64_t(packet->payload, 32);
86-
flow->protos.ntp.trans_time = get_u_int64_t(packet->payload, 40);
8780
}
8881
}
82+
flow->protos.ntp[stage].ref_time = get_u_int64_t(packet->payload, 16);
83+
flow->protos.ntp[stage].org_time = get_u_int64_t(packet->payload, 24);
84+
flow->protos.ntp[stage].rec_time = get_u_int64_t(packet->payload, 32);
85+
flow->protos.ntp[stage].trans_time = get_u_int64_t(packet->payload, 40);
86+
}
8987

90-
NDPI_LOG_INFO(ndpi_struct, "found NTP\n");
91-
ndpi_int_ntp_add_connection(ndpi_struct, flow);
92-
return;
88+
static void ndpi_search_ntp_udp(struct ndpi_detection_module_struct *ndpi_struct, struct ndpi_flow_struct *flow)
89+
{
90+
struct ndpi_packet_struct *packet = &ndpi_struct->packet;
91+
92+
NDPI_LOG_DBG(ndpi_struct, "search NTP\n");
93+
94+
if (packet->udp->dest != htons(123) && packet->udp->source != htons(123)) {
95+
NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
96+
return;
9397
}
9498

95-
NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
99+
if (packet->payload_packet_len < 48) {
100+
NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
101+
return;
102+
}
103+
104+
uint8_t version = (packet->payload[0] & 56) >> 3;
105+
106+
if (version == 2) {
107+
flow->protos.ntp[flow->l4.udp.ntp_stage].version = version;
108+
ndpi_int_ntp_add_connection(ndpi_struct, flow);
109+
return;
110+
}
111+
112+
if (version > 4) {
113+
NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
114+
return;
115+
}
116+
117+
uint8_t mode = packet->payload[0] & 7;
118+
uint8_t stratum = packet->payload[1];
119+
120+
if (stratum > 16) {
121+
NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
122+
return;
123+
}
124+
125+
flow->protos.ntp[flow->l4.udp.ntp_stage].version = version;
126+
flow->protos.ntp[flow->l4.udp.ntp_stage].mode = mode;
127+
flow->protos.ntp[flow->l4.udp.ntp_stage].leap_indicator = (packet->payload[0] & 192) >> 6;
128+
flow->protos.ntp[flow->l4.udp.ntp_stage].stratum = stratum;
129+
130+
get_ntp_info(flow, packet, flow->l4.udp.ntp_stage);
131+
flow->l4.udp.ntp_stage = 1;
132+
NDPI_LOG_INFO(ndpi_struct, "found NTP\n");
133+
ndpi_set_extra_dissection(flow);
134+
ndpi_int_ntp_add_connection(ndpi_struct, flow);
135+
return;
96136
}
97137

98138

@@ -103,4 +143,3 @@ void init_ntp_dissector(struct ndpi_detection_module_struct *ndpi_struct)
103143
NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_UDP_WITH_PAYLOAD,
104144
1, NDPI_PROTOCOL_NTP);
105145
}
106-

tests/cfgs/default/result/android.pcap.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Guessed flow protos: 3
22

33
DPI Packets (TCP): 147 (5.25 pkts/flow)
4-
DPI Packets (UDP): 52 (1.68 pkts/flow)
4+
DPI Packets (UDP): 53 (1.71 pkts/flow)
55
DPI Packets (other): 4 (1.00 pkts/flow)
66
Confidence Match by port : 2 (flows)
77
Confidence DPI : 60 (flows)
@@ -105,7 +105,7 @@ JA Host Stats:
105105
36 UDP 192.168.2.16:7660 <-> 192.168.2.1:53 [proto: 5/DNS][Stack: DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][cat: Network/14][Breed: Acceptable][1 pkts/84 bytes <-> 1 pkts/100 bytes][Goodput ratio: 49/57][0.04 sec][Hostname/SNI: datasaver.googleapis.com][172.217.21.202][DNS Id: 0xfda8][PLAIN TEXT (datasaver)][Plen Bins: 0,100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
106106
37 UDP 192.168.2.16:18379 <-> 192.168.2.1:53 [proto: 5/DNS][Stack: DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][cat: Network/14][Breed: Acceptable][1 pkts/84 bytes <-> 1 pkts/100 bytes][Goodput ratio: 49/57][0.00 sec][Hostname/SNI: datasaver.googleapis.com][172.217.21.202][DNS Id: 0x3c64][PLAIN TEXT (datasaver)][Plen Bins: 0,100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
107107
38 UDP 192.168.2.16:39760 <-> 192.168.2.1:53 [proto: 5/DNS][Stack: DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][cat: Network/14][Breed: Acceptable][1 pkts/82 bytes <-> 1 pkts/98 bytes][Goodput ratio: 48/57][0.04 sec][Hostname/SNI: android.googleapis.com][172.217.22.10][DNS Id: 0xb8a5][PLAIN TEXT (android)][Plen Bins: 0,100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
108-
39 UDP 192.168.2.16:45863 <-> 216.239.35.8:123 [proto: 9/NTP][Stack: NTP][IP: 126/Google][ClearText][Confidence: DPI][FPC: 9/NTP, Confidence: DPI][DPI packets: 1][cat: System/18][Breed: Acceptable][1 pkts/90 bytes <-> 1 pkts/90 bytes][Goodput ratio: 53/53][0.04 sec][Plen Bins: 0,100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
108+
39 UDP 192.168.2.16:45863 <-> 216.239.35.8:123 [proto: 9/NTP][Stack: NTP][IP: 126/Google][ClearText][Confidence: DPI][FPC: 9/NTP, Confidence: DPI][DPI packets: 2][cat: System/18][Breed: Acceptable][1 pkts/90 bytes <-> 1 pkts/90 bytes][Goodput ratio: 53/53][0.04 sec][Plen Bins: 0,100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
109109
40 ICMPV6 [::]:0 -> [ff02::16]:0 [proto: 102/ICMPV6][Stack: ICMPV6][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 102/ICMPV6, Confidence: DPI][DPI packets: 1][cat: Network/14][Breed: Acceptable][2 pkts/180 bytes -> 0 pkts/0 bytes][Goodput ratio: 22/0][0.22 sec][Plen Bins: 100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
110110
41 ICMPV6 [fe80::4e6a:f6ff:fe9f:f627]:0 -> [ff02::16]:0 [proto: 102/ICMPV6][Stack: ICMPV6][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 102/ICMPV6, Confidence: DPI][DPI packets: 1][cat: Network/14][Breed: Acceptable][2 pkts/180 bytes -> 0 pkts/0 bytes][Goodput ratio: 22/0][0.09 sec][Plen Bins: 100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
111111
42 UDP 192.168.2.16:10677 <-> 192.168.2.1:53 [proto: 5/DNS][Stack: DNS][IP: 0/Unknown][ClearText][Confidence: DPI][FPC: 5/DNS, Confidence: DPI][DPI packets: 2][cat: Network/14][Breed: Acceptable][1 pkts/79 bytes <-> 1 pkts/95 bytes][Goodput ratio: 46/55][0.00 sec][Hostname/SNI: proxy.googlezip.net][172.217.20.76][DNS Id: 0xd5f9][PLAIN TEXT (googlezip)][Plen Bins: 0,100,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]

0 commit comments

Comments
 (0)