Subject: Patch for "traceroute" interface selection problem
To: None <tech-net@netbsd.org>
From: Matthias Scheler <tron@lyssa.owl.de>
List: tech-net
Date: 12/08/1998 21:35:46
	Hi,

here is my cleaned up patch for "traceroute" based on Ken's suggestion
how to find the correct IP address for sending out packets.

With the new patch "traceroute" neither terminates when the UDP method
fails nor breaks compatibility with systems returning "INADDR_ANY" on
"getsockname()".

	Regards

-- 
Matthias Scheler                                http://home.owl.de/~tron/

Index: traceroute.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/traceroute/traceroute.c,v
retrieving revision 1.25
diff -u -r1.25 traceroute.c
--- traceroute.c	1998/08/27 20:31:02	1.25
+++ traceroute.c	1998/12/08 21:29:35
@@ -359,8 +359,8 @@
 __dead	void usage(void);
 int	wait_for_reply(int, struct sockaddr_in *, struct timeval *);
 void	frag_err(void);
+int	find_local_ip(struct sockaddr_in *, struct sockaddr_in *);
 
-
 int
 main(int argc, char **argv)
 {
@@ -729,7 +729,7 @@
 		 * Warn if there are more than one.
 		 */
 		setsin(from, al->addr);
-		if (n > 1 && device == NULL) {
+		if (n > 1 && device == NULL && !find_local_ip(from, to)) {
 			Fprintf(stderr,
 		    "%s: Warning: Multiple interfaces found; using %s @ %s\n",
 			    prog, inet_ntoa(from->sin_addr), al->device);
@@ -1466,3 +1466,37 @@
         }
 }
 
+int
+find_local_ip(struct sockaddr_in *from, struct sockaddr_in *to)
+{
+	int sock;
+	struct sockaddr_in help;
+	int help_len;
+
+	sock = socket(AF_INET, SOCK_DGRAM, 0);
+	if (sock < 0) return (0);
+
+	help.sin_family = AF_INET;
+	/*
+	 * At this point the port number doesn't matter,
+	 * it only has to be greater zero.
+	 */
+	help.sin_port = 42;
+	help.sin_addr.s_addr = to->sin_addr.s_addr;
+	if (connect(sock, (struct sockaddr *)&help, sizeof(help)) < 0) {
+		(void)close(sock);
+		return (0);
+	}
+
+	help_len = sizeof(help);
+	if (getsockname(sock, (struct sockaddr *)&help, &help_len) < 0 ||
+	    help_len != sizeof(help) ||
+	    help.sin_addr.s_addr == INADDR_ANY) {
+		(void)close(sock);
+		return (0);
+	}
+
+	(void)close(sock);
+	setsin(from, help.sin_addr.s_addr);
+	return (1);
+}