PR/45257: Instead of passing a 32bit sec and 32 bit usec timestamp in little

endian format by default, pass a struct timespec in native host format. Add
-C flag to produce a compatible timestamp like before.
This commit is contained in:
christos 2011-09-10 20:04:28 +00:00
parent 3cc8722d9f
commit e8ad09e0b7
2 changed files with 112 additions and 68 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ping.8,v 1.47 2006/03/21 22:54:46 pavel Exp $
.\" $NetBSD: ping.8,v 1.48 2011/09/10 20:04:28 christos Exp $
.\"
.\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\"
.\" @(#)ping.8 8.2 (Berkeley) 12/11/93
.\"
.Dd March 21, 2006
.Dd September 10, 2011
.Dt PING 8
.Os
.Sh NAME
@ -40,7 +40,7 @@ packets to network hosts
.Sh SYNOPSIS
.Nm
.Bk -words
.Op Fl adDfLnoPqQrRv
.Op Fl aCdDfLnoPqQrRv
.Ek
.Bk -words
.Op Fl c Ar count
@ -93,7 +93,7 @@ datagrams (``pings'') have an IP and
.Tn ICMP
header,
followed by a
.Dq struct timeval
.Dq struct timespec
and then an arbitrary number of ``pad'' bytes used to fill out the
packet.
The options are as follows:
@ -108,6 +108,10 @@ Stop after sending (and waiting the specified delay to receive)
.Ar count
.Tn ECHO_RESPONSE
packets.
.It Fl C
Send timestamps in compat format; two 32 bit words in little endian format,
the first one representing seconds, and the second one representing
microseconds.
.It Fl d
Set the
.Dv SO_DEBUG
@ -322,12 +326,20 @@ will always be 8 bytes more than the requested data space (the
.Tn ICMP
header).
.Pp
If the data space is at least eight bytes large,
If the data space is at least
.Dv sizeof(struct timespec)
(16) large,
.Nm
uses the first
.Dv sizeof(struct timespec)
byres to include a timestamp to compute round trip times.
Otherwise if the data space is at least eight bytes large (or the
.Fl C
flag is specified),
.Nm
uses the first eight bytes of this space to include a timestamp to compute
round trip times.
If less than eight bytes of pad are specified,
no round trip times are given.
If there are not enough bytes of pad no round trip times are given.
.Sh DUPLICATE AND DAMAGED PACKETS
.Nm
will report duplicate and damaged packets.

View File

@ -1,4 +1,4 @@
/* $NetBSD: ping.c,v 1.98 2011/08/27 18:40:18 joerg Exp $ */
/* $NetBSD: ping.c,v 1.99 2011/09/10 20:04:28 christos Exp $ */
/*
* Copyright (c) 1989, 1993
@ -58,7 +58,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: ping.c,v 1.98 2011/08/27 18:40:18 joerg Exp $");
__RCSID("$NetBSD: ping.c,v 1.99 2011/09/10 20:04:28 christos Exp $");
#endif
#include <stdio.h>
@ -113,6 +113,7 @@ __RCSID("$NetBSD: ping.c,v 1.98 2011/08/27 18:40:18 joerg Exp $");
#define F_MCAST 0x2000 /* multicast target */
#define F_MCAST_NOLOOP 0x4000 /* no multicast loopback */
#define F_AUDIBLE 0x8000 /* audible output */
#define F_TIMING64 0x10000 /* 64 bit time, nanoseconds */
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
#define F_POLICY 0x10000
@ -151,11 +152,13 @@ static char *fill_pat;
static int s; /* Socket file descriptor */
static int sloop; /* Socket file descriptor/loopback */
#define PHDR_LEN sizeof(struct tv32) /* size of timestamp header */
#define PHDR_LEN sizeof(struct tv32) /* size of timestamp header */
#define PHDR64_LEN sizeof(struct timespec) /* size of timestamp header */
static struct sockaddr_in whereto, send_addr; /* Who to ping */
static struct sockaddr_in src_addr; /* from where */
static struct sockaddr_in loc_addr; /* 127.1 */
static int datalen = 64 - PHDR_LEN; /* How much data */
static int datalen; /* How much data */
static int phdrlen;
#ifndef __NetBSD__
static char *progname;
@ -187,7 +190,7 @@ static int ident; /* our ID, in network byte order */
static int nreceived; /* # of packets we got back */
static double interval; /* interval between packets */
static struct timeval interval_tv;
static struct timespec interval_tv;
static double tmin = 999999999.0;
static double tmax = 0.0;
static double tsum = 0.0; /* sum of all times */
@ -196,11 +199,11 @@ static double maxwait = 0.0;
static int bufspace = IP_MAXPACKET;
static struct timeval now, clear_cache, last_tx, next_tx, first_tx;
static struct timeval last_rx, first_rx;
static struct timespec now, clear_cache, last_tx, next_tx, first_tx;
static struct timespec last_rx, first_rx;
static int lastrcvd = 1; /* last ping sent has been received */
static struct timeval jiggle_time;
static struct timespec jiggle_time;
static int jiggle_cnt, total_jiggled, jiggle_direction = -1;
__dead static void doit(void);
@ -211,10 +214,12 @@ static void summary(int);
static void pinger(void);
static void fill(void);
static void rnd_fill(void);
static double diffsec(struct timeval *, struct timeval *);
static void timevaladd(struct timeval *, struct timeval *);
static void sec_to_timeval(const double, struct timeval *);
static double timeval_to_sec(const struct timeval *);
static double diffsec(struct timespec *, struct timespec *);
#if 0
static void timespecadd(struct timespec *, struct timespec *);
#endif
static void sec_to_timespec(const double, struct timespec *);
static double timespec_to_sec(const struct timespec *);
static void pr_pack(u_char *, int, struct sockaddr_in *);
static u_int16_t in_cksum(u_int16_t *, u_int);
static void pr_saddr(u_char *);
@ -232,6 +237,7 @@ main(int argc, char *argv[])
{
int c, i, on = 1, hostind = 0;
long l;
int len = -1, compat = 0;
u_char ttl = 0;
u_long tos = 0;
char *p;
@ -275,12 +281,15 @@ main(int argc, char *argv[])
#endif /*IPSEC_POLICY_IPSEC*/
#endif
while ((c = getopt(argc, argv,
"ac:dDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:" IPSECOPT)) != -1) {
"ac:CdDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:" IPSECOPT)) != -1) {
#undef IPSECOPT
switch (c) {
case 'a':
pingflags |= F_AUDIBLE;
break;
case 'C':
compat = 1;
break;
case 'c':
npackets = strtol(optarg, &p, 0);
if (*p != '\0' || npackets <= 0)
@ -341,7 +350,7 @@ main(int argc, char *argv[])
errx(1, "Bad/invalid packet size %s", optarg);
if (l > MAXPACKET)
errx(1, "packet size is too large");
datalen = (int)l;
len = (int)l;
break;
case 'v':
pingflags |= F_VERBOSE;
@ -416,7 +425,7 @@ main(int argc, char *argv[])
if (preload > 0 && prog_getuid())
errx(1, "Must be superuser to use -l");
#endif
sec_to_timeval(interval, &interval_tv);
sec_to_timespec(interval, &interval_tv);
if ((pingflags & (F_AUDIBLE|F_FLOOD)) == (F_AUDIBLE|F_FLOOD))
warnx("Sorry, no audible output for flood pings");
@ -446,8 +455,20 @@ main(int argc, char *argv[])
loc_addr.sin_len = sizeof(struct sockaddr_in);
loc_addr.sin_addr.s_addr = htonl((127 << 24) + 1);
if (datalen >= (int)PHDR_LEN) /* can we time them? */
if (len != -1)
datalen = len;
else
datalen = 64;
if (!compat && datalen >= (int)PHDR64_LEN) { /* can we time them? */
pingflags |= F_TIMING64;
phdrlen = PHDR64_LEN;
} else if (datalen >= (int)PHDR_LEN) { /* can we time them? */
pingflags |= F_TIMING;
phdrlen = PHDR_LEN;
} else
phdrlen = 0;
datalen -= phdrlen;
packlen = datalen + 60 + 76; /* MAXIP + MAXICMP */
if ((packet = malloc(packlen)) == NULL)
err(1, "Out of memory");
@ -457,7 +478,7 @@ main(int argc, char *argv[])
} else if (pingflags & F_PING_RANDOM) {
rnd_fill();
} else {
for (i = PHDR_LEN; i < datalen; i++)
for (i = phdrlen; i < datalen; i++)
opack_icmp.icmp_data[i] = i;
}
@ -649,7 +670,7 @@ main(int argc, char *argv[])
/* fire off them quickies */
for (i = 0; i < preload; i++) {
(void)gettimeofday(&now, 0);
clock_gettime(CLOCK_MONOTONIC, &now);
pinger();
}
@ -667,9 +688,9 @@ doit(void)
double sec, last, d_last;
struct pollfd fdmaskp[1];
(void)gettimeofday(&clear_cache,0);
(void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
if (maxwait != 0) {
last = timeval_to_sec(&clear_cache) + maxwait;
last = timespec_to_sec(&clear_cache) + maxwait;
d_last = 0;
} else {
last = 0;
@ -677,10 +698,10 @@ doit(void)
}
do {
(void)gettimeofday(&now,0);
clock_gettime(CLOCK_MONOTONIC, &now);
if (last != 0)
d_last = last - timeval_to_sec(&now);
d_last = last - timespec_to_sec(&now);
if (ntransmitted < npackets && d_last > 0) {
/* send if within 100 usec or late for next packet */
@ -708,7 +729,6 @@ doit(void)
break;
}
fdmaskp[0].fd = s;
fdmaskp[0].events = POLLIN;
cc = prog_poll(fdmaskp, 1, (int)(sec * 1000));
@ -734,7 +754,7 @@ doit(void)
}
continue;
}
(void)gettimeofday(&now, 0);
clock_gettime(CLOCK_MONOTONIC, &now);
pr_pack(packet, cc, &from);
} while (nreceived < npackets
@ -806,9 +826,10 @@ jiggle(int delta)
/*
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
* will be added on by the kernel. The ID field is our UNIX process ID,
* and the sequence number is an ascending integer. The first PHDR_LEN bytes
* and the sequence number is an ascending integer. The first phdrlen bytes
* of the data portion are used to hold a UNIX "timeval" struct in VAX
* byte-order, to compute the round-trip time.
* byte-order, to compute the round-trip time, or a UNIX "timespec" in native
* format.
*/
static void
pinger(void)
@ -830,13 +851,13 @@ pinger(void)
opack_icmp.icmp_id = ~ident;
opack_icmp.icmp_cksum = 0;
opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp,
PHDR_LEN);
phdrlen);
sw = 0;
if (prog_setsockopt(sloop,IPPROTO_IP,IP_HDRINCL,
(char *)&sw,sizeof(sw)) < 0)
err(1, "Can't turn off special IP header");
if (prog_sendto(sloop, (char *) &opack_icmp,
PHDR_LEN, MSG_DONTROUTE,
phdrlen, MSG_DONTROUTE,
(struct sockaddr *)&loc_addr,
sizeof(struct sockaddr_in)) < 0) {
/*
@ -853,16 +874,20 @@ pinger(void)
(char *)&sw, sizeof(sw)) < 0)
err(1, "Can't set special IP header");
(void)gettimeofday(&clear_cache,0);
(void)clock_gettime(CLOCK_MONOTONIC, &clear_cache);
}
opack_icmp.icmp_type = ICMP_ECHO;
opack_icmp.icmp_id = ident;
tv32.tv32_sec = (uint32_t)htonl(now.tv_sec);
tv32.tv32_usec = htonl(now.tv_usec);
if (pingflags & F_TIMING)
if (pingflags & F_TIMING) {
tv32.tv32_sec = (uint32_t)htonl(now.tv_sec);
tv32.tv32_usec = htonl(now.tv_nsec / 1000);
(void) memcpy(&opack_icmp.icmp_data[0], &tv32, sizeof(tv32));
cc = datalen + PHDR_LEN;
} else if (pingflags & F_TIMING64)
(void) memcpy(&opack_icmp.icmp_data[0], &now, sizeof(now));
cc = datalen + phdrlen;
opack_icmp.icmp_cksum = 0;
opack_icmp.icmp_cksum = in_cksum((u_int16_t *)&opack_icmp, cc);
@ -896,7 +921,7 @@ pinger(void)
*/
if (diffsec(&next_tx, &now) <= interval) {
do {
timevaladd(&next_tx, &interval_tv);
timespecadd(&next_tx, &interval_tv, &next_tx);
} while (diffsec(&next_tx, &now) < -0.1);
}
@ -928,7 +953,7 @@ pr_pack_sub(int cc,
if (dupflag)
(void)printf(" DUP!");
(void)printf(" ttl=%d", ttl);
if (pingflags & F_TIMING)
if (pingflags & (F_TIMING|F_TIMING64))
(void)printf(" time=%.3f ms", triptime*1000.0);
/*
@ -983,6 +1008,8 @@ pr_pack(u_char *buf,
icp = (struct icmp *)(buf + hlen);
if (icp->icmp_type == ICMP_ECHOREPLY
&& icp->icmp_id == ident) {
struct timespec tv;
if (icp->icmp_seq == htons((u_int16_t)(ntransmitted-1)))
lastrcvd = 1;
last_rx = now;
@ -990,12 +1017,15 @@ pr_pack(u_char *buf,
first_rx = last_rx;
nreceived++;
if (pingflags & F_TIMING) {
struct timeval tv;
struct tv32 tv32;
(void) memcpy(&tv32, icp->icmp_data, sizeof(tv32));
tv.tv_sec = (uint32_t)ntohl(tv32.tv32_sec);
tv.tv_usec = ntohl(tv32.tv32_usec);
tv.tv_nsec = ntohl(tv32.tv32_usec) * 1000;
} else if (pingflags & F_TIMING64)
(void) memcpy(&tv, icp->icmp_data, sizeof(tv));
if (pingflags & (F_TIMING|F_TIMING64)) {
triptime = diffsec(&last_rx, &tv);
tsum += triptime;
tsumsq += triptime * triptime;
@ -1066,12 +1096,12 @@ pr_pack(u_char *buf,
PR_PACK_SUB();
/* check the data */
if (datalen > (int)PHDR_LEN
if (datalen > phdrlen
&& !(pingflags & F_PING_RANDOM)
&& memcmp(icp->icmp_data + PHDR_LEN,
opack_icmp.icmp_data + PHDR_LEN,
datalen-PHDR_LEN)) {
for (i=PHDR_LEN; i<datalen; i++) {
&& memcmp(icp->icmp_data + phdrlen,
opack_icmp.icmp_data + phdrlen,
datalen - phdrlen)) {
for (i = phdrlen; i < datalen; i++) {
if (icp->icmp_data[i] !=
opack_icmp.icmp_data[i])
break;
@ -1081,8 +1111,8 @@ pr_pack(u_char *buf,
" %#x but was %#x", i,
(u_char)opack_icmp.icmp_data[i],
(u_char)icp->icmp_data[i]);
for (i=PHDR_LEN; i<datalen; i++) {
if ((i%16) == PHDR_LEN)
for (i = phdrlen; i < datalen; i++) {
if ((i % 16) == phdrlen)
(void)printf("\n\t");
(void)printf("%2x ",(u_char)icp->icmp_data[i]);
}
@ -1235,44 +1265,46 @@ in_cksum(u_int16_t *p, u_int len)
/*
* compute the difference of two timevals in seconds
* compute the difference of two timespecs in seconds
*/
static double
diffsec(struct timeval *timenow,
struct timeval *then)
diffsec(struct timespec *timenow,
struct timespec *then)
{
if (timenow->tv_sec == 0)
return -1;
return ((int32_t)((uint32_t)timenow->tv_sec - (uint32_t)then->tv_sec)
* 1.0 + (timenow->tv_usec - then->tv_usec)/1000000.0);
return (timenow->tv_sec - then->tv_sec)
* 1.0 + (timenow->tv_nsec - then->tv_nsec) / 1000000000.0;
}
#if 0
static void
timevaladd(struct timeval *t1,
struct timeval *t2)
timespecadd(struct timespec *t1,
struct timespec *t2)
{
t1->tv_sec += t2->tv_sec;
if ((t1->tv_usec += t2->tv_usec) >= 1000000) {
if ((t1->tv_nsec += t2->tv_nsec) >= 1000000000) {
t1->tv_sec++;
t1->tv_usec -= 1000000;
t1->tv_nsec -= 1000000000;
}
}
#endif
static void
sec_to_timeval(const double sec, struct timeval *tp)
sec_to_timespec(const double sec, struct timespec *tp)
{
tp->tv_sec = sec;
tp->tv_usec = (sec - tp->tv_sec) * 1000000.0;
tp->tv_nsec = (sec - tp->tv_sec) * 1000000000.0;
}
static double
timeval_to_sec(const struct timeval *tp)
timespec_to_sec(const struct timespec *tp)
{
return tp->tv_sec + tp->tv_usec / 1000000.0;
return tp->tv_sec + tp->tv_nsec / 1000000000.0;
}
@ -1768,7 +1800,7 @@ fill(void)
&pat[8], &pat[9], &pat[10], &pat[11],
&pat[12], &pat[13], &pat[14], &pat[15]);
for (k=PHDR_LEN, j = 0; k <= datalen; k++) {
for (k = phdrlen, j = 0; k <= datalen; k++) {
opack_icmp.icmp_data[k] = pat[j];
if (++j >= i)
j = 0;
@ -1778,7 +1810,7 @@ fill(void)
(void)printf("PATTERN: 0x");
for (j=0; j<i; j++)
(void)printf("%02x",
(u_char)opack_icmp.icmp_data[PHDR_LEN+j]);
(u_char)opack_icmp.icmp_data[phdrlen + j]);
(void)printf("\n");
}
@ -1791,7 +1823,7 @@ rnd_fill(void)
static u_int32_t rnd;
int i;
for (i = PHDR_LEN; i < datalen; i++) {
for (i = phdrlen; i < datalen; i++) {
rnd = (3141592621U * rnd + 663896637U);
opack_icmp.icmp_data[i] = rnd>>24;
}
@ -1856,7 +1888,7 @@ usage(void)
#endif /*IPSEC*/
(void)fprintf(stderr, "usage: \n"
"%s [-adDfLnoPqQrRv] [-c count] [-g gateway] [-h host]"
"%s [-aCdDfLnoPqQrRv] [-c count] [-g gateway] [-h host]"
" [-i interval] [-I addr]\n"
" [-l preload] [-p pattern] [-s size] [-t tos] [-T ttl]"
" [-w maxwait] " IPSECOPT "host\n",