Update from Vernon Schryver, fixing the kluge to flush the route cache.

This commit is contained in:
christos 1997-06-01 19:34:46 +00:00
parent 079405ea2a
commit 01bf6a0596
2 changed files with 347 additions and 351 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ping.8,v 1.14 1997/04/10 06:16:06 mikel Exp $ .\" $NetBSD: ping.8,v 1.15 1997/06/01 19:34:46 christos Exp $
.\" .\"
.\" Copyright (c) 1985, 1991, 1993 .\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved. .\" The Regents of the University of California. All rights reserved.
@ -46,15 +46,14 @@ packets to network hosts
.Op Fl dfnoqrvDPQRL .Op Fl dfnoqrvDPQRL
.Op Fl c Ar count .Op Fl c Ar count
.Op Fl g Ar gateway .Op Fl g Ar gateway
.Op Fl i Ar wait .Op Fl i Ar interval
.Op Fl I Ar ifaddr
.Op Fl l Ar preload .Op Fl l Ar preload
.Op Fl p Ar pattern .Op Fl p Ar pattern
.Op Fl s Ar packetsize .Op Fl s Ar packetsize
.Op Fl t Ar ttl .Op Fl t Ar tos
.Op Fl T Ar ttl
.Op Fl w Ar maxwait .Op Fl w Ar maxwait
.Op Fl I Ar ifaddr
.Op Fl S Ar ifaddr
.Op Fl T Ar tos
.Ar host .Ar host
.Sh DESCRIPTION .Sh DESCRIPTION
.Nm Ping .Nm Ping
@ -87,7 +86,8 @@ option on the socket being used.
.It Fl D .It Fl D
Set the Set the
.Dv Don't Fragment .Dv Don't Fragment
bit. bit in the IP header.
This can be used to determine the path MTU.
.It Fl f .It Fl f
Flood ping. Flood ping.
Outputs packets as fast as they come back or one hundred times per second, Outputs packets as fast as they come back or one hundred times per second,
@ -102,9 +102,13 @@ Only the super-user may use this option.
.Bf -emphasis .Bf -emphasis
This can be very hard on a network and should be used with caution. This can be very hard on a network and should be used with caution.
.Ef .Ef
.It Fl i Ar wait .It Fl g Ar gateway
Use Lose Source Routing to send the ECHO_REQUEST packets via
.Ar gateway .
.TP
.It Fl i Ar internal
Wait Wait
.Ar wait .Ar internal
seconds seconds
.Em between sending each packet . .Em between sending each packet .
The default is to wait for one second between each packet, The default is to wait for one second between each packet,
@ -112,6 +116,9 @@ except when the -f option is used the wait interval is 0.01 seconds.
.It Fl I Ar ifaddr .It Fl I Ar ifaddr
Send multicast datagrams on the network interface specified by the Send multicast datagrams on the network interface specified by the
interface's hostname or IP address. interface's hostname or IP address.
.It Fl h Ar host
is an alternate way of specifying the target host instead of as the
last argument.
.It Fl l Ar preload .It Fl l Ar preload
If If
.Ar preload .Ar preload
@ -119,9 +126,12 @@ is specified,
.Nm ping .Nm ping
sends that many packets as fast as possible before falling into its normal sends that many packets as fast as possible before falling into its normal
mode of behavior. mode of behavior.
.It Fl L
Disable loopback when sending to multicast destinations,
so the transmitting host doesn't see the ICMP requests.
.It Fl n .It Fl n
Numeric output only. Numeric output only.
No attempt will be made to lookup symbolic names for host addresses. No attempt will be made to look up symbolic names for host addresses.
.It Fl o .It Fl o
Exit successfully after receiving one reply packet. Exit successfully after receiving one reply packet.
.It Fl p Ar pattern .It Fl p Ar pattern
@ -131,10 +141,17 @@ For example,
.Dq Li \-p ff .Dq Li \-p ff
will cause the sent packet to be filled with all will cause the sent packet to be filled with all
ones. ones.
.It Fl P
Use a psuedo-random sequence for the data instead of the default,
fixed sequence of incrementing 8-bit integers.
This is useful to foil compression on PPP and other links.
.It Fl q .It Fl q
Quiet output. Quiet output.
Nothing is displayed except the summary lines at startup time and Nothing is displayed except the summary lines at startup time and
when finished. when finished.
.It Fl Q
Do not display responses such as Network Unreachable ICMP messages
concerning the ECHO_REQUESTs sent.
.It Fl R .It Fl R
Record route. Record route.
Includes the Includes the
@ -152,9 +169,14 @@ If the host is not on a directly-attached network, an error is returned.
This option can be used to ping a local host through an interface This option can be used to ping a local host through an interface
that has no route through it (e.g., after the interface was dropped by that has no route through it (e.g., after the interface was dropped by
.Xr routed 8 ) . .Xr routed 8 ) .
.It Fl S Ar ifaddr .It Fl R
Specify the interface to transmit from on machines with multiple Record Route. Includes the RECORD_ROUTE option in the ECHO_REQUEST
interfaces. For unicast pings. packet and displays the route buffer on returned packets.
Note that the IP header is only large enough for eight such routes,
and only six when using the
.Fl g
option.
Many hosts ignore or discard this option.
.It Fl s Ar packetsize .It Fl s Ar packetsize
Specifies the number of data bytes to be sent. Specifies the number of data bytes to be sent.
The default is 56, which translates into 64 The default is 56, which translates into 64
@ -163,19 +185,10 @@ data bytes when combined
with the 8 bytes of with the 8 bytes of
.Tn ICMP .Tn ICMP
header data. The maximum allowed value is 65468 bytes. header data. The maximum allowed value is 65468 bytes.
header data. If the .It Fl T Ar ttl
.Fl D
or
.Fl T
options are specified, or the
.Fl t
option to a unicast destination, a raw socket will be used and the 8 bytes of
header data are included in
.Ar packetsize .
.It Fl t Ar ttl
Use the specified time-to-live. Use the specified time-to-live.
.It Fl T Ar tos .It Fl t Ar tos
Use the specified type of service. Use the specified hexadecimal type of service.
.It Fl v .It Fl v
Verbose output. Verbose output.
.Tn ICMP .Tn ICMP
@ -187,18 +200,6 @@ Specifies the number of seconds to wait for a response to a packet
before transmitting the next one. The default is 10. before transmitting the next one. The default is 10.
.El .El
.Pp .Pp
In addition, the following options may be used for multicast pings:
.Bl -tag -width Ds
.It Fl L
Disable the loopback, so the transmitting host doesn't see the ICMP
requests.
.It Fl R
Record Route. Includes the RECORD_ROUTE option in the ECHO_REQUEST
packet and displays the route buffer on returned packets. Note that
the IP header is only large enough for six such routes. Many hosts
ignore or discard this option.
.El
.Pp
When using When using
.Nm ping .Nm ping
for fault isolation, it should first be run on the local host, to verify for fault isolation, it should first be run on the local host, to verify
@ -275,8 +276,8 @@ header).
.Pp .Pp
If the data space is at least eight bytes large, If the data space is at least eight bytes large,
.Nm ping .Nm ping
uses the first eight bytes of this space to include a timestamp which uses the first eight bytes of this space to include a timestamp to compute
it uses in the computation of round trip times. round trip times.
If less than eight bytes of pad are specified, no round trip times are If less than eight bytes of pad are specified, no round trip times are
given. given.
.Sh DUPLICATE AND DAMAGED PACKETS .Sh DUPLICATE AND DAMAGED PACKETS
@ -386,8 +387,8 @@ Others may use completely wild values.
.El .El
.Sh EXIT STATUS .Sh EXIT STATUS
.Nm .Nm
returns 0 on success (the host is alive), and non zero if the arguments are returns 0 on success (the host is alive),
incorrect or the host is not responding. and non-zero if the arguments are incorrect or the host is not responding.
.Sh BUGS .Sh BUGS
Many Hosts and Gateways ignore the Many Hosts and Gateways ignore the
.Tn RECORD_ROUTE .Tn RECORD_ROUTE

View File

@ -1,4 +1,4 @@
/* $NetBSD: ping.c,v 1.29 1997/04/02 09:22:01 augustss Exp $ */ /* $NetBSD: ping.c,v 1.30 1997/06/01 19:34:49 christos Exp $ */
/* /*
* Copyright (c) 1989, 1993 * Copyright (c) 1989, 1993
@ -60,7 +60,7 @@
*/ */
#ifndef lint #ifndef lint
static char rcsid[] = "$NetBSD: ping.c,v 1.29 1997/04/02 09:22:01 augustss Exp $"; static char rcsid[] = "$NetBSD: ping.c,v 1.30 1997/06/01 19:34:49 christos Exp $";
#endif #endif
#include <stdio.h> #include <stdio.h>
@ -75,7 +75,6 @@ static char rcsid[] = "$NetBSD: ping.c,v 1.29 1997/04/02 09:22:01 augustss Exp $
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <limits.h> #include <limits.h>
#include <math.h>
#include <string.h> #include <string.h>
#include <err.h> #include <err.h>
#ifdef sgi #ifdef sgi
@ -107,14 +106,11 @@ static char rcsid[] = "$NetBSD: ping.c,v 1.29 1997/04/02 09:22:01 augustss Exp $
#define F_PING_RANDOM 0x0080 /* use random data */ #define F_PING_RANDOM 0x0080 /* use random data */
#define F_NUMERIC 0x0100 /* do not do gethostbyaddr() calls */ #define F_NUMERIC 0x0100 /* do not do gethostbyaddr() calls */
#define F_TIMING 0x0200 /* room for a timestamp */ #define F_TIMING 0x0200 /* room for a timestamp */
#define F_TTL 0x0400 /* Time to live */ #define F_DF 0x0400 /* set IP DF bit */
#define F_HDRINCL 0x0800 /* Include our ip headers */ #define F_SOURCE_ADDR 0x0800 /* set source IP address/interface */
#define F_SOURCE_ADDR 0x1000 /* Source address */ #define F_ONCE 0x1000 /* exit(0) after receiving 1 reply */
#define F_ONCE 0x2000 /* exit(0) after receiving 1 reply */ #define F_MCAST 0x2000 /* multicast target */
#define F_MCAST_NOLOOP 0x4000 /* no multicast loopback */
#define MULTICAST_NOLOOP 1 /* multicast options */
#define MULTICAST_TTL 2
#define MULTICAST_IF 4
/* MAX_DUP_CHK is the number of bits in received table, the /* MAX_DUP_CHK is the number of bits in received table, the
* maximum number of received sequence numbers we can track to check * maximum number of received sequence numbers we can track to check
@ -133,30 +129,40 @@ int nrepeats = 0;
u_char *packet; u_char *packet;
int packlen; int packlen;
int pingflags = 0, options, moptions; int pingflags = 0, options;
char *fill_pat; char *fill_pat;
int s; /* Socket file descriptor */ int s; /* Socket file descriptor */
#define PHDR_LEN sizeof(struct timeval) /* size of timestamp header */ #define PHDR_LEN sizeof(struct timeval) /* size of timestamp header */
struct sockaddr_in whereto, send_addr; /* Who to ping */ struct sockaddr_in whereto, send_addr; /* Who to ping */
struct sockaddr_in src_addr; /* from where */
struct sockaddr_in loc_addr; /* 127.1 */ struct sockaddr_in loc_addr; /* 127.1 */
int datalen = 64-PHDR_LEN; /* How much data */ int datalen = 64-PHDR_LEN; /* How much data */
#ifdef sgi
static char *__progname;
#else
extern char *__progname; extern char *__progname;
#endif
char hostname[MAXHOSTNAMELEN]; char hostname[MAXHOSTNAMELEN];
static struct { static struct {
struct ip o_ip; struct ip o_ip;
char o_opt[MAX_IPOPTLEN];
union { union {
u_char u_buf[MAXPACKET - sizeof(struct ip)]; u_char u_buf[MAXPACKET];
struct icmp u_icmp; struct icmp u_icmp;
} o_u; } o_u;
} out_pack; } out_pack;
#define opack_icmp out_pack.o_u.u_icmp #define opack_icmp out_pack.o_u.u_icmp
#define opack_ip out_pack.o_ip struct ip *opack_ip;
char optspace[MAX_IPOPTLEN]; /* record route space */
int optlen;
int npackets; /* total packets to send */ int npackets; /* total packets to send */
int preload; /* number of packets to "preload" */ int preload; /* number of packets to "preload" */
@ -177,8 +183,6 @@ int reset_kerninfo;
#endif #endif
int bufspace = 60*1024; int bufspace = 60*1024;
char optspace[MAX_IPOPTLEN]; /* record route space */
int optlen;
struct timeval now, clear_cache, last_tx, next_tx, first_tx; struct timeval now, clear_cache, last_tx, next_tx, first_tx;
struct timeval last_rx, first_rx; struct timeval last_rx, first_rx;
@ -207,32 +211,33 @@ static void pr_iph(struct icmp *, int);
static void pr_retip(struct icmp *, int); static void pr_retip(struct icmp *, int);
static int pr_icmph(struct icmp *, struct sockaddr_in *, int); static int pr_icmph(struct icmp *, struct sockaddr_in *, int);
static void jiggle(int), jiggle_flush(int); static void jiggle(int), jiggle_flush(int);
static void gethost(const char *, struct sockaddr_in *, char *); static void gethost(const char *, const char *,
struct sockaddr_in *, char *, int);
static void usage(void); static void usage(void);
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int c, i, on = 1; int c, i, on = 1, hostind = 0;
struct sockaddr_in ifaddr; long l;
u_char ttl = 0;
u_long tos = 0;
char *p; char *p;
u_char ttl = MAXTTL, loop = 1, df = 0;
int tos = 0;
int mcast;
#ifdef SIGINFO #ifdef SIGINFO
struct termios ts; struct termios ts;
#endif #endif
#ifdef SIGINFO #if defined(SIGINFO) && defined(NOKERNINFO)
if (tcgetattr (0, &ts) != -1) { if (tcgetattr (0, &ts) != -1) {
reset_kerninfo = !(ts.c_lflag & NOKERNINFO); reset_kerninfo = !(ts.c_lflag & NOKERNINFO);
ts.c_lflag |= NOKERNINFO; ts.c_lflag |= NOKERNINFO;
tcsetattr (0, TCSANOW, &ts); tcsetattr (0, TCSANOW, &ts);
} }
#endif #endif
while ((c = getopt(argc, argv, "c:dDfg:h:i:I:l:Lnop:PqRQrs:t:T:vw:")) != -1) { while ((c = getopt(argc, argv,
"c:dDfg:h:i:I:l:Lnop:PqQrRs:t:T:vw:")) != -1) {
switch (c) { switch (c) {
case 'c': case 'c':
npackets = strtol(optarg, &p, 0); npackets = strtol(optarg, &p, 0);
@ -240,8 +245,7 @@ main(int argc, char *argv[])
errx(1, "Bad/invalid number of packets"); errx(1, "Bad/invalid number of packets");
break; break;
case 'D': case 'D':
options |= F_HDRINCL; pingflags |= F_DF;
df = -1;
break; break;
case 'd': case 'd':
options |= SO_DEBUG; options |= SO_DEBUG;
@ -249,15 +253,19 @@ main(int argc, char *argv[])
case 'f': case 'f':
pingflags |= F_FLOOD; pingflags |= F_FLOOD;
break; break;
case 'h':
hostind = optind-1;
break;
case 'i': /* wait between sending packets */ case 'i': /* wait between sending packets */
interval = strtod(optarg, &p); interval = strtod(optarg, &p);
if (*p != '\0' || interval <= 0) if (*p != '\0' || interval <= 0)
errx(1, "Bad/invalid interval"); errx(1, "Bad/invalid interval %s", optarg);
break; break;
case 'l': case 'l':
preload = strtol(optarg, &p, 0); preload = strtol(optarg, &p, 0);
if (*p != '\0' || preload < 0) if (*p != '\0' || preload < 0)
errx(1, "Bad/invalid preload value"); errx(1, "Bad/invalid preload value %s",
optarg);
break; break;
case 'n': case 'n':
pingflags |= F_NUMERIC; pingflags |= F_NUMERIC;
@ -288,7 +296,7 @@ main(int argc, char *argv[])
case 's': /* size of packet to send */ case 's': /* size of packet to send */
datalen = strtol(optarg, &p, 0); datalen = strtol(optarg, &p, 0);
if (*p != '\0' || datalen <= 0) if (*p != '\0' || datalen <= 0)
errx(1, "Bad/invalid packet size"); errx(1, "Bad/invalid packet size %s", optarg);
if (datalen > MAXPACKET) if (datalen > MAXPACKET)
errx(1, "packet size is too large"); errx(1, "packet size is too large");
break; break;
@ -299,34 +307,31 @@ main(int argc, char *argv[])
pingflags |= F_RECORD_ROUTE; pingflags |= F_RECORD_ROUTE;
break; break;
case 'L': case 'L':
moptions |= MULTICAST_NOLOOP; pingflags |= F_MCAST_NOLOOP;
loop = 0;
break; break;
case 't': case 't':
options |= F_TTL; tos = strtoul(optarg, &p, 0);
ttl = strtol(optarg, &p, 0); if (*p != '\0' || tos > 0xFF)
if (*p != '\0' || ttl > 255 || ttl <= 0)
errx(1, "Bad/invalid ttl");
break;
case 'T':
options |= F_HDRINCL;
tos = strtoul(optarg, NULL, 0);
if (tos > 0xFF)
errx(1, "bad tos value: %s", optarg); errx(1, "bad tos value: %s", optarg);
break; break;
case 'T':
l = strtol(optarg, &p, 0);
if (*p != '\0' || l > 255 || l <= 0)
errx(1, "ttl out of range");
ttl = (u_char)l; /* cannot check >255 otherwise */
break;
case 'I': case 'I':
options |= F_SOURCE_ADDR; pingflags |= F_SOURCE_ADDR;
gethost(optarg, &ifaddr, NULL); gethost("-I", optarg, &src_addr, 0, 0);
break; break;
case 'g': case 'g':
pingflags |= F_SOURCE_ROUTE; pingflags |= F_SOURCE_ROUTE;
gethost(optarg, &send_addr, NULL); gethost("-g", optarg, &send_addr, 0, 0);
break; break;
case 'w': case 'w':
maxwait = strtod(optarg, &p); maxwait = strtod(optarg, &p);
if (*p != '\0' || maxwait <= 0) if (*p != '\0' || maxwait <= 0)
errx(1, "Bad/invalid maxwait time"); errx(1, "Bad/invalid maxwait time %s", optarg);
break; break;
default: default:
usage(); usage();
@ -348,33 +353,18 @@ main(int argc, char *argv[])
npackets = INT_MAX; npackets = INT_MAX;
} }
if (optind != argc-1) if (hostind == 0) {
if (optind != argc-1)
usage();
else
hostind = optind;
}
else if (hostind >= argc - 1)
usage(); usage();
gethost(argv[optind], &whereto, hostname); gethost("", argv[hostind], &whereto, hostname, sizeof(hostname));
if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)))
mcast = IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)); pingflags |= F_MCAST;
if (options & F_SOURCE_ADDR) {
if (mcast)
moptions |= MULTICAST_IF;
else {
if (bind(s, (struct sockaddr*) &ifaddr,
sizeof(ifaddr)) == -1)
err(1, "bind failed");
}
}
if (options & F_TTL) {
if (mcast)
moptions |= MULTICAST_TTL;
else
options |= F_HDRINCL;
}
if (options & F_RECORD_ROUTE && options & F_HDRINCL)
errx(1, "-R option and -D or -T, or -t to unicast destinations"
" are incompatible");
if (!(pingflags & F_SOURCE_ROUTE)) if (!(pingflags & F_SOURCE_ROUTE))
(void) memcpy(&send_addr, &whereto, sizeof(send_addr)); (void) memcpy(&send_addr, &whereto, sizeof(send_addr));
@ -398,80 +388,79 @@ main(int argc, char *argv[])
ident = getpid() & 0xFFFF; ident = getpid() & 0xFFFF;
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
err(1, "Cannot create socket"); err(1, "Cannot create socket");
if (options & SO_DEBUG) { if (options & SO_DEBUG) {
if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *) &on, if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *) &on,
sizeof(on)) == -1) sizeof(on)) == -1)
err(1, "Can't turn on socket debugging"); warn("Can't turn on socket debugging");
} }
if (options & SO_DONTROUTE) { if (options & SO_DONTROUTE) {
if (setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *) &on, if (setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *) &on,
sizeof(on)) == -1) sizeof(on)) == -1)
err(1, "Can't turn off socket routing"); warn("SO_DONTROUTE");
} }
if (options & F_HDRINCL) { if (pingflags & F_SOURCE_ROUTE) {
if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *) &on, optspace[IPOPT_OPTVAL] = IPOPT_LSRR;
sizeof(on)) == -1) optspace[IPOPT_OLEN] = optlen = 7;
err(1, "Can't set option to include ip headers"); optspace[IPOPT_OFFSET] = IPOPT_MINOFF;
(void) memcpy(&whereto.sin_addr, &optspace[IPOPT_MINOFF-1],
opack_ip.ip_v = IPVERSION; sizeof(whereto.sin_addr));
opack_ip.ip_hl = sizeof(struct ip) >> 2; optspace[optlen++] = IPOPT_NOP;
opack_ip.ip_tos = tos;
opack_ip.ip_id = 0;
opack_ip.ip_off = (df?IP_DF:0);
opack_ip.ip_ttl = ttl;
opack_ip.ip_p = IPPROTO_ICMP;
opack_ip.ip_src.s_addr = INADDR_ANY;
opack_ip.ip_dst = whereto.sin_addr;
} }
if (pingflags & F_RECORD_ROUTE) {
optspace[optlen+IPOPT_OPTVAL] = IPOPT_RR;
optspace[optlen+IPOPT_OLEN] = (MAX_IPOPTLEN -1-optlen);
optspace[optlen+IPOPT_OFFSET] = IPOPT_MINOFF;
optlen = MAX_IPOPTLEN;
}
/* this leaves opack_ip 0(mod 4) aligned */
opack_ip = (struct ip *)((char *)&out_pack.o_ip
+ sizeof(out_pack.o_opt)
- optlen);
(void) memcpy(opack_ip + 1, optspace, optlen);
/* if (setsockopt(s,IPPROTO_IP,IP_HDRINCL, (char *) &on, sizeof(on)) < 0)
* Loose Source Route and Record and Record Route options err(1, "Can't set special IP header");
*/
if (0 != (pingflags & (F_RECORD_ROUTE | F_SOURCE_ROUTE))) { opack_ip->ip_v = IPVERSION;
if (pingflags & F_SOURCE_ROUTE) { opack_ip->ip_hl = (sizeof(struct ip)+optlen) >> 2;
optlen = 7+4; opack_ip->ip_tos = tos;
optspace[IPOPT_OPTVAL] = IPOPT_LSRR; opack_ip->ip_off = (pingflags & F_DF) ? IP_DF : 0;
optspace[IPOPT_OLEN] = optlen; opack_ip->ip_ttl = ttl ? ttl : MAXTTL;
optspace[IPOPT_OFFSET] = IPOPT_MINOFF; opack_ip->ip_p = IPPROTO_ICMP;
(void) memcpy(&optspace[IPOPT_MINOFF+4-1], opack_ip->ip_src = src_addr.sin_addr;
&whereto.sin_addr, 4); opack_ip->ip_dst = send_addr.sin_addr;
optspace[optlen++] = IPOPT_NOP;
if (pingflags & F_MCAST) {
if (pingflags & F_MCAST_NOLOOP) {
u_char loop = 0;
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP,
(char *) &loop, 1) < 0)
err(1, "Can't disable multicast loopback");
} }
if (pingflags & F_RECORD_ROUTE) {
optspace[optlen+IPOPT_OPTVAL] = IPOPT_RR;
optspace[optlen+IPOPT_OLEN] = (sizeof(optspace)
-1-optlen);
optspace[optlen+IPOPT_OFFSET] = IPOPT_MINOFF;
optlen = sizeof(optspace);
}
if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, optspace,
optlen) == -1)
err(1, "Can't set source/record routing");
}
if (moptions & MULTICAST_NOLOOP) { if (ttl != 0
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, && setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
(char *) &loop, 1) == -1) (char *) &ttl, 1) < 0)
err(1, "Can't disable multicast loopback");
}
if (moptions & MULTICAST_TTL) {
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
(char *) &ttl, 1) == -1)
err(1, "Can't set multicast time-to-live"); err(1, "Can't set multicast time-to-live");
}
if (moptions & MULTICAST_IF) { if ((pingflags & F_SOURCE_ADDR)
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, && setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
(char *) &ifaddr.sin_addr, sizeof(ifaddr.sin_addr)) == -1) (char *) &src_addr.sin_addr,
sizeof(src_addr.sin_addr)) < 0)
err(1, "Can't set multicast source interface"); err(1, "Can't set multicast source interface");
} else if (pingflags & F_SOURCE_ADDR) {
if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
(char *) &src_addr.sin_addr,
sizeof(src_addr.sin_addr)) < 0)
err(1, "Can't set source interface/address");
} }
(void)printf("PING %s (%s): %d data bytes\n", hostname, (void)printf("PING %s (%s): %d data bytes\n", hostname,
inet_ntoa(whereto.sin_addr), inet_ntoa(whereto.sin_addr), datalen);
datalen);
/* When pinging the broadcast address, you can get a lot /* When pinging the broadcast address, you can get a lot
* of answers. Doing something so evil is useful if you * of answers. Doing something so evil is useful if you
@ -484,10 +473,11 @@ main(int argc, char *argv[])
err(1, "Cannot set the receive buffer size"); err(1, "Cannot set the receive buffer size");
} }
/* make it possible to send giant probes */ /* make it possible to send giant probes, but do not worry now
if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char*)&bufspace, * if it fails, since we probably won't send giant probes.
sizeof(bufspace)) == -1) */
err(1, "Cannot set the send buffer size"); (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF,
(char*)&bufspace, sizeof(bufspace));
(void)signal(SIGINT, prefinish); (void)signal(SIGINT, prefinish);
#ifdef SIGINFO #ifdef SIGINFO
@ -499,7 +489,7 @@ main(int argc, char *argv[])
#ifdef sgi #ifdef sgi
/* run with a non-degrading priority to improve the delay values. */ /* run with a non-degrading priority to improve the delay values. */
(void)schedctl(NDPRI, 0, NDPHIMAX); (void) cap_schedctl(NDPRI, 0, NDPHIMAX);
#endif #endif
/* fire off them quickies */ /* fire off them quickies */
@ -519,50 +509,50 @@ doit(void)
int cc; int cc;
struct sockaddr_in from; struct sockaddr_in from;
int fromlen; int fromlen;
double sec; double sec, last, d_last;
struct timeval timeout; struct timeval timeout;
fd_set fdmask; fd_set fdmask;
double last = 0;
(void)gettimeofday(&clear_cache, 0); (void)gettimeofday(&clear_cache,0);
if (maxwait != 0) {
last = timeval_to_sec(&clear_cache) + maxwait;
d_last = 0;
} else {
last = 0;
d_last = 365*24*60*60;
}
FD_ZERO(&fdmask); FD_ZERO(&fdmask);
for (;;) { do {
(void)gettimeofday(&now, 0); (void)gettimeofday(&now,0);
if (maxwait != 0) { if (last != 0)
if (last == 0) d_last = last - timeval_to_sec(&now);
last = timeval_to_sec(&now) + maxwait;
else if (last <= timeval_to_sec(&now))
finish(0);
}
if (ntransmitted < npackets) { if (ntransmitted < npackets && d_last > 0) {
/* send if within 100 usec or late for next packet */ /* send if within 100 usec or late for next packet */
sec = diffsec(&next_tx, &now); sec = diffsec(&next_tx,&now);
if (sec <= 0.0001 if (sec <= 0.0001
|| (lastrcvd && (pingflags & F_FLOOD))) { || (lastrcvd && (pingflags & F_FLOOD))) {
pinger(); pinger();
sec = diffsec(&next_tx, &now); sec = diffsec(&next_tx,&now);
} }
if (sec < 0.0) if (sec < 0.0)
sec = 0.0; sec = 0.0;
if (d_last < sec)
sec = d_last;
} else { } else {
/* For the last response, wait twice as long as the /* For the last response, wait twice as long as the
* worst case seen, or 10 times as long as the * worst case seen, or 10 times as long as the
* maximum interpacket interval, whichever is longer. * maximum interpacket interval, whichever is longer.
*/ */
if (2 * tmax > 10 * interval) sec = MAX(2*tmax,10*interval) - diffsec(&now,&last_tx);
sec = 2 * tmax; if (d_last < sec)
else sec = d_last;
sec = 10 * interval;
sec -= diffsec(&now, &last_tx);
if (sec <= 0) if (sec <= 0)
finish(0); break;
} }
@ -575,7 +565,7 @@ doit(void)
if (errno == EINTR) if (errno == EINTR)
continue; continue;
jiggle_flush(1); jiggle_flush(1);
err(1, "select failed"); err(1, "select");
} }
continue; continue;
} }
@ -587,19 +577,18 @@ doit(void)
if (cc < 0) { if (cc < 0) {
if (errno != EINTR) { if (errno != EINTR) {
jiggle_flush(1); jiggle_flush(1);
warn("recvfrom failed"); warn("recvfrom");
(void)fflush(stderr); (void)fflush(stderr);
} }
continue; continue;
} }
(void)gettimeofday(&now, 0); (void)gettimeofday(&now, 0);
pr_pack(packet, cc, &from); pr_pack(packet, cc, &from);
if (nreceived >= npackets)
finish(0); } while (nreceived < npackets
if (nreceived > 0 && (pingflags & F_ONCE)) && (nreceived == 0 || !(pingflags & F_ONCE)));
finish(0);
} finish(0);
/*NOTREACHED*/
} }
@ -672,64 +661,57 @@ jiggle(int delta)
static void static void
pinger(void) pinger(void)
{ {
int i, cc; int i, cc, sw;
void *packet = &opack_icmp;
opack_icmp.icmp_code = 0; opack_icmp.icmp_code = 0;
opack_icmp.icmp_seq = htons((u_short)(ntransmitted)); opack_icmp.icmp_seq = htons((u_short)(ntransmitted));
/* clear the cached route in the kernel after an ICMP
* response such as a Redirect is seen to stop causing
* more such packets. Also clear the cached route
* periodically in case of routing changes that make
* black holes come and go.
*/
if (clear_cache.tv_sec != now.tv_sec) { if (clear_cache.tv_sec != now.tv_sec) {
/* clear the cached route in the kernel after an ICMP
* response such as a Redirect is seen to stop causing
* more such packets. Also clear the cached route
* periodically in case of routing changes that make
* black holes come and go.
*/
opack_icmp.icmp_type = ICMP_ECHOREPLY; opack_icmp.icmp_type = ICMP_ECHOREPLY;
opack_icmp.icmp_id = ~ident; opack_icmp.icmp_id = ~ident;
opack_icmp.icmp_cksum = 0; opack_icmp.icmp_cksum = 0;
opack_icmp.icmp_cksum = in_cksum((u_short*)&opack_icmp, opack_icmp.icmp_cksum = in_cksum((u_short*)&opack_icmp,
PHDR_LEN); PHDR_LEN);
if (optlen != 0 && sw = 0;
setsockopt(s, IPPROTO_IP, IP_OPTIONS, optspace, 0) == -1) if (setsockopt(s,IPPROTO_IP,IP_HDRINCL,
err(1, "Record/Source Route"); (char *)&sw,sizeof(sw)) < 0)
if (options & F_HDRINCL) { err(1, "Can't turn off special IP header");
packet = &opack_ip; if (sendto(s, (char *) &opack_icmp, PHDR_LEN, MSG_DONTROUTE,
cc = sizeof(struct ip) + PHDR_LEN; (struct sockaddr *)&loc_addr,
opack_ip.ip_len = cc; sizeof(struct sockaddr_in)) < 0)
opack_ip.ip_sum = in_cksum((u_short *)&opack_ip, cc); err(1, "failed to clear cached route");
} sw = 1;
else if (setsockopt(s,IPPROTO_IP,IP_HDRINCL,
cc = PHDR_LEN; (char *)&sw, sizeof(sw)) < 0)
(void) sendto(s, packet, cc, MSG_DONTROUTE, err(1, "Can't set special IP header");
(struct sockaddr *)&loc_addr, sizeof(struct sockaddr_in));
if (optlen != 0 && setsockopt(s, IPPROTO_IP, IP_OPTIONS, (void)gettimeofday(&clear_cache,0);
optspace, optlen) == -1)
err(1, "Record/Source Route");
} }
opack_icmp.icmp_type = ICMP_ECHO; opack_icmp.icmp_type = ICMP_ECHO;
opack_icmp.icmp_id = ident; opack_icmp.icmp_id = ident;
if (pingflags & F_TIMING) if (pingflags & F_TIMING)
(void) memcpy(opack_icmp.icmp_data, &now, sizeof(now)); (void) memcpy(&opack_icmp.icmp_data[0], &now, sizeof(now));
cc = datalen+PHDR_LEN; cc = datalen+PHDR_LEN;
opack_icmp.icmp_cksum = 0; opack_icmp.icmp_cksum = 0;
opack_icmp.icmp_cksum = in_cksum((u_short*)&opack_icmp, cc); opack_icmp.icmp_cksum = in_cksum((u_short*)&opack_icmp, cc);
if (options & F_HDRINCL) { cc += opack_ip->ip_hl<<2;
packet = &opack_ip; opack_ip->ip_len = cc;
cc += sizeof(struct ip); i = sendto(s, (char *) opack_ip, cc, 0,
opack_ip.ip_len = cc; (struct sockaddr *)&send_addr, sizeof(struct sockaddr_in));
opack_ip.ip_sum = in_cksum((u_short *)&opack_ip, cc);
}
i = sendto(s, packet, cc, 0, (struct sockaddr *)&send_addr,
sizeof(struct sockaddr_in));
if (i != cc) { if (i != cc) {
jiggle_flush(1); jiggle_flush(1);
if (i < 0) if (i < 0)
warn("sendto failed"); warn("sendto");
else else
(void) fprintf(stderr, warnx("wrote %s %d chars, ret=%d", hostname, cc, i);
"%s: wrote %s %d chars, ret=%d\n", __progname,
hostname, cc, i);
(void)fflush(stderr); (void)fflush(stderr);
} }
lastrcvd = 0; lastrcvd = 0;
@ -779,11 +761,11 @@ pr_pack_sub(int cc,
return; return;
(void)printf("%d bytes from %s: icmp_seq=%u", cc, addr, seqno); (void)printf("%d bytes from %s: icmp_seq=%u", cc, addr, seqno);
if (dupflag)
(void)printf(" DUP!");
(void)printf(" ttl=%d", ttl); (void)printf(" ttl=%d", ttl);
if (pingflags & F_TIMING) if (pingflags & F_TIMING)
(void)printf(" time=%.3f ms", triptime*1000.0); (void)printf(" time=%.3f ms", triptime*1000.0);
if (dupflag)
(void)printf(" (DUP!)");
} }
@ -808,8 +790,8 @@ pr_pack(u_char *buf,
double triptime = 0.0; double triptime = 0.0;
#define PR_PACK_SUB() {if (!dumped) { \ #define PR_PACK_SUB() {if (!dumped) { \
dumped = 1; \ dumped = 1; \
pr_pack_sub(cc, inet_ntoa(from->sin_addr), \ pr_pack_sub(cc, inet_ntoa(from->sin_addr), \
ntohs((u_short)icp->icmp_seq), \ ntohs((u_short)icp->icmp_seq), \
dupflag, ip->ip_ttl, triptime);}} dupflag, ip->ip_ttl, triptime);}}
/* Check the IP header */ /* Check the IP header */
@ -841,7 +823,6 @@ pr_pack(u_char *buf,
struct timeval tv; struct timeval tv;
(void) memcpy(&tv, icp->icmp_data, sizeof(tv)); (void) memcpy(&tv, icp->icmp_data, sizeof(tv));
triptime = diffsec(&last_rx, &tv); triptime = diffsec(&last_rx, &tv);
tsum += triptime; tsum += triptime;
if (triptime < tmin) if (triptime < tmin)
tmin = triptime; tmin = triptime;
@ -852,8 +833,9 @@ pr_pack(u_char *buf,
if (TST(ntohs((u_short)icp->icmp_seq))) { if (TST(ntohs((u_short)icp->icmp_seq))) {
nrepeats++, nreceived--; nrepeats++, nreceived--;
dupflag=1; dupflag=1;
} else } else {
SET(ntohs((u_short)icp->icmp_seq)); SET(ntohs((u_short)icp->icmp_seq));
}
if (pingflags & F_QUIET) if (pingflags & F_QUIET)
return; return;
@ -864,7 +846,7 @@ pr_pack(u_char *buf,
/* check the data */ /* check the data */
if (datalen > PHDR_LEN if (datalen > PHDR_LEN
&& !(pingflags & F_PING_RANDOM) && !(pingflags & F_PING_RANDOM)
&& bcmp(&icp->icmp_data[PHDR_LEN], && memcmp(&icp->icmp_data[PHDR_LEN],
&opack_icmp.icmp_data[PHDR_LEN], &opack_icmp.icmp_data[PHDR_LEN],
datalen-PHDR_LEN)) { datalen-PHDR_LEN)) {
for (i=PHDR_LEN; i<datalen; i++) { for (i=PHDR_LEN; i<datalen; i++) {
@ -880,7 +862,7 @@ pr_pack(u_char *buf,
for (i=PHDR_LEN; i<datalen; i++) { for (i=PHDR_LEN; i<datalen; i++) {
if ((i%16) == PHDR_LEN) if ((i%16) == PHDR_LEN)
(void)printf("\n\t"); (void)printf("\n\t");
(void)printf("%2x ", (u_char)icp->icmp_data[i]); (void)printf("%2x ",(u_char)icp->icmp_data[i]);
} }
} }
@ -933,7 +915,7 @@ pr_pack(u_char *buf,
continue; continue;
if (dumped <= 1) { if (dumped <= 1) {
if (i == old_rrlen if (i == old_rrlen
&& !bcmp(cp, old_rr, i)) { && !memcmp(cp, old_rr, i)) {
if (dumped) if (dumped)
(void)printf("\t(same route)"); (void)printf("\t(same route)");
j = ((i+3)/4)*4; j = ((i+3)/4)*4;
@ -942,7 +924,7 @@ pr_pack(u_char *buf,
break; break;
} }
old_rrlen = i; old_rrlen = i;
bcopy(cp, old_rr, i); (void) memcpy(old_rr, cp, i);
} }
if (!dumped) { if (!dumped) {
jiggle_flush(1); jiggle_flush(1);
@ -1059,7 +1041,7 @@ timevaladd(struct timeval *t1,
static void static void
sec_to_timeval(const double sec, struct timeval *tp) sec_to_timeval(const double sec, struct timeval *tp)
{ {
tp->tv_sec = (long) sec; tp->tv_sec = sec;
tp->tv_usec = (sec - tp->tv_sec) * 1000000.0; tp->tv_usec = (sec - tp->tv_sec) * 1000000.0;
} }
@ -1157,7 +1139,7 @@ prefinish(int s)
static void static void
finish(int s) finish(int s)
{ {
#ifdef SIGINFO #if defined(SIGINFO) && defined(NOKERNINFO)
struct termios ts; struct termios ts;
if (reset_kerninfo && tcgetattr (0, &ts) != -1) { if (reset_kerninfo && tcgetattr (0, &ts) != -1) {
@ -1170,7 +1152,7 @@ finish(int s)
#endif #endif
summary(1); summary(1);
exit(nreceived > 0 ? 0 : 1); exit(nreceived > 0 ? 0 : 2);
} }
@ -1439,7 +1421,7 @@ pr_iph(struct icmp *icp,
(void) memcpy(&ip, icp->icmp_data, sizeof(ip)); (void) memcpy(&ip, icp->icmp_data, sizeof(ip));
hlen = ip.ip_hl << 2; hlen = ip.ip_hl << 2;
cp = &icp->icmp_data[20]; /* point to options */ cp = (u_char *) &icp->icmp_data[20]; /* point to options */
(void)printf("\n Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n"); (void)printf("\n Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n");
(void)printf(" %1x %1x %02x %04x %04x", (void)printf(" %1x %1x %02x %04x %04x",
@ -1504,7 +1486,7 @@ pr_retip(struct icmp *icp,
int cc) int cc)
{ {
int hlen; int hlen;
unsigned char *cp; u_char *cp;
struct ip ip; struct ip ip;
(void) memcpy(&ip, icp->icmp_data, sizeof(ip)); (void) memcpy(&ip, icp->icmp_data, sizeof(ip));
@ -1513,7 +1495,7 @@ pr_retip(struct icmp *icp,
pr_iph(icp, cc); pr_iph(icp, cc);
hlen = ip.ip_hl << 2; hlen = ip.ip_hl << 2;
cp = &icp->icmp_data[hlen]; cp = (u_char *) &icp->icmp_data[hlen];
if (ip.ip_p == IPPROTO_TCP) { if (ip.ip_p == IPPROTO_TCP) {
if (pingflags & F_VERBOSE) if (pingflags & F_VERBOSE)
@ -1551,9 +1533,9 @@ fill(void)
} }
if (cp == fill_pat || *cp != '\0' || (cp-fill_pat) > 16*2) { if (cp == fill_pat || *cp != '\0' || (cp-fill_pat) > 16*2) {
(void)fflush(stdout); (void)fflush(stdout);
errx(1, errx(1, "\"-p %s\": patterns must be specified with"
"\"-p %s\": patterns must be specified with 1-32 hex digits\n", " 1-32 hex digits\n",
fill_pat); fill_pat);
} }
i = sscanf(fill_pat, i = sscanf(fill_pat,
@ -1593,46 +1575,59 @@ rnd_fill(void)
} }
static void static void
gethost(const char *name, struct sockaddr_in *sa, char *realname) gethost(const char *arg,
const char *name,
struct sockaddr_in *sa,
char *realname,
int realname_len)
{ {
struct hostent *hp; struct hostent *hp;
(void) memset(sa, 0, sizeof(*sa)); bzero(sa, sizeof(*sa));
sa->sin_family = AF_INET; sa->sin_family = AF_INET;
if (inet_aton(name, &sa->sin_addr) != 0) { /* If it is an IP address, try to convert it to a name to
if (realname == NULL) * have something nice to display.
*/
if (inet_aton(name, &sa->sin_addr) != 0) {
if (realname) {
if (pingflags & F_NUMERIC)
hp = 0;
else
hp = gethostbyaddr((char *)&sa->sin_addr,
sizeof(sa->sin_addr),
AF_INET);
(void)strncpy(realname, hp ? hp->h_name : name,
realname_len);
realname[realname_len-1] = '\0';
}
return; return;
if ((pingflags & F_NUMERIC) }
|| !(hp = gethostbyaddr((char *) &sa->sin_addr,
sizeof(sa->sin_addr), AF_INET)))
(void) strncpy(realname, name, MAXHOSTNAMELEN);
else
(void) strncpy(realname, hp->h_name, MAXHOSTNAMELEN);
realname[MAXHOSTNAMELEN-1] = '\0';
return;
}
hp = gethostbyname(name); hp = gethostbyname(name);
if (hp) { if (!hp)
if (hp->h_addrtype != AF_INET) errx(1, "Cannot resolve \"%s\" (%s)",name,hstrerror(h_errno));
errx(1, "`%s' only supported with IP", name);
(void) memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr)); if (hp->h_addrtype != AF_INET)
if (realname == NULL) errx(1, "%s only supported with IP", arg);
return;
(void) strncpy(realname, hp->h_name, MAXHOSTNAMELEN); bcopy(hp->h_addr, &sa->sin_addr, sizeof(sa->sin_addr));
realname[MAXHOSTNAMELEN-1] = '\0';
} else if (realname) {
errx(1, "Cannot resolve host `%s' (%s)", name, (void)strncpy(realname, hp->h_name, realname_len);
hstrerror(h_errno)); realname[realname_len-1] = '\0';
}
} }
static void static void
usage(void) usage(void)
{ {
(void) fprintf(stderr, "Usage: %s %s\n%s\n", __progname, (void)fprintf(stderr, "Usage: \n"
"[-dfnoqrvRLP] [-c count] [-s size] [-l preload] [-p pattern]", "%s [-dDfnqrvRLP] [-c count] [-s size] [-l preload]"
"[-i interval] [-T ttl] [-I addr] [-g gateway] [-w maxwait] host"); " [-p pattern]\n"
" [-i interval] [-i maxwait] [-t tos] [-T ttl]"
" [-I addr] [-g gateway] host\n",
__progname);
exit(1); exit(1);
} }