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: