Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 13 Apr 2010 00:48:54 +0000 (UTC)
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r206535 - in stable/8/usr.sbin: . dumpcis makefs makefs/ffs mfiutil rpcbind
Message-ID:  <201004130048.o3D0msej091565@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: imp
Date: Tue Apr 13 00:48:54 2010
New Revision: 206535
URL: http://svn.freebsd.org/changeset/base/206535

Log:
  MFC r203710:
  
    When you have multiple addresses on the same network on different
    interfaces (such as when you are part of a carp pool), and you run
    rpcbind -h to restrict which interfaces have rpc services, rpcbind can
    none-the-less return addresses that aren't in the -h list.  This patch
    enforces the rule that when you specify -h on the command line, then
    services returned from rpcbind must be to one of the addresses listed
    in -h, or be a loopback address (since localhost is implicit when
    running -h).
  
    The root cause of this is the assumption in addrmerge that there can
    be only one interface that matches a given network IP address.  This
    turns out not to be the case.  To retain historical behavior, I didn't
    try to fix the routine to prefer the address that the request came
    into, since I didn't know the side effects that might cause in the
    normal case.  My quick analysis suggests that it wouldn't be a
    problem, but since this code is tricky I opted for the more
    conservative patch of only restricting the reply when -h is in effect.
  
    Hence, this change will have no effect when you are running rpcbind
    without -h.
  
    Reviewed by:	alfred@
    Sponsored by:	iX Systems
    MFC after:	2 weeks

Modified:
  stable/8/usr.sbin/rpcbind/rpcbind.c
  stable/8/usr.sbin/rpcbind/rpcbind.h
  stable/8/usr.sbin/rpcbind/util.c
Directory Properties:
  stable/8/usr.sbin/   (props changed)
  stable/8/usr.sbin/Makefile   (props changed)
  stable/8/usr.sbin/acpi/   (props changed)
  stable/8/usr.sbin/arp/   (props changed)
  stable/8/usr.sbin/bsnmpd/   (props changed)
  stable/8/usr.sbin/burncd/   (props changed)
  stable/8/usr.sbin/cdcontrol/   (props changed)
  stable/8/usr.sbin/chown/   (props changed)
  stable/8/usr.sbin/cpucontrol/   (props changed)
  stable/8/usr.sbin/crashinfo/   (props changed)
  stable/8/usr.sbin/cron/   (props changed)
  stable/8/usr.sbin/crunch/examples/   (props changed)
  stable/8/usr.sbin/cxgbtool/   (props changed)
  stable/8/usr.sbin/diskinfo/   (props changed)
  stable/8/usr.sbin/dumpcis/cardinfo.h   (props changed)
  stable/8/usr.sbin/dumpcis/cis.h   (props changed)
  stable/8/usr.sbin/faithd/   (props changed)
  stable/8/usr.sbin/freebsd-update/   (props changed)
  stable/8/usr.sbin/inetd/   (props changed)
  stable/8/usr.sbin/iostat/   (props changed)
  stable/8/usr.sbin/jail/   (props changed)
  stable/8/usr.sbin/jls/   (props changed)
  stable/8/usr.sbin/lpr/   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_bswap.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ffs_subr.c   (props changed)
  stable/8/usr.sbin/makefs/ffs/ufs_bswap.h   (props changed)
  stable/8/usr.sbin/makefs/getid.c   (props changed)
  stable/8/usr.sbin/mergemaster/   (props changed)
  stable/8/usr.sbin/mfiutil/mfiutil.8   (props changed)
  stable/8/usr.sbin/mptutil/   (props changed)
  stable/8/usr.sbin/ndp/   (props changed)
  stable/8/usr.sbin/newsyslog/   (props changed)
  stable/8/usr.sbin/ntp/   (props changed)
  stable/8/usr.sbin/pmcstat/   (props changed)
  stable/8/usr.sbin/powerd/   (props changed)
  stable/8/usr.sbin/ppp/   (props changed)
  stable/8/usr.sbin/pstat/   (props changed)
  stable/8/usr.sbin/rpc.umntall/   (props changed)
  stable/8/usr.sbin/rtsold/   (props changed)
  stable/8/usr.sbin/service/   (props changed)
  stable/8/usr.sbin/sysinstall/   (props changed)
  stable/8/usr.sbin/syslogd/   (props changed)
  stable/8/usr.sbin/traceroute/   (props changed)
  stable/8/usr.sbin/traceroute6/   (props changed)
  stable/8/usr.sbin/usbconfig/   (props changed)
  stable/8/usr.sbin/vidcontrol/   (props changed)
  stable/8/usr.sbin/wpa/   (props changed)
  stable/8/usr.sbin/ypserv/   (props changed)
  stable/8/usr.sbin/zic/   (props changed)

Modified: stable/8/usr.sbin/rpcbind/rpcbind.c
==============================================================================
--- stable/8/usr.sbin/rpcbind/rpcbind.c	Tue Apr 13 00:33:07 2010	(r206534)
+++ stable/8/usr.sbin/rpcbind/rpcbind.c	Tue Apr 13 00:48:54 2010	(r206535)
@@ -92,6 +92,7 @@ int oldstyle_local = 0;
 int verboselog = 0;
 
 char **hosts = NULL;
+struct sockaddr **bound_sa;
 int ipv6_only = 0;
 int nhosts = 0;
 int on = 1;
@@ -119,6 +120,7 @@ static void rbllist_add(rpcprog_t, rpcve
 			     struct netbuf *);
 static void terminate(int);
 static void parseargs(int, char *[]);
+static void update_bound_sa(void);
 
 int
 main(int argc, char *argv[])
@@ -130,6 +132,8 @@ main(int argc, char *argv[])
 
 	parseargs(argc, argv);
 
+	update_bound_sa();
+
 	/* Check that another rpcbind isn't already running. */
 	if ((rpcbindlockfd = (open(RPCBINDDLOCK,
 	    O_RDONLY|O_CREAT, 0444))) == -1)
@@ -323,8 +327,7 @@ init_transport(struct netconfig *nconf)
 	     * If no hosts were specified, just bind to INADDR_ANY.
 	     * Otherwise  make sure 127.0.0.1 is added to the list.
 	     */
-	    nhostsbak = nhosts;
-	    nhostsbak++;
+	    nhostsbak = nhosts + 1;
 	    hosts = realloc(hosts, nhostsbak * sizeof(char *));
 	    if (nhostsbak == 1)
 	        hosts[0] = "*";
@@ -657,6 +660,75 @@ error:
 	return (1);
 }
 
+/*
+ * Create the list of addresses that we're bound to.  Normally, this
+ * list is empty because we're listening on the wildcard address
+ * (nhost == 0).  If -h is specified on the command line, then
+ * bound_sa will have a list of the addresses that the program binds
+ * to specifically.  This function takes that list and converts them to
+ * struct sockaddr * and stores them in bound_sa.
+ */
+static void
+update_bound_sa(void)
+{
+	struct addrinfo hints, *res = NULL;
+	int i;
+
+	if (nhosts == 0)
+		return;
+	bound_sa = malloc(sizeof(*bound_sa) * nhosts);
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = PF_UNSPEC;
+	for (i = 0; i < nhosts; i++)  {
+		if (getaddrinfo(hosts[i], NULL, &hints, &res) != 0)
+			continue;
+		bound_sa[i] = malloc(res->ai_addrlen);
+		memcpy(bound_sa[i], res->ai_addr, res->ai_addrlen);
+	}
+}
+
+/*
+ * Match the sa against the list of addresses we've bound to.  If
+ * we've not specifically bound to anything, we match everything.
+ * Otherwise, if the IPv4 or IPv6 address matches one of the addresses
+ * in bound_sa, we return true.  If not, we return false.
+ */
+int
+listen_addr(const struct sockaddr *sa)
+{
+	int i;
+
+	/*
+	 * If nhosts == 0, then there were no -h options on the
+	 * command line, so all addresses are addresses we're
+	 * listening to.
+	 */
+	if (nhosts == 0)
+		return 1;
+	for (i = 0; i < nhosts; i++) {
+		if (bound_sa[i] == NULL ||
+		    sa->sa_family != bound_sa[i]->sa_family)
+			continue;
+		switch (sa->sa_family) {
+		case AF_INET:
+		  	if (memcmp(&SA2SINADDR(sa), &SA2SINADDR(bound_sa[i]),
+			    sizeof(struct in_addr)) == 0)
+				return (1);
+			break;
+#ifdef INET6
+		case AF_INET6:
+		  	if (memcmp(&SA2SIN6ADDR(sa), &SA2SIN6ADDR(bound_sa[i]),
+			    sizeof(struct in6_addr)) == 0)
+				return (1);
+			break;
+#endif
+		default:
+			break;
+		}
+	}
+	return (0);
+}
+
 static void
 rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
 	    struct netbuf *addr)

Modified: stable/8/usr.sbin/rpcbind/rpcbind.h
==============================================================================
--- stable/8/usr.sbin/rpcbind/rpcbind.h	Tue Apr 13 00:33:07 2010	(r206534)
+++ stable/8/usr.sbin/rpcbind/rpcbind.h	Tue Apr 13 00:48:54 2010	(r206535)
@@ -134,6 +134,7 @@ void read_warmstart(void);
 
 char *addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
 		     char *netid);
+int listen_addr(const struct sockaddr *sa);
 void network_init(void);
 struct sockaddr *local_sa(int);
 
@@ -141,4 +142,12 @@ struct sockaddr *local_sa(int);
 #define	RPCB_ALLVERS 0
 #define	RPCB_ONEVERS 1
 
+/* To convert a struct sockaddr to IPv4 or IPv6 address */
+#define	SA2SIN(sa)	((struct sockaddr_in *)(sa))
+#define	SA2SINADDR(sa)	(SA2SIN(sa)->sin_addr)
+#ifdef INET6
+#define	SA2SIN6(sa)	((struct sockaddr_in6 *)(sa))
+#define	SA2SIN6ADDR(sa)	(SA2SIN6(sa)->sin6_addr)
+#endif
+
 #endif /* rpcbind_h */

Modified: stable/8/usr.sbin/rpcbind/util.c
==============================================================================
--- stable/8/usr.sbin/rpcbind/util.c	Tue Apr 13 00:33:07 2010	(r206534)
+++ stable/8/usr.sbin/rpcbind/util.c	Tue Apr 13 00:48:54 2010	(r206535)
@@ -58,13 +58,6 @@
 
 #include "rpcbind.h"
 
-#define	SA2SIN(sa)	((struct sockaddr_in *)(sa))
-#define	SA2SINADDR(sa)	(SA2SIN(sa)->sin_addr)
-#ifdef INET6
-#define	SA2SIN6(sa)	((struct sockaddr_in6 *)(sa))
-#define	SA2SIN6ADDR(sa)	(SA2SIN6(sa)->sin6_addr)
-#endif
-
 static struct sockaddr_in *local_in4;
 #ifdef INET6
 static struct sockaddr_in6 *local_in6;
@@ -176,9 +169,13 @@ addrmerge(struct netbuf *caller, char *s
 		goto freeit;
 
 	/*
-	 * Loop through all interfaces. For each interface, see if the
-	 * network portion of its address is equal to that of the client.
-	 * If so, we have found the interface that we want to use.
+	 * Loop through all interfaces. For each interface, see if it
+	 * is either the loopback interface (which we always listen
+	 * on) or is one of the addresses the program bound to (the
+	 * wildcard by default, or a subset if -h is specified) and
+	 * the network portion of its address is equal to that of the
+	 * client.  If so, we have found the interface that we want to
+	 * use.
 	 */
 	bestif = NULL;
 	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
@@ -189,6 +186,9 @@ addrmerge(struct netbuf *caller, char *s
 		    !(ifap->ifa_flags & IFF_UP))
 			continue;
 
+		if (!(ifap->ifa_flags & IFF_LOOPBACK) && !listen_addr(ifsa))
+			continue;
+
 		switch (hint_sa->sa_family) {
 		case AF_INET:
 			/*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201004130048.o3D0msej091565>