From darrenr@FreeBSD.org  Sat Jul 14 09:26:31 2012
Return-Path: <darrenr@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id 8EF1E106564A
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 14 Jul 2012 09:26:31 +0000 (UTC)
	(envelope-from darrenr@FreeBSD.org)
Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28])
	by mx1.freebsd.org (Postfix) with ESMTP id 3E9988FC0C
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 14 Jul 2012 09:26:31 +0000 (UTC)
Received: from freefall.freebsd.org (localhost [127.0.0.1])
	by freefall.freebsd.org (8.14.5/8.14.5) with ESMTP id q6E9QV41065503
	for <FreeBSD-gnats-submit@freebsd.org>; Sat, 14 Jul 2012 09:26:31 GMT
	(envelope-from darrenr@freefall.freebsd.org)
Received: (from darrenr@localhost)
	by freefall.freebsd.org (8.14.5/8.14.5/Submit) id q6E9QVAn065502;
	Sat, 14 Jul 2012 09:26:31 GMT
	(envelope-from darrenr)
Message-Id: <201207140926.q6E9QVAn065502@freefall.freebsd.org>
Date: Sat, 14 Jul 2012 09:26:31 GMT
From: Darren Reed <darrenr@FreeBSD.org>
Reply-To: Darren Reed <darrenr@FreeBSD.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: rsh/rlogin do not use the correct IP address
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         169849
>Category:       kern
>Synopsis:       [libc] [patch] rsh/rlogin do not use the correct IP address
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Jul 14 09:30:03 UTC 2012
>Closed-Date:    
>Last-Modified:  Sun Jul 15 02:50:43 UTC 2012
>Originator:     Darren Reed
>Release:        FreeBSD 9.0-STABLE i386
>Organization:
FreeBSD
>Environment:
System: FreeBSD freefall.freebsd.org 9.0-STABLE FreeBSD 9.0-STABLE #6 r235139: Tue May 8 21:19:03 UTC 2012 simon@freefall.freebsd.org:/usr/obj/usr/src/sys/FREEFALL i386


	
>Description:
The BSD r-commands, rsh, rlogin ,etc, do not use the same IP address
for the outgoing connection for stderr as the local server when running
ona a host with address aliases.

To explain this with an example...
Server A has IP addresses 1.2.3.4 and 1.3.4.5
Client B does "rsh 1.3.4.5 who"
Server A accepts the connection on port 514 for 1.3.4.5 and initiates a
connection back to Client B using IP address 1.2.3.4.

The outgoing connection should use the same IP address as was made for
the incoming TCP connection.
>How-To-Repeat:

use rsh from a client to a freebsd server with multiple addresses and
connect to an alias, noticing that the return connection does not
originate from the same source as the destination of the client.
>Fix:

--- usr/src/lib/libc/net/rcmd.c.DIST	2012-07-14 19:44:54.000000000 +1000
+++ usr/src/lib/libc/net/rcmd.c	2012-07-14 19:42:47.000000000 +1000
@@ -330,6 +330,14 @@
 rresvport_af(alport, family)
 	int *alport, family;
 {
+	return rresvport_af_addr(alport, family, NULL);
+}
+
+int
+rresvport_af_addr(alport, family, addr)
+	int *alport, family;
+	void *addr;
+{
 	int s;
 	struct sockaddr_storage ss;
 	u_short *sport;
@@ -340,13 +348,19 @@
 	case AF_INET:
 		((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in);
 		sport = &((struct sockaddr_in *)&ss)->sin_port;
-		((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
+		if (addr != NULL)
+			((struct sockaddr_in *)&ss)->sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
+		else
+			((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
 		break;
 #ifdef INET6
 	case AF_INET6:
 		((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6);
 		sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
-		((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
+		if (addr != NULL)
+			((struct sockaddr_in6 *)&ss)->sin6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr;
+		else
+			((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
 		break;
 #endif
 	default:
--- usr/src/include/unistd.h.DIST	2012-01-03 14:23:59.000000000 +1100
+++ usr/src/include/unistd.h	2012-07-14 19:42:25.000000000 +1000
@@ -546,6 +546,7 @@
 pid_t	 rfork_thread(int, void *, int (*)(void *), void *);
 int	 rresvport(int *);
 int	 rresvport_af(int *, int);
+int	 rresvport_af_addr(int *, int, void *);
 int	 ruserok(const char *, int, const char *, const char *);
 #if __BSD_VISIBLE
 #ifndef _SELECT_DECLARED
--- usr/src/lib/libc/net/Symbol.map.DIST	2012-01-03 14:26:01.000000000 +1100
+++ usr/src/lib/libc/net/Symbol.map	2012-07-14 20:15:17.000000000 +1000
@@ -99,6 +99,7 @@
 	rcmd_af;
 	rresvport;
 	rresvport_af;
+	rresvport_af_addr;
 	ruserok;
 	iruserok;
 	iruserok_sa;
--- usr/src/libexec/rshd/rshd.c.DIST	2012-01-03 14:26:11.000000000 +1100
+++ usr/src/libexec/rshd/rshd.c	2012-07-14 20:22:58.000000000 +1000
@@ -110,7 +110,7 @@
 int	sent_null;
 int	no_delay;
 
-void	 doit(struct sockaddr *);
+void	 doit(struct sockaddr *, struct sockaddr *);
 static void	 rshd_errx(int, const char *, ...) __printf0like(2, 3);
 void	 getstr(char *, int, const char *);
 int	 local_domain(char *);
@@ -128,8 +128,10 @@
 	extern int __check_rhosts_file;
 	struct linger linger;
 	socklen_t fromlen;
+	socklen_t locallen;
 	int ch, on = 1;
 	struct sockaddr_storage from;
+	struct sockaddr_storage local;
 
 	openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
 
@@ -165,6 +167,10 @@
 		syslog(LOG_ERR, "getpeername: %m");
 		exit(1);
 	}
+	if (getsockname(0, (struct sockaddr *)&local, &locallen) < 0) {
+		syslog(LOG_ERR, "getsockname: %m");
+		exit(1);
+	}
 	if (keepalive &&
 	    setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
 	    sizeof(on)) < 0)
@@ -177,7 +183,7 @@
 	if (no_delay &&
 	    setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0)
 		syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m");
-	doit((struct sockaddr *)&from);
+	doit((struct sockaddr *)&from, (struct sockaddr *)&local);
 	/* NOTREACHED */
 	return(0);
 }
@@ -185,7 +191,7 @@
 extern char **environ;
 
 void
-doit(struct sockaddr *fromp)
+doit(struct sockaddr *fromp, struct sockaddr *localp)
 {
 	extern char *__rcmd_errstr;	/* syslog hook from libc/net/rcmd.c. */
 	struct passwd *pwd;
@@ -278,7 +284,7 @@
 	(void) alarm(0);
 	if (port != 0) {
 		int lport = IPPORT_RESERVED - 1;
-		s = rresvport_af(&lport, af);
+		s = rresvport_af_addr(&lport, af, localp);
 		if (s < 0) {
 			syslog(LOG_ERR, "can't get stderr port: %m");
 			exit(1);


>Release-Note:
>Audit-Trail:
>Unformatted:
