Subject: bin/2017: ping should support more options
To: None <gnats-bugs@NetBSD.ORG>
From: John Hawkinson <jhawk@mit.edu>
List: netbsd-bugs
Date: 02/04/1996 00:44:14
>Number: 2017
>Category: bin
>Synopsis: ping should support more options
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: bin-bug-people (Utility Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Sun Feb 4 01:20:09 1996
>Last-Modified:
>Originator: John Hawkinson
>Organization:
MIT SIPB
>Release: 1.1
>Environment:
System: NetBSD lola-granola 1.1A NetBSD 1.1A (LOLA) #143: Sat Jan 13 01:51:04 EST 1996 mycroft@lola-granola:/afs/sipb.mit.edu/project/netbsd/dev/current-source/build/i386_nbsd1/sys/arch/i386/compile/LOLA i386
>Description:
It would be nice if ping supported some more options, such as
setting the TOS, the DF bit, and the TTL on unicast packets.
Here are some patches to support this. They do require the use
of IP_HDRINCL, so -R will not work with them.
I've also replaced many instances of atoi(foo) with
strtol(foo, NULL, 0), so that "0x1234" works in addition
to "4660".
>How-To-Repeat:
N/A
>Fix:
===================================================================
RCS file: RCS/ping.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -c -r1.1 -r1.2
*** ping.c 1996/01/18 05:41:07 1.1
--- ping.c 1996/02/04 05:22:11 1.2
***************
*** 115,120 ****
--- 115,122 ----
#define F_SO_DONTROUTE 0x080
#define F_VERBOSE 0x100
#define F_SADDR 0x200
+ #define F_HDRINCL 0x400
+ #define F_TTL 0x800
/* multicast options */
int moptions;
***************
*** 135,141 ****
struct sockaddr_in whence; /* Which interface we come from */
int datalen = DEFDATALEN;
int s; /* socket file descriptor */
! u_char outpack[MAXPACKET];
char BSPACE = '\b'; /* characters written for flood */
char DOT = '.';
char *hostname;
--- 137,144 ----
struct sockaddr_in whence; /* Which interface we come from */
int datalen = DEFDATALEN;
int s; /* socket file descriptor */
! u_char outpackhdr[MAXPACKET];
! u_char *outpack=outpackhdr+sizeof(struct ip);
char BSPACE = '\b'; /* characters written for flood */
char DOT = '.';
char *hostname;
***************
*** 176,201 ****
struct hostent *hp;
struct sockaddr_in *to;
struct protoent *proto;
! struct in_addr ifaddr, saddr;
register int i;
int ch, fdmask, hold, packlen, preload;
u_char *datap, *packet;
char *target, hnamebuf[MAXHOSTNAMELEN];
! u_char ttl, loop = 1;
#ifdef IP_OPTIONS
char rspace[3 + 4 * NROUTES + 1]; /* record route space */
#endif
preload = 0;
datap = &outpack[8 + sizeof(struct timeval)];
! while ((ch = getopt(argc, argv, "I:LRS:c:dfh:i:l:np:qrs:t:vw:")) != EOF)
switch(ch) {
case 'c':
! npackets = atoi(optarg);
if (npackets <= 0)
errx(1, "bad number of packets to transmit: %s",
optarg);
break;
case 'd':
options |= F_SO_DEBUG;
break;
--- 179,209 ----
struct hostent *hp;
struct sockaddr_in *to;
struct protoent *proto;
! struct in_addr saddr;
register int i;
int ch, fdmask, hold, packlen, preload;
u_char *datap, *packet;
char *target, hnamebuf[MAXHOSTNAMELEN];
! u_char ttl = MAXTTL, loop = 1, df = 0;
! int tos = 0;
#ifdef IP_OPTIONS
char rspace[3 + 4 * NROUTES + 1]; /* record route space */
#endif
preload = 0;
datap = &outpack[8 + sizeof(struct timeval)];
! while ((ch = getopt(argc, argv, "DI:LRS:c:dfh:i:l:np:qrs:T:t:vw:")) != EOF)
switch(ch) {
case 'c':
! npackets = strtol(optarg, 0, NULL);
if (npackets <= 0)
errx(1, "bad number of packets to transmit: %s",
optarg);
break;
+ case 'D':
+ options |= F_HDRINCL;
+ df = -1;
+ break;
case 'd':
options |= F_SO_DEBUG;
break;
***************
*** 206,217 ****
setbuf(stdout, (char *)NULL);
break;
case 'I':
! if (inet_aton(optarg, &ifaddr) == 0)
! errx(1, "bad interface address: %s", optarg);
! moptions |= MULTICAST_IF;
break;
case 'i': /* wait between sending packets */
! interval = atoi(optarg);
if (interval <= 0)
errx(1, "bad timing interval: %s", optarg);
options |= F_INTERVAL;
--- 214,230 ----
setbuf(stdout, (char *)NULL);
break;
case 'I':
! case 'S': /* deprecated */
! if (inet_aton(optarg, &saddr) == 0) {
! if ((hp = gethostbyname(optarg)) == NULL)
! errx(1, "bad interface address: %s",
! optarg);
! memcpy(&saddr, hp->h_addr, sizeof(saddr));
! }
! options |= F_SADDR;
break;
case 'i': /* wait between sending packets */
! interval = strtol(optarg, NULL, 0);
if (interval <= 0)
errx(1, "bad timing interval: %s", optarg);
options |= F_INTERVAL;
***************
*** 221,227 ****
loop = 0;
break;
case 'l':
! preload = atoi(optarg);
if (preload < 0)
errx(1, "bad preload value: %s", optarg);
break;
--- 234,240 ----
loop = 0;
break;
case 'l':
! preload = strtol(optarg, NULL, 0);
if (preload < 0)
errx(1, "bad preload value: %s", optarg);
break;
***************
*** 241,275 ****
case 'r':
options |= F_SO_DONTROUTE;
break;
- case 'S':
- if (inet_aton(optarg, &saddr) == 0) {
- if ((hp = gethostbyname(optarg)) == NULL)
- errx(1, "bad interface address: %s",
- optarg);
- memcpy(&saddr, hp->h_addr, sizeof(saddr));
- }
- options |= F_SADDR;
- break;
case 's': /* size of packet to send */
! datalen = atoi(optarg);
if (datalen <= 0)
errx(1, "bad packet size: %s", optarg);
if (datalen > MAXPACKET)
errx(1, "packet size too large: %s", optarg);
break;
case 't':
! ttl = atoi(optarg);
if (ttl <= 0)
errx(1, "bad ttl value: %s", optarg);
if (ttl > 255)
errx(1, "ttl value too large: %s", optarg);
- moptions |= MULTICAST_TTL;
break;
case 'v':
options |= F_VERBOSE;
break;
case 'w':
! maxwait = atoi(optarg);
if (maxwait <= 0)
errx(1, "bad maxwait value: %s", optarg);
break;
--- 254,285 ----
case 'r':
options |= F_SO_DONTROUTE;
break;
case 's': /* size of packet to send */
! datalen = strtol(optarg, NULL, 0);
if (datalen <= 0)
errx(1, "bad packet size: %s", optarg);
if (datalen > MAXPACKET)
errx(1, "packet size too large: %s", optarg);
break;
+ case 'T':
+ options |= F_HDRINCL;
+ tos = strtoul(optarg, NULL, 0);
+ if (tos > 0xFF)
+ errx(1, "bad tos value: %s", optarg);
+ break;
case 't':
! options |= F_TTL;
! ttl = strtol(optarg, NULL, 0);
if (ttl <= 0)
errx(1, "bad ttl value: %s", optarg);
if (ttl > 255)
errx(1, "ttl value too large: %s", optarg);
break;
case 'v':
options |= F_VERBOSE;
break;
case 'w':
! maxwait = strtol(optarg, NULL, 0);
if (maxwait <= 0)
errx(1, "bad maxwait value: %s", optarg);
break;
***************
*** 320,331 ****
--- 330,345 ----
hold = 1;
if (options & F_SADDR) {
+ if (IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
+ moptions |= MULTICAST_IF;
+ else {
memset(&whence, 0, sizeof(whence));
whence.sin_len = sizeof(whence);
whence.sin_family = AF_INET;
memcpy(&whence.sin_addr.s_addr, &saddr, sizeof(saddr));
if (bind(s, (struct sockaddr*)&whence, sizeof(whence)) < 0)
err(1, "bind");
+ }
}
if (options & F_SO_DEBUG)
***************
*** 335,342 ****
--- 349,386 ----
(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
sizeof(hold));
+ if (options & F_TTL) {
+ if (IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
+ moptions |= MULTICAST_TTL;
+ else
+ options |= F_HDRINCL;
+ }
+
+ if (options & F_RROUTE && options & F_HDRINCL)
+ errx(1, "-R option and -D or -T, or -t to unicast destinations"
+ " are incompatible");
+
+
+ if (options & F_HDRINCL) {
+ struct ip *ip = (struct ip*)outpackhdr;
+
+ setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ ip->ip_tos = tos;
+ ip->ip_id = 0;
+ ip->ip_off = (df?IP_DF:0);
+ ip->ip_ttl = ttl;
+ ip->ip_p = proto->p_proto;
+ ip->ip_src.s_addr = INADDR_ANY;
+ ip->ip_dst = to->sin_addr;
+ }
+
+
/* record route option */
if (options & F_RROUTE) {
+ if (IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
+ errx(1, "record route not valid to multicast destinations");
#ifdef IP_OPTIONS
rspace[IPOPT_OPTVAL] = IPOPT_RR;
rspace[IPOPT_OLEN] = sizeof(rspace)-1;
***************
*** 360,367 ****
sizeof(ttl)) < 0)
err(1, "setsockopt IP_MULTICAST_TTL");
if ((moptions & MULTICAST_IF) &&
! setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
! sizeof(ifaddr)) < 0)
err(1, "setsockopt IP_MULTICAST_IF");
/*
--- 404,411 ----
sizeof(ttl)) < 0)
err(1, "setsockopt IP_MULTICAST_TTL");
if ((moptions & MULTICAST_IF) &&
! setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &saddr,
! sizeof(saddr)) < 0)
err(1, "setsockopt IP_MULTICAST_IF");
/*
***************
*** 466,471 ****
--- 510,516 ----
register struct icmp *icp;
register int cc;
int i;
+ char *packet = outpack;
icp = (struct icmp *)outpack;
icp->icmp_type = ICMP_ECHO;
***************
*** 485,492 ****
/* compute ICMP checksum here */
icp->icmp_cksum = in_cksum((u_short *)icp, cc);
! i = sendto(s, (char *)outpack, cc, 0, &whereto,
! sizeof(struct sockaddr));
if (i < 0 || i != cc) {
if (i < 0)
--- 530,547 ----
/* compute ICMP checksum here */
icp->icmp_cksum = in_cksum((u_short *)icp, cc);
! if (options & F_HDRINCL) {
! struct ip *ip = (struct ip*)outpackhdr;
!
! packet = (char*)ip;
! cc+=sizeof(struct ip);
! ip->ip_len=cc;
! ip->ip_sum=in_cksum((u_short *)outpackhdr, cc);
! }
!
! i = sendto(s, (char *)packet, cc, 0, &whereto,
! sizeof(struct sockaddr));
!
if (i < 0 || i != cc) {
if (i < 0)
***************
*** 1027,1032 ****
usage()
{
(void)fprintf(stderr,
! "usage: ping [-dfLnqRrv] [-c count] [-I ifaddr] [ -S ifaddr ] [-i wait]\n\t[-l preload] [-p pattern] [-s packetsize] [-t ttl] [-w maxwait] host\n");
exit(1);
}
--- 1082,1089 ----
usage()
{
(void)fprintf(stderr,
! "usage: ping [-DdfLnqRrv] [-c count] [-I ifaddr] [-i wait]\n"
! "\t[-l preload] [-p pattern] [-s packetsize] [-t ttl]"
! " [-w maxwait] host\n");
exit(1);
}
===================================================================
RCS file: RCS/ping.8,v
retrieving revision 1.2
retrieving revision 1.3
diff -c -r1.2 -r1.3
*** ping.8 1996/01/18 05:55:41 1.2
--- ping.8 1996/02/04 05:25:55 1.3
***************
*** 78,83 ****
--- 78,87 ----
.Ar count
.Tn ECHO_RESPONSE
packets.
+ .It Fl D
+ Set the
+ .Dv Don't Fragment
+ bit.
.It Fl d
Set the
.Dv SO_DEBUG
***************
*** 96,101 ****
--- 100,108 ----
.Bf -emphasis
This can be very hard on a network and should be used with caution.
.Ef
+ .It Fl I Ar ifaddr
+ Specify the interface to transmit from on machines with multiple
+ interfaces. For unicast and multicast pings.
.It Fl i Ar wait
Wait
.Ar wait
***************
*** 143,151 ****
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
.Xr routed 8 ) .
- .It Fl S Ar ifaddr
- Specify the interface to transmit from on machines with multiple
- interfaces. For unicast pings.
.It Fl s Ar packetsize
Specifies the number of data bytes to be sent.
The default is 56, which translates into 64
--- 150,155 ----
***************
*** 153,159 ****
data bytes when combined
with the 8 bytes of
.Tn ICMP
! header data.
.It Fl v
Verbose output.
.Tn ICMP
--- 157,175 ----
data bytes when combined
with the 8 bytes of
.Tn ICMP
! header data. If the
! .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 tos
! Use the specified type of service.
! .It Fl t Ar ttl
! Use the specified time-to-live.
.It Fl v
Verbose output.
.Tn ICMP
***************
*** 165,179 ****
before transmitting the next one. The default is 10.
.El
.Pp
! In addition, the following options may be used for multicast pings:
.Bl -tag -width Ds
- .It Fl I Ar ifaddr
- Transmit using the specified interface address.
.It Fl L
Disable the loopback, so the transmitting host doesn't see the ICMP
requests.
- .It Fl t Ar ttl
- Use the specified time-to-live.
.El
.Pp
When using
--- 181,191 ----
before transmitting the next one. The default is 10.
.El
.Pp
! In addition, the following option 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.
.El
.Pp
When using
>Audit-Trail:
>Unformatted: