From aa451354b274192e0a5d07620ab64c4f7266b64d Mon Sep 17 00:00:00 2001 From: German Service Network Date: Tue, 8 Oct 2024 20:40:03 +0200 Subject: [PATCH] Add feature: support ICMP type 13/14 timestamps --- ci/test-04-options-a-b.pl | 13 ++++++++- ci/test-05-options-c-e.pl | 21 ++++++++++++++- src/fping.c | 55 +++++++++++++++++++++++++++++++++++---- src/fping.h | 2 +- src/socket4.c | 14 ++++++++-- 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/ci/test-04-options-a-b.pl b/ci/test-04-options-a-b.pl index 1e16ee3..ec5b0f0 100755 --- a/ci/test-04-options-a-b.pl +++ b/ci/test-04-options-a-b.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -use Test::Command tests => 41; +use Test::Command tests => 44; use Test::More; use Time::HiRes qw(gettimeofday tv_interval); @@ -84,6 +84,17 @@ $cmd->stdout_like(qr{127\.0\.0\.1 is alive \(TTL \d+\)}); $cmd->stderr_is_eq(""); } +# fping --icmp-timestamp +SKIP: { +if($^O eq 'darwin') { + skip 'On macOS, this test is unreliable', 3; +} +my $cmd = Test::Command->new(cmd => "fping --icmp-timestamp 127.0.0.1"); +$cmd->exit_is_num(0); +$cmd->stdout_like(qr{127\.0\.0\.1 is alive \(Timestamp Originate=\d+ Receive=\d+ Transmit=\d+\)}); +$cmd->stderr_is_eq(""); +} + # fping --print-ttl with IPv6 SKIP: { if($ENV{SKIP_IPV6}) { diff --git a/ci/test-05-options-c-e.pl b/ci/test-05-options-c-e.pl index db5abd6..f8ca25a 100755 --- a/ci/test-05-options-c-e.pl +++ b/ci/test-05-options-c-e.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -use Test::Command tests => 75; +use Test::Command tests => 78; use Test::More; # -c n count of pings to send to each target (default 1) @@ -77,6 +77,25 @@ SKIP: { ff02::1 : xmt/rcv/%loss = 1/1/0%, min/avg/max = \d\.\d+/\d\.\d+/\d\.\d+\n}); } +# fping --icmp-timestamp -c n 127.0.0.1 +SKIP: { +if($^O eq 'darwin') { + skip 'On macOS, this test is unreliable', 3; +} +my $cmd = Test::Command->new(cmd => "fping -4 --icmp-timestamp -c 2 127.0.0.1"); +$cmd->exit_is_num(0); +$cmd->stdout_like(qr{127\.0\.0\.1 : \[0\], 20 bytes, \d\.\d+ ms \(\d\.\d+ avg, 0% loss\) +ICMP timestamp: Originate=\d+ Receive=\d+ Transmit=\d+ +ICMP timestamp RTT tsrtt=\d+ +127\.0\.0\.1 : \[1\], 20 bytes, \d\.\d+ ms \(\d\.\d+ avg, 0% loss\) +ICMP timestamp: Originate=\d+ Receive=\d+ Transmit=\d+ +ICMP timestamp RTT tsrtt=\d+ +}); + +$cmd->stderr_like(qr{127\.0\.0\.1 : xmt/rcv/%loss = 2/2/0%, min/avg/max = \d\.\d+/\d\.\d+/\d\.\d+ +}); +} + # fping -C n { my $cmd = Test::Command->new(cmd => "fping -4 -C 2 -p 100 localhost 127.0.0.1"); diff --git a/src/fping.c b/src/fping.c index 87b5fb9..fd38bc6 100644 --- a/src/fping.c +++ b/src/fping.c @@ -361,6 +361,7 @@ int timestamp_format_flag = 0; int random_data_flag = 0; int cumulative_stats_flag = 0; int check_source_flag = 0; +int icmp_request_typ = 0; int print_tos_flag = 0; int print_ttl_flag = 0; #if defined(DEBUG) || defined(_DEBUG) @@ -536,6 +537,7 @@ int main(int argc, char **argv) { "ttl", 'H', OPTPARSE_REQUIRED }, { "interval", 'i', OPTPARSE_REQUIRED }, { "iface", 'I', OPTPARSE_REQUIRED }, + { "icmp-timestamp", '0', OPTPARSE_NONE }, #ifdef SO_MARK { "fwmark", 'k', OPTPARSE_REQUIRED }, #endif @@ -584,6 +586,8 @@ int main(int argc, char **argv) } } else if (strstr(optparse_state.optlongname, "check-source") != NULL) { check_source_flag = 1; + } else if (strstr(optparse_state.optlongname, "icmp-timestamp") != NULL) { + icmp_request_typ = 13; } else if (strstr(optparse_state.optlongname, "print-tos") != NULL) { print_tos_flag = 1; } else if (strstr(optparse_state.optlongname, "print-ttl") != NULL) { @@ -1925,6 +1929,7 @@ int send_ping(HOST_ENTRY *h, int index) int n; int myseq; int ret = 1; + uint8_t proto = ICMP_ECHO; update_current_time(); h->last_send_time = current_time_ns; @@ -1933,7 +1938,9 @@ int send_ping(HOST_ENTRY *h, int index) dbg_printf("%s [%d]: send ping\n", h->host, index); if (h->saddr.ss_family == AF_INET && socket4 >= 0) { - n = socket_sendto_ping_ipv4(socket4, (struct sockaddr *)&h->saddr, h->saddr_len, myseq, ident4); + if(icmp_request_typ == 13) + proto = 13; + n = socket_sendto_ping_ipv4(socket4, (struct sockaddr *)&h->saddr, h->saddr_len, myseq, ident4, proto); } #ifdef IPV6 else if (h->saddr.ss_family == AF_INET6 && socket6 >= 0) { @@ -2173,7 +2180,10 @@ int decode_icmp_ipv4( unsigned short *id, unsigned short *seq, int *ip_header_tos, - int *ip_header_ttl) + int *ip_header_ttl, + long *ip_header_otime_ms, + long *ip_header_rtime_ms, + long *ip_header_ttime_ms) { struct icmp *icp; int hlen = 0; @@ -2206,7 +2216,7 @@ int decode_icmp_ipv4( icp = (struct icmp *)(reply_buf + hlen); - if (icp->icmp_type != ICMP_ECHOREPLY) { + if (icp->icmp_type != ICMP_ECHOREPLY && icp->icmp_type != 14) { /* Handle other ICMP packets */ struct icmp *sent_icmp; SEQMAP_VALUE *seqmap_value; @@ -2221,7 +2231,7 @@ int decode_icmp_ipv4( sent_icmp = (struct icmp *)(reply_buf + hlen + ICMP_MINLEN + sizeof(struct ip)); - if (sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != ident4) { + if ((sent_icmp->icmp_type != ICMP_ECHO && sent_icmp->icmp_type != 13) || sent_icmp->icmp_id != ident4) { /* not caused by us */ return -1; } @@ -2272,6 +2282,12 @@ int decode_icmp_ipv4( *id = icp->icmp_id; *seq = ntohs(icp->icmp_seq); + if(icp->icmp_type == 14) { + *ip_header_otime_ms = ntohl(icp->icmp_dun.id_ts.its_otime); + *ip_header_rtime_ms = ntohl(icp->icmp_dun.id_ts.its_rtime); + *ip_header_ttime_ms = ntohl(icp->icmp_dun.id_ts.its_ttime); + //tsdiff_ms = tsrecv_ms - tsorig_ms; + } return hlen; } @@ -2384,6 +2400,11 @@ int wait_for_reply(int64_t wait_time) unsigned short seq; int ip_header_tos = -1; int ip_header_ttl = -1; + // ICMP Timestamp + long ip_header_otime_ms = -1; + long ip_header_rtime_ms = -1; + long ip_header_ttime_ms = -1; + int tsrtt; /* Receive packet */ result = receive_packet(wait_time, /* max. wait time, in ns */ @@ -2412,7 +2433,10 @@ int wait_for_reply(int64_t wait_time) &id, &seq, &ip_header_tos, - &ip_header_ttl); + &ip_header_ttl, + &ip_header_otime_ms, + &ip_header_rtime_ms, + &ip_header_ttime_ms); if (ip_hlen < 0) { return 1; } @@ -2539,6 +2563,15 @@ int wait_for_reply(int64_t wait_time) } } + if (icmp_request_typ == 13) { + if(ip_header_otime_ms != -1 && ip_header_rtime_ms != -1 && ip_header_ttime_ms != -1) { + printf(" (Timestamp Originate=%lu Receive=%lu Transmit=%lu)", ip_header_otime_ms, ip_header_rtime_ms, ip_header_ttime_ms); + } + else { + printf(" (Timestamp unknown)"); + } + } + if (elapsed_flag) printf(" (%s ms)", sprint_tm(this_reply)); @@ -2578,6 +2611,17 @@ int wait_for_reply(int64_t wait_time) } printf("\n"); + + if (icmp_request_typ == 13) { + if(ip_header_otime_ms != -1 && ip_header_rtime_ms != -1 && ip_header_ttime_ms != -1) { + printf("ICMP timestamp: Originate=%lu Receive=%lu Transmit=%lu\n", ip_header_otime_ms, ip_header_rtime_ms, ip_header_ttime_ms); + tsrtt = (ip_header_ttime_ms - ip_header_otime_ms) + (this_reply - (ip_header_rtime_ms - ip_header_otime_ms)); + printf("ICMP timestamp RTT tsrtt=%d\n", tsrtt); + } + else { + printf("ICMP timestamp: unknown\n"); + } + } } return 1; @@ -3088,6 +3132,7 @@ void usage(int is_error) fprintf(out, " -t, --timeout=MSEC individual target initial timeout (default: %.0f ms,\n", timeout / 1e6); fprintf(out, " except with -l/-c/-C, where it's the -p period up to 2000 ms)\n"); fprintf(out, " --check-source discard replies not from target address\n"); + fprintf(out, " --icmp-timestamp send ping type Timestamp Request\n"); fprintf(out, "\n"); fprintf(out, "Output options:\n"); fprintf(out, " -a, --alive show targets that are alive\n"); diff --git a/src/fping.h b/src/fping.h index c0acdfb..f50710b 100644 --- a/src/fping.h +++ b/src/fping.h @@ -28,7 +28,7 @@ extern int random_data_flag; int open_ping_socket_ipv4(int *socktype); void init_ping_buffer_ipv4(size_t ping_data_size); void socket_set_src_addr_ipv4(int s, struct in_addr *src_addr, int *ident); -int socket_sendto_ping_ipv4(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq, uint16_t icmp_id); +int socket_sendto_ping_ipv4(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq, uint16_t icmp_id, uint8_t icmp_proto); #ifdef IPV6 int open_ping_socket_ipv6(int *socktype); void init_ping_buffer_ipv6(size_t ping_data_size); diff --git a/src/socket4.c b/src/socket4.c index d7c4ae3..d3d07d4 100644 --- a/src/socket4.c +++ b/src/socket4.c @@ -43,6 +43,7 @@ #include #include #include +#include char* ping_buffer_ipv4 = 0; size_t ping_pkt_size_ipv4; @@ -129,14 +130,23 @@ unsigned short calcsum(unsigned short* buffer, int length) return ~sum; } -int socket_sendto_ping_ipv4(int s, struct sockaddr* saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr) +int socket_sendto_ping_ipv4(int s, struct sockaddr* saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr, uint8_t icmp_proto) { struct icmp* icp; + struct timespec tsorig; + long tsorig_ms; int n; icp = (struct icmp*)ping_buffer_ipv4; - icp->icmp_type = ICMP_ECHO; + icp->icmp_type = icmp_proto; + if(icmp_proto == 13) { + clock_gettime(CLOCK_REALTIME, &tsorig); + tsorig_ms = (tsorig.tv_sec % (24*60*60)) * 1000 + tsorig.tv_nsec / 1000000; + icp->icmp_otime = htonl(tsorig_ms); + icp->icmp_rtime = 0; + icp->icmp_ttime = 0; + } icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_seq = htons(icmp_seq_nr); -- 2.43.0