Subject: bin/1014: ping should allow specification of source interfaces
To: None <gnats-admin@sun-lamp.cs.berkeley.edu>
From: John Hawkinson <jhawk@MIT.EDU>
List: netbsd-bugs
Date: 05/02/1995 21:05:05
>Number:         1014
>Category:       bin
>Synopsis:       ping should allow specification of source interfaces
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue May  2 21:05:03 1995
>Originator:     John Hawkinson
>Organization:
MIT SIPB
>Release:        Tue May  2 23:53:23 EDT 1995
>Environment:
	
System: NetBSD quiche-lorraine 1.0A NetBSD 1.0A (ATHENA-AHA) #8: Wed Apr 26 20:19:45 EDT 1995 jhawk@lola-granola:/afs/sipb.mit.edu/project/netbsd/dev/current-source/src/sys/arch/i386/compile/ATHENA-AHA i386


>Description:

	ping, unlike traceroute doesn't allow the user to specify
	the source address for unicast pings. For multicast pings,
	the -I option allows it.

	This patch causes ping to bind to the address specified in the
	-S option, in order to mandate a specific source address.

	It would be nice if -I and -S weren't seperate options, but I
	suspect there's not much that can be done about that.

>How-To-Repeat:

	Stare at your machine and wonder why it doesn't work?
	Note that this code is useless under 1.0 due to the rip_output.c
	bug...

>Fix:

*** ping.c.orig	Tue May  2 23:50:58 1995
--- ping.c	Tue May  2 23:51:47 1995
***************
*** 114,119 ****
--- 114,120 ----
  #define	F_SO_DEBUG	0x040
  #define	F_SO_DONTROUTE	0x080
  #define	F_VERBOSE	0x100
+ #define	F_SADDR		0x200
  
  /* multicast options */
  int moptions;
***************
*** 131,136 ****
--- 132,138 ----
  char rcvd_tbl[MAX_DUP_CHK / 8];
  
  struct sockaddr whereto;	/* who to ping */
+ struct sockaddr_in whence;		/* Which interface we come from */
  int datalen = DEFDATALEN;
  int s;				/* socket file descriptor */
  u_char outpack[MAXPACKET];
***************
*** 173,179 ****
  	struct hostent *hp;
  	struct sockaddr_in *to;
  	struct protoent *proto;
! 	struct in_addr ifaddr;
  	register int i;
  	int ch, fdmask, hold, packlen, preload;
  	u_char *datap, *packet;
--- 175,181 ----
  	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;
***************
*** 185,191 ****
  
  	preload = 0;
  	datap = &outpack[8 + sizeof(struct timeval)];
! 	while ((ch = getopt(argc, argv, "I:LRc:dfh:i:l:np:qrs:t:v")) != EOF)
  		switch(ch) {
  		case 'c':
  			npackets = atoi(optarg);
--- 187,193 ----
  
  	preload = 0;
  	datap = &outpack[8 + sizeof(struct timeval)];
! 	while ((ch = getopt(argc, argv, "I:LRS:c:dfh:i:l:np:qrs:t:v")) != EOF)
  		switch(ch) {
  		case 'c':
  			npackets = atoi(optarg);
***************
*** 238,243 ****
--- 240,253 ----
  		case 'r':
  			options |= F_SO_DONTROUTE;
  			break;
+ 		case 'S':
+ 			if (inet_aton(optarg,&saddr)==0) {
+ 			  if ((hp = gethostbyname(optarg))==0)
+ 				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)
***************
*** 300,305 ****
--- 310,326 ----
  	if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0)
  		err(1, "socket");
  	hold = 1;
+ 
+ 	if (options & F_SADDR) {
+ 	  	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)
  		(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
  		    sizeof(hold));
***************
*** 996,1000 ****
  {
  	(void)fprintf(stderr,
  	    "usage: ping [-dfLnqRrv] [-c count] [-I ifaddr] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] [-t ttl] host\n");
! 	exit(1);
  }
--- 1017,1021 ----
  {
  	(void)fprintf(stderr,
  	    "usage: ping [-dfLnqRrv] [-c count] [-I ifaddr] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] [-t ttl] host\n");
! 	    "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");
  }
*** ping.8.orig	Tue May  2 23:50:58 1995
--- ping.8	Tue May  2 23:51:28 1995
***************
*** 49,54 ****
--- 49,55 ----
  .Op Fl i Ar wait
  .Op Fl l Ar preload
  .Op Fl p Ar pattern
+ .Op Fl S Ar ifaddr
  .Op Fl s Ar packetsize
  .Op Fl t Ar ttl
  .Ar host
***************
*** 141,146 ****
--- 142,150 ----
  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

>Audit-Trail:
>Unformatted: