]> git.gsnw.org Git - fping.git/commitdiff
Add feature: support ICMP type 13/14 timestamps
authorGerman Service Network <support@gsnw.de>
Tue, 8 Oct 2024 18:40:03 +0000 (20:40 +0200)
committerSebastian <176771227+gsnw-sebast@users.noreply.github.com>
Mon, 11 Nov 2024 10:58:22 +0000 (11:58 +0100)
ci/test-04-options-a-b.pl
ci/test-05-options-c-e.pl
src/fping.c
src/fping.h
src/socket4.c

index 1e16ee3d6d194497f6c64b08df974deb9ef0fe4a..ec5b0f01617a1b1d1a5ad763e3aab835cffe8135 100755 (executable)
@@ -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}) {
index db5abd6d33dccd59945b6e9b711a7da5219158b9..f8ca25aadc82a2983444b326523a31d7c921eea3 100755 (executable)
@@ -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");
index 87b5fb9e53819332fa9780733d13789c614ff0f8..fd38bc666d3e8dde5ee9084ac82a7765321fdb0b 100644 (file)
@@ -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");
index c0acdfb852896a46052955eb8d469913ec6008a5..f50710bcedf09eb28de559abf84bbab2c2003f58 100644 (file)
@@ -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);
index d7c4ae359e3779ac4fbe5d2eaa18f725505d3748..d3d07d42ee69296b05cbaf2d84328ce9a3076127 100644 (file)
@@ -43,6 +43,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/socket.h>
+#include <time.h>
 
 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);