diff options
| author | Maxim Konovalov <maxim@FreeBSD.org> | 2026-05-01 17:45:27 +0000 |
|---|---|---|
| committer | Maxim Konovalov <maxim@FreeBSD.org> | 2026-05-02 03:16:55 +0000 |
| commit | 069681afd58a711eb7407be4a9c9a05f787d250f (patch) | |
| tree | 7b11889fbf99de5441b558e33fa5e4f384d431c3 | |
| parent | c4f08d46c7f717cc8c66bf702c006765a5b6b1a9 (diff) | |
ping: use CLOCK_REALTIME for ICMP Originate Timestamp
RFC 792 defines the ICMP Originate Timestamp field as milliseconds
since midnight UTC. However, ping(8) currently derives this value
from CLOCK_MONOTONIC, which represents time since an unspecified
starting point and is not related to UTC.
The issue was introduced by commit 1ad76f1b6047, which replaced
gettimeofday(2) with clock_gettime(CLOCK_MONOTONIC) for timekeeping
in ping(8).
Fix this by using CLOCK_REALTIME when generating the ICMP originate
timestamp.
Before:
$ ping -Mt -c1 127.0.0.1
ICMP_TSTAMP
PING 127.0.0.1 (127.0.0.1): 56 data bytes
<...> time=0.061 ms tso=16:50:31 tsr=17:38:28 tst=17:38:28
(note the tso is off)
After:
$ ping -Mt -c1 127.0.0.1
ICMP_TSTAMP
PING 127.0.0.1 (127.0.0.1): 56 data bytes
<...> time=0.038 ms tso=17:42:09 tsr=17:42:09 tst=17:42:09
Reviewed by: asomers, glebius
Fixes: 1ad76f1b6047
MFC after: 1 month
Differential Revision: https://reviews.freebsd.org/D56759
| -rw-r--r-- | sbin/ping/ping.c | 9 | ||||
| -rw-r--r-- | sbin/ping/tests/ping_test.sh | 35 |
2 files changed, 43 insertions, 1 deletions
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c index d10e3c85c9bd..579ecb9151bb 100644 --- a/sbin/ping/ping.c +++ b/sbin/ping/ping.c @@ -1029,9 +1029,16 @@ pinger(void) */ tv32.tv32_sec = (uint32_t)htonl(now.tv_sec); tv32.tv32_nsec = (uint32_t)htonl(now.tv_nsec); - if (options & F_TIME) + if (options & F_TIME) { + /* + * However, per RFC 792 the Originate Timestamp (otime) + * should be milliseconds since midnight UTC. Something, + * that CLOCK_MONOTONIC does not guarantee. + */ + (void)clock_gettime(CLOCK_REALTIME, &now); icp.icmp_otime = htonl((now.tv_sec % (24*60*60)) * 1000 + now.tv_nsec / 1000000); + } if (timing) bcopy((void *)&tv32, (void *)&outpack[ICMP_MINLEN + phdr_len], diff --git a/sbin/ping/tests/ping_test.sh b/sbin/ping/tests/ping_test.sh index 5a12ace104d7..6e090cfd945a 100644 --- a/sbin/ping/tests/ping_test.sh +++ b/sbin/ping/tests/ping_test.sh @@ -253,6 +253,40 @@ inject_reply_cleanup() ifconfig `cat tun.txt` destroy } +atf_test_case timestamp_origin +timestamp_origin_head() +{ + atf_set "descr" "ICMP Originate Timestamp" +} +timestamp_origin_body() +{ + require_ipv4 + # Run ping timestamp + out=$(ping -Mt -c1 127.0.0.1) + + # Extract tso and tsr + tso=$(echo "$out" | sed -n 's/.*tso=\([0-9:]*\).*/\1/p') + tsr=$(echo "$out" | sed -n 's/.*tsr=\([0-9:]*\).*/\1/p') + + atf_check test -n "$tso" + atf_check test -n "$tsr" + + # Convert tso and tsr from HH:MM:SS to seconds + tso_s=`date -jf %H:%M:%S $tso` + tsr_s=`date -jf %H:%M:%S $tsr` + + diff=$((tso_s - tsr_s)) + # Tolerate negative time difference between the sender and receiver + if [ $diff -lt 0 ]; then + diff=$(( -diff )) + fi + + # Tolerate 2 seconds difference + if [ $diff -gt 2 ]; then + atf_fail "tso ($tso) differs from tsr ($tsr) by $diff seconds" + fi +} + atf_init_test_cases() { atf_add_test_case ping_c1_s56_t1 @@ -271,6 +305,7 @@ atf_init_test_cases() atf_add_test_case inject_opts atf_add_test_case inject_pip atf_add_test_case inject_reply + atf_add_test_case timestamp_origin } check_ping_statistics() |
