[Midnightbsd-cvs] src [10344] trunk/usr.sbin/rpcbind: sync up

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Sun Jun 3 18:46:26 EDT 2018


Revision: 10344
          http://svnweb.midnightbsd.org/src/?rev=10344
Author:   laffer1
Date:     2018-06-03 18:46:25 -0400 (Sun, 03 Jun 2018)
Log Message:
-----------
sync up

Modified Paths:
--------------
    trunk/usr.sbin/rpcbind/Makefile
    trunk/usr.sbin/rpcbind/check_bound.c
    trunk/usr.sbin/rpcbind/pmap_svc.c
    trunk/usr.sbin/rpcbind/rpcb_stat.c
    trunk/usr.sbin/rpcbind/rpcb_svc.c
    trunk/usr.sbin/rpcbind/rpcb_svc_4.c
    trunk/usr.sbin/rpcbind/rpcb_svc_com.c
    trunk/usr.sbin/rpcbind/rpcbind.8
    trunk/usr.sbin/rpcbind/rpcbind.c
    trunk/usr.sbin/rpcbind/rpcbind.h
    trunk/usr.sbin/rpcbind/security.c
    trunk/usr.sbin/rpcbind/util.c
    trunk/usr.sbin/rpcbind/warmstart.c

Added Paths:
-----------
    trunk/usr.sbin/rpcbind/tests/
    trunk/usr.sbin/rpcbind/tests/Makefile
    trunk/usr.sbin/rpcbind/tests/addrmerge_test.c

Property Changed:
----------------
    trunk/usr.sbin/rpcbind/rpcbind.8

Modified: trunk/usr.sbin/rpcbind/Makefile
===================================================================
--- trunk/usr.sbin/rpcbind/Makefile	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/Makefile	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+# $MidnightBSD$
 #	$NetBSD: Makefile,v 1.3 2000/06/20 13:56:43 fvdl Exp $
-# $MidnightBSD$
+# $FreeBSD: stable/10/usr.sbin/rpcbind/Makefile 319243 2017-05-30 17:46:19Z ngie $
 
 .include <bsd.own.mk>
 
@@ -8,15 +9,29 @@
 SRCS=	check_bound.c rpcb_stat.c rpcb_svc_4.c rpcbind.c pmap_svc.c \
 	rpcb_svc.c rpcb_svc_com.c security.c warmstart.c util.c
 
-CFLAGS+= -DPORTMAP -DLIBWRAP
+CFLAGS+= -DPORTMAP
 
 .if ${MK_INET6_SUPPORT} != "no"
 CFLAGS+= -DINET6
 .endif
 
+.if ${MK_RPCBIND_WARMSTART_SUPPORT} != "no"
+CFLAGS+= -DWARMSTART
+.endif
+
+.if ${MK_TCP_WRAPPERS} != "no"
+CFLAGS+= -DLIBWRAP
+DPADD+=	${LIBWRAP}
+LDADD+=	-lwrap
+.endif
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
+DPADD+=	${LIBUTIL}
+LDADD+=	-lutil
+
 WARNS?=	1
 
-DPADD=	${LIBWRAP} ${LIBUTIL}
-LDADD=	-lwrap -lutil
-
 .include <bsd.prog.mk>

Modified: trunk/usr.sbin/rpcbind/check_bound.c
===================================================================
--- trunk/usr.sbin/rpcbind/check_bound.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/check_bound.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: check_bound.c,v 1.2 2000/06/22 08:09:26 fvdl Exp $	*/
-/*	$MidnightBSD$ */
+/*	$FreeBSD: stable/10/usr.sbin/rpcbind/check_bound.c 301644 2016-06-08 17:09:47Z ngie $ */
 
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
@@ -44,7 +45,7 @@
 /*
  * check_bound.c
  * Checks to see whether the program is still bound to the
- * claimed address and returns the univeral merged address
+ * claimed address and returns the universal merged address
  *
  */
 
@@ -51,6 +52,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <rpc/rpc.h>
+#include <rpc/svc_dg.h>
 #include <stdio.h>
 #include <netconfig.h>
 #include <syslog.h>
@@ -160,6 +162,7 @@
 mergeaddr(SVCXPRT *xprt, char *netid, char *uaddr, char *saddr)
 {
 	struct fdlist *fdl;
+	struct svc_dg_data *dg_data;
 	char *c_uaddr, *s_uaddr, *m_uaddr, *allocated_uaddr = NULL;
 
 	for (fdl = fdhead; fdl; fdl = fdl->next)
@@ -171,21 +174,31 @@
 		/* that server died */
 		return (nullstring);
 	/*
+	 * Try to determine the local address on which the client contacted us,
+	 * so we can send a reply from the same address.  If it's unknown, then
+	 * try to determine which address the client used, and pick a nearby
+	 * local address.
+	 *
 	 * If saddr is not NULL, the remote client may have included the
 	 * address by which it contacted us.  Use that for the "client" uaddr,
 	 * otherwise use the info from the SVCXPRT.
 	 */
-	if (saddr != NULL) {
+	dg_data = (struct svc_dg_data*)xprt->xp_p2;
+	if (dg_data != NULL && dg_data->su_srcaddr.buf != NULL) {
+		c_uaddr = taddr2uaddr(fdl->nconf, &dg_data->su_srcaddr);
+		allocated_uaddr = c_uaddr;
+	}
+	else if (saddr != NULL) {
 		c_uaddr = saddr;
 	} else {
 		c_uaddr = taddr2uaddr(fdl->nconf, svc_getrpccaller(xprt));
-		if (c_uaddr == NULL) {
-			syslog(LOG_ERR, "taddr2uaddr failed for %s",
-				fdl->nconf->nc_netid);
-			return (NULL);
-		}
 		allocated_uaddr = c_uaddr;
 	}
+	if (c_uaddr == NULL) {
+		syslog(LOG_ERR, "taddr2uaddr failed for %s",
+			fdl->nconf->nc_netid);
+		return (NULL);
+	}
 
 #ifdef ND_DEBUG
 	if (debugging) {
@@ -208,8 +221,7 @@
 		fprintf(stderr, "mergeaddr: uaddr = %s, merged uaddr = %s\n",
 				uaddr, m_uaddr);
 #endif
-	if (allocated_uaddr != NULL)
-		free(allocated_uaddr);
+	free(allocated_uaddr);
 	return (m_uaddr);
 }
 
@@ -218,7 +230,7 @@
  * structure should not be freed.
  */
 struct netconfig *
-rpcbind_get_conf(char *netid)
+rpcbind_get_conf(const char *netid)
 {
 	struct fdlist *fdl;
 

Modified: trunk/usr.sbin/rpcbind/pmap_svc.c
===================================================================
--- trunk/usr.sbin/rpcbind/pmap_svc.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/pmap_svc.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: pmap_svc.c,v 1.2 2000/10/20 11:49:40 fvdl Exp $	*/
-/*	$MidnightBSD$ */
+/*	$FreeBSD: stable/10/usr.sbin/rpcbind/pmap_svc.c 173412 2007-11-07 10:53:41Z kevlo $ */
 
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for

Modified: trunk/usr.sbin/rpcbind/rpcb_stat.c
===================================================================
--- trunk/usr.sbin/rpcbind/rpcb_stat.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/rpcb_stat.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,6 +1,7 @@
+/* $MidnightBSD$ */
 /*
  * $NetBSD: rpcb_stat.c,v 1.2 2000/07/04 20:27:40 matt Exp $
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/rpcbind/rpcb_stat.c 302453 2016-07-08 20:39:37Z ngie $
  */
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
@@ -152,7 +153,7 @@
 	rpcbs_rmtcalllist *rl;
 	struct netconfig *nconf;
 
-	if (rtype > RPCBVERS_STAT)
+	if (rtype >= RPCBVERS_STAT)
 		return;
 	for (rl = inf[rtype].rmtinfo; rl; rl = rl->next) {
 

Modified: trunk/usr.sbin/rpcbind/rpcb_svc.c
===================================================================
--- trunk/usr.sbin/rpcbind/rpcb_svc.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/rpcb_svc.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: rpcb_svc.c,v 1.1 2000/06/02 23:15:41 fvdl Exp $	*/
-/*	$MidnightBSD$ */
+/*	$FreeBSD: stable/10/usr.sbin/rpcbind/rpcb_svc.c 173412 2007-11-07 10:53:41Z kevlo $ */
 
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for

Modified: trunk/usr.sbin/rpcbind/rpcb_svc_4.c
===================================================================
--- trunk/usr.sbin/rpcbind/rpcb_svc_4.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/rpcb_svc_4.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,6 +1,7 @@
+/* $MidnightBSD$ */
 /*
  * $NetBSD: rpcb_svc_4.c,v 1.1 2000/06/02 23:15:41 fvdl Exp $
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/rpcbind/rpcb_svc_4.c 173412 2007-11-07 10:53:41Z kevlo $
  */
 
 /*

Modified: trunk/usr.sbin/rpcbind/rpcb_svc_com.c
===================================================================
--- trunk/usr.sbin/rpcbind/rpcb_svc_com.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/rpcb_svc_com.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: rpcb_svc_com.c,v 1.9 2002/11/08 00:16:39 fvdl Exp $	*/
-/*	$MidnightBSD$ */
+/*	$FreeBSD: stable/10/usr.sbin/rpcbind/rpcb_svc_com.c 319615 2017-06-06 07:22:26Z delphij $ */
 
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
@@ -56,6 +57,7 @@
 #include <stdio.h>
 #ifdef PORTMAP
 #include <netinet/in.h>
+#include <rpc/rpc_com.h>
 #include <rpc/pmap_prot.h>
 #endif /* PORTMAP */
 #include <string.h>
@@ -419,7 +421,8 @@
 static bool_t
 xdr_encap_parms(XDR *xdrs, struct encap_parms *epp)
 {
-	return (xdr_bytes(xdrs, &(epp->args), (u_int *) &(epp->arglen), ~0));
+	return (xdr_bytes(xdrs, &(epp->args), (u_int *) &(epp->arglen),
+	    RPC_MAXDATASIZE));
 }
 
 /*
@@ -430,9 +433,9 @@
 xdr_rmtcall_args(XDR *xdrs, struct r_rmtcall_args *cap)
 {
 	/* does not get the address or the arguments */
-	if (xdr_u_int32_t(xdrs, &(cap->rmt_prog)) &&
-	    xdr_u_int32_t(xdrs, &(cap->rmt_vers)) &&
-	    xdr_u_int32_t(xdrs, &(cap->rmt_proc))) {
+	if (xdr_rpcprog(xdrs, &(cap->rmt_prog)) &&
+	    xdr_rpcvers(xdrs, &(cap->rmt_vers)) &&
+	    xdr_rpcproc(xdrs, &(cap->rmt_proc))) {
 		return (xdr_encap_parms(xdrs, &(cap->rmt_args)));
 	}
 	return (FALSE);

Modified: trunk/usr.sbin/rpcbind/rpcbind.8
===================================================================
--- trunk/usr.sbin/rpcbind/rpcbind.8	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/rpcbind.8	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,8 +1,9 @@
+.\" $MidnightBSD$
 .\" @(#)rpcbind.1m 1.19 92/09/14 SMI; from SVr4
 .\" Copyright 1989 AT&T
 .\" Copyright 1991 Sun Microsystems, Inc.
-.\" $MidnightBSD$
-.Dd April 23, 2007
+.\" $FreeBSD: stable/10/usr.sbin/rpcbind/rpcbind.8 319242 2017-05-30 17:42:48Z ngie $
+.Dd April 19, 2017
 .Dt RPCBIND 8
 .Os
 .Sh NAME
@@ -10,7 +11,7 @@
 .Nd universal addresses to RPC program number mapper
 .Sh SYNOPSIS
 .Nm
-.Op Fl 6adiLls
+.Op Fl 6adiLlswW
 .Op Fl h Ar bindip
 .Sh DESCRIPTION
 The
@@ -85,7 +86,7 @@
 With this option, the name-to-address translation consistency
 checks are shown in detail.
 .It Fl h Ar bindip
-Specify specific IP addresses to bind to for TCP and UDP requests.
+IP addresses to bind to when servicing TCP and UDP requests.
 This option
 may be specified multiple times and is typically necessary when running
 on a multi-homed host.
@@ -133,6 +134,22 @@
 clients from using
 .Nm
 to connect to services from a privileged port.
+.It Fl w
+Enable the warmstart feature.
+.Pp
+The warmstart feature saves RPC registrations on termination.
+Any saved RPC registrations are restored on restart if
+.Fl w
+is specified.
+This feature helps avoid RPC service interruption when restarting
+.Nm .
+warmstart support must be compiled in to
+.Nm .
+Portmap registrations are stored in
+.Pa /tmp/portmap.file .
+.Nm
+registrations are stored in
+.Pa /tmp/rpcbind.file .
 .El
 .Sh NOTES
 All RPC servers must be restarted if
@@ -140,7 +157,14 @@
 is restarted.
 .Sh FILES
 .Bl -tag -width /var/run/rpcbind.sock -compact
+.It Pa /tmp/portmap.file
+saved portmap registrations file.
+.It Pa /tmp/rpcbind.file
+saved
+.Nm
+registrations file.
 .It Pa /var/run/rpcbind.sock
+socket used for local connections.
 .El
 .Sh SEE ALSO
 .Xr rpcbind 3 ,


Property changes on: trunk/usr.sbin/rpcbind/rpcbind.8
___________________________________________________________________
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Modified: trunk/usr.sbin/rpcbind/rpcbind.c
===================================================================
--- trunk/usr.sbin/rpcbind/rpcbind.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/rpcbind.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: rpcbind.c,v 1.3 2002/11/08 00:16:40 fvdl Exp $	*/
-/*	$MidnightBSD$ */
+/*	$FreeBSD: stable/10/usr.sbin/rpcbind/rpcbind.c 332348 2018-04-10 03:15:07Z delphij $ */
 
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
@@ -86,17 +87,17 @@
 
 #define RPCBINDDLOCK "/var/run/rpcbind.lock"
 
-int runasdaemon = 0;
+static int runasdaemon = 0;
 int insecure = 0;
 int oldstyle_local = 0;
 int verboselog = 0;
 
-char **hosts = NULL;
-struct sockaddr **bound_sa;
-int ipv6_only = 0;
-int nhosts = 0;
-int on = 1;
-int rpcbindlockfd;
+static char **hosts = NULL;
+static struct sockaddr **bound_sa;
+static int ipv6_only = 0;
+static int nhosts = 0;
+static int on = 1;
+static int rpcbindlockfd;
 
 #ifdef WARMSTART
 /* Local Variable */
@@ -289,7 +290,7 @@
 	     */
 	    if ((fd = __rpc_nconf2fd(nconf)) < 0) {
 		int non_fatal = 0;
-		if (errno == EPROTONOSUPPORT)
+		if (errno == EAFNOSUPPORT)
 		    non_fatal = 1;
 		syslog(non_fatal?LOG_DEBUG:LOG_ERR, "cannot create socket for %s",
 		    nconf->nc_netid);
@@ -352,7 +353,7 @@
 		 */
 		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
 		    int non_fatal = 0;
-		    if (errno == EPROTONOSUPPORT &&
+		    if (errno == EAFNOSUPPORT &&
 			nconf->nc_semantics != NC_TPI_CLTS) 
 			non_fatal = 1;
 		    syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 
@@ -366,7 +367,7 @@
 			hints.ai_flags &= AI_NUMERICHOST;
 		    } else {
 			/*
-			 * Skip if we have an AF_INET6 adress.
+			 * Skip if we have an AF_INET6 address.
 			 */
 			if (inet_pton(AF_INET6,
 			    hosts[nhostsbak], host_addr) == 1) {
@@ -381,7 +382,7 @@
 			hints.ai_flags &= AI_NUMERICHOST;
 		    } else {
 			/*
-			 * Skip if we have an AF_INET adress.
+			 * Skip if we have an AF_INET address.
 			 */
 			if (inet_pton(AF_INET, hosts[nhostsbak],
 			    host_addr) == 1) {
@@ -548,6 +549,8 @@
 		pml->pml_map.pm_port = PMAPPORT;
 		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
 			if (tcptrans[0]) {
+				free(pml);
+				pml = NULL;
 				syslog(LOG_ERR,
 				"cannot have more than one TCP transport");
 				goto error;
@@ -755,12 +758,13 @@
  * Catch the signal and die
  */
 static void
-terminate(int dummy __unused)
+terminate(int signum __unused)
 {
 	close(rpcbindlockfd);
 #ifdef WARMSTART
 	syslog(LOG_ERR,
-		"rpcbind terminating on signal. Restart with \"rpcbind -w\"");
+	    "rpcbind terminating on signal %d. Restart with \"rpcbind -w\"",
+	    signum);
 	write_warmstart();	/* Dump yourself */
 #endif
 	exit(2);

Modified: trunk/usr.sbin/rpcbind/rpcbind.h
===================================================================
--- trunk/usr.sbin/rpcbind/rpcbind.h	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/rpcbind.h	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: rpcbind.h,v 1.1 2000/06/03 00:47:21 fvdl Exp $	*/
-/*	$MidnightBSD$ */
+/*	$FreeBSD: stable/10/usr.sbin/rpcbind/rpcbind.h 296994 2016-03-17 20:00:49Z asomers $ */
 
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
@@ -83,7 +84,7 @@
 int add_bndlist(struct netconfig *, struct netbuf *);
 bool_t is_bound(char *, char *);
 char *mergeaddr(SVCXPRT *, char *, char *, char *);
-struct netconfig *rpcbind_get_conf(char *);
+struct netconfig *rpcbind_get_conf(const char *);
 
 void rpcbs_init(void); 
 void rpcbs_procinfo(rpcvers_t, rpcproc_t);
@@ -132,8 +133,8 @@
 void write_warmstart(void);
 void read_warmstart(void);
 
-char *addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
-		     char *netid);
+char *addrmerge(struct netbuf *caller, const char *serv_uaddr,
+		const char *clnt_uaddr, char const *netid);
 int listen_addr(const struct sockaddr *sa);
 void network_init(void);
 struct sockaddr *local_sa(int);

Modified: trunk/usr.sbin/rpcbind/security.c
===================================================================
--- trunk/usr.sbin/rpcbind/security.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/security.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,5 +1,6 @@
+/* $MidnightBSD$ */
 /*	$NetBSD: security.c,v 1.5 2000/06/08 09:01:05 fvdl Exp $	*/
-/*	$MidnightBSD$ */
+/*	$FreeBSD: stable/10/usr.sbin/rpcbind/security.c 107952 2002-12-16 22:24:26Z mbr $ */
 
 #include <sys/types.h>
 #include <sys/time.h>

Added: trunk/usr.sbin/rpcbind/tests/Makefile
===================================================================
--- trunk/usr.sbin/rpcbind/tests/Makefile	                        (rev 0)
+++ trunk/usr.sbin/rpcbind/tests/Makefile	2018-06-03 22:46:25 UTC (rev 10344)
@@ -0,0 +1,18 @@
+# $MidnightBSD$
+# $FreeBSD: stable/10/usr.sbin/rpcbind/tests/Makefile 296994 2016-03-17 20:00:49Z asomers $
+
+.include <bsd.own.mk>
+
+.PATH:	${.CURDIR}/..
+
+ATF_TESTS_C=	addrmerge_test
+CFLAGS+=	-I${.CURDIR}/.. -Wno-cast-qual
+SRCS.addrmerge_test=	addrmerge_test.c util.c
+
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+= -DINET6
+.endif
+
+WARNS?=	3
+
+.include <bsd.test.mk>


Property changes on: trunk/usr.sbin/rpcbind/tests/Makefile
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Added: trunk/usr.sbin/rpcbind/tests/addrmerge_test.c
===================================================================
--- trunk/usr.sbin/rpcbind/tests/addrmerge_test.c	                        (rev 0)
+++ trunk/usr.sbin/rpcbind/tests/addrmerge_test.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -0,0 +1,872 @@
+/* $MidnightBSD$ */
+/*-
+ * Copyright (c) 2014 Spectra Logic Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD: stable/10/usr.sbin/rpcbind/tests/addrmerge_test.c 302676 2016-07-12 21:49:08Z asomers $
+ */
+
+#include <rpc/rpc.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ifaddrs.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <atf-c.h>
+
+#include "rpcbind.h"
+
+#define MAX_IFADDRS 16
+
+int debugging = false;
+
+/* Data for mocking getifaddrs */
+struct ifaddr_storage {
+	struct ifaddrs ifaddr;
+	struct sockaddr_storage addr;
+	struct sockaddr_storage mask;
+	struct sockaddr_storage bcast;
+} mock_ifaddr_storage[MAX_IFADDRS];
+struct ifaddrs *mock_ifaddrs = NULL;
+int ifaddr_count = 0; 
+
+/* Data for mocking listen_addr */
+int bind_address_count = 0;
+struct sockaddr* bind_addresses[MAX_IFADDRS];
+
+/* Stub library functions */
+void
+freeifaddrs(struct ifaddrs *ifp __unused)
+{
+	return ;
+}
+
+int
+getifaddrs(struct ifaddrs **ifap)
+{
+	*ifap = mock_ifaddrs;
+	return (0);
+}
+
+static void
+mock_ifaddr4(const char* name, const char* addr, const char* mask,
+    const char* bcast, unsigned int flags, bool bind)
+{
+	struct ifaddrs *ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
+	struct sockaddr_in *in = (struct sockaddr_in*)
+	    			&mock_ifaddr_storage[ifaddr_count].addr;
+	struct sockaddr_in *mask_in = (struct sockaddr_in*)
+	    			&mock_ifaddr_storage[ifaddr_count].mask;
+	struct sockaddr_in *bcast_in = (struct sockaddr_in*)
+	    			&mock_ifaddr_storage[ifaddr_count].bcast;
+
+	in->sin_family = AF_INET;
+	in->sin_port = 0;
+	in->sin_len = sizeof(*in);
+	in->sin_addr.s_addr = inet_addr(addr);
+	mask_in->sin_family = AF_INET;
+	mask_in->sin_port = 0;
+	mask_in->sin_len = sizeof(*mask_in);
+	mask_in->sin_addr.s_addr = inet_addr(mask);
+	bcast_in->sin_family = AF_INET;
+	bcast_in->sin_port = 0;
+	bcast_in->sin_len = sizeof(*bcast_in);
+	bcast_in->sin_addr.s_addr = inet_addr(bcast);
+	*ifaddr = (struct ifaddrs) {
+		.ifa_next = NULL,
+		.ifa_name = (char*) name,
+		.ifa_flags = flags,
+		.ifa_addr = (struct sockaddr*) in,
+		.ifa_netmask = (struct sockaddr*) mask_in,
+		.ifa_broadaddr = (struct sockaddr*) bcast_in,
+		.ifa_data = NULL,	/* addrmerge doesn't care*/
+	};
+
+	if (ifaddr_count > 0)
+		mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
+	ifaddr_count++;
+	mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
+
+	/* Optionally simulate binding an ip ala "rpcbind -h foo" */
+	if (bind) {
+		bind_addresses[bind_address_count] = (struct sockaddr*)in;
+		bind_address_count++;
+	}
+}
+
+#ifdef INET6
+static void
+mock_ifaddr6(const char* name, const char* addr, const char* mask,
+    const char* bcast, unsigned int flags, uint32_t scope_id, bool bind)
+{
+	struct ifaddrs *ifaddr = &mock_ifaddr_storage[ifaddr_count].ifaddr;
+	struct sockaddr_in6 *in6 = (struct sockaddr_in6*)
+	    			&mock_ifaddr_storage[ifaddr_count].addr;
+	struct sockaddr_in6 *mask_in6 = (struct sockaddr_in6*)
+	    			&mock_ifaddr_storage[ifaddr_count].mask;
+	struct sockaddr_in6 *bcast_in6 = (struct sockaddr_in6*)
+	    			&mock_ifaddr_storage[ifaddr_count].bcast;
+
+	in6->sin6_family = AF_INET6;
+	in6->sin6_port = 0;
+	in6->sin6_len = sizeof(*in6);
+	in6->sin6_scope_id = scope_id;
+	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, addr, (void*)&in6->sin6_addr));
+	mask_in6->sin6_family = AF_INET6;
+	mask_in6->sin6_port = 0;
+	mask_in6->sin6_len = sizeof(*mask_in6);
+	mask_in6->sin6_scope_id = scope_id;
+	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, mask,
+	    (void*)&mask_in6->sin6_addr));
+	bcast_in6->sin6_family = AF_INET6;
+	bcast_in6->sin6_port = 0;
+	bcast_in6->sin6_len = sizeof(*bcast_in6);
+	bcast_in6->sin6_scope_id = scope_id;
+	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, bcast,
+	    (void*)&bcast_in6->sin6_addr));
+	*ifaddr = (struct ifaddrs) {
+		.ifa_next = NULL,
+		.ifa_name = (char*) name,
+		.ifa_flags = flags,
+		.ifa_addr = (struct sockaddr*) in6,
+		.ifa_netmask = (struct sockaddr*) mask_in6,
+		.ifa_broadaddr = (struct sockaddr*) bcast_in6,
+		.ifa_data = NULL,	/* addrmerge doesn't care*/
+	};
+
+	if (ifaddr_count > 0)
+		mock_ifaddr_storage[ifaddr_count - 1].ifaddr.ifa_next = ifaddr;
+	ifaddr_count++;
+	mock_ifaddrs = &mock_ifaddr_storage[0].ifaddr;
+
+	/* Optionally simulate binding an ip ala "rpcbind -h foo" */
+	if (bind) {
+		bind_addresses[bind_address_count] = (struct sockaddr*)in6;
+		bind_address_count++;
+	}
+}
+#else
+static void
+mock_ifaddr6(const char* name __unused, const char* addr __unused,
+    const char* mask __unused, const char* bcast __unused,
+    unsigned int flags __unused, uint32_t scope_id __unused, bool bind __unused)
+{
+}
+#endif /*INET6 */
+
+static void
+mock_lo0(void)
+{
+	/* 
+	 * This broadcast address looks wrong, but it's what getifaddrs(2)
+	 * actually returns.  It's invalid because IFF_BROADCAST is not set
+	 */
+	mock_ifaddr4("lo0", "127.0.0.1", "255.0.0.0", "127.0.0.1",
+	    IFF_LOOPBACK | IFF_UP | IFF_RUNNING | IFF_MULTICAST, false);
+	mock_ifaddr6("lo0", "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+	    "::1",
+	    IFF_LOOPBACK | IFF_UP | IFF_RUNNING | IFF_MULTICAST, 0, false);
+}
+
+static void
+mock_igb0(void)
+{
+	mock_ifaddr4("igb0", "192.0.2.2", "255.255.255.128", "192.0.2.127",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    false);
+	mock_ifaddr6("igb0", "2001:db8::2", "ffff:ffff:ffff:ffff::",
+	    "2001:db8::ffff:ffff:ffff:ffff",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    0, false);
+	/* Link local address */
+	mock_ifaddr6("igb0", "fe80::2", "ffff:ffff:ffff:ffff::",
+	    "fe80::ffff:ffff:ffff:ffff",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    2, false);
+}
+
+/* On the same subnet as igb0 */
+static void
+mock_igb1(bool bind)
+{
+	mock_ifaddr4("igb1", "192.0.2.3", "255.255.255.128", "192.0.2.127",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    bind);
+	mock_ifaddr6("igb1", "2001:db8::3", "ffff:ffff:ffff:ffff::",
+	    "2001:db8::ffff:ffff:ffff:ffff",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    0, bind);
+	/* Link local address */
+	mock_ifaddr6("igb1", "fe80::3", "ffff:ffff:ffff:ffff::",
+	    "fe80::ffff:ffff:ffff:ffff",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    3, bind);
+}
+
+/* igb2 is on a different subnet than igb0 */
+static void
+mock_igb2(void)
+{
+	mock_ifaddr4("igb2", "192.0.2.130", "255.255.255.128", "192.0.2.255",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    false);
+	mock_ifaddr6("igb2", "2001:db8:1::2", "ffff:ffff:ffff:ffff::",
+	    "2001:db8:1:0:ffff:ffff:ffff:ffff",
+	    IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_SIMPLEX | IFF_MULTICAST,
+	    0, false);
+}
+
+/* tun0 is a P2P interface */
+static void
+mock_tun0(void)
+{
+	mock_ifaddr4("tun0", "192.0.2.5", "255.255.255.255", "192.0.2.6",
+	    IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_MULTICAST, false);
+	mock_ifaddr6("tun0", "2001:db8::5",
+	    "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+	    "2001:db8::6",
+	    IFF_UP | IFF_RUNNING | IFF_POINTOPOINT | IFF_MULTICAST, 0, false);
+}
+
+
+/* Stub rpcbind functions */
+int
+listen_addr(const struct sockaddr *sa)
+{
+	int i;
+	
+	if (bind_address_count == 0)
+		return (1);
+	
+	for (i = 0; i < bind_address_count; i++) {
+		if (bind_addresses[i]->sa_family != sa->sa_family)
+			continue;
+
+		if (0 == memcmp(bind_addresses[i]->sa_data, sa->sa_data,
+		    sa->sa_len))
+			return (1);
+	}
+	return (0);
+}
+
+struct netconfig*
+rpcbind_get_conf(const char* netid __unused)
+{
+	/* Use static variables so we can return pointers to them */
+	static char* lookups = NULL;
+	static struct netconfig nconf_udp;
+#ifdef INET6
+	static struct netconfig nconf_udp6;
+#endif /* INET6 */
+
+	nconf_udp.nc_netid = "udp"; //netid_storage;
+	nconf_udp.nc_semantics = NC_TPI_CLTS;
+	nconf_udp.nc_flag = NC_VISIBLE;
+	nconf_udp.nc_protofmly = (char*)"inet";
+	nconf_udp.nc_proto = (char*)"udp";
+	nconf_udp.nc_device = (char*)"-";
+	nconf_udp.nc_nlookups = 0;
+	nconf_udp.nc_lookups = &lookups;
+
+#ifdef INET6
+	nconf_udp6.nc_netid = "udp6"; //netid_storage;
+	nconf_udp6.nc_semantics = NC_TPI_CLTS;
+	nconf_udp6.nc_flag = NC_VISIBLE;
+	nconf_udp6.nc_protofmly = (char*)"inet6";
+	nconf_udp6.nc_proto = (char*)"udp6";
+	nconf_udp6.nc_device = (char*)"-";
+	nconf_udp6.nc_nlookups = 0;
+	nconf_udp6.nc_lookups = &lookups;
+#endif /* INET6 */
+
+	if (0 == strncmp("udp", netid, sizeof("udp")))
+		return (&nconf_udp);
+#ifdef INET6
+	else if (0 == strncmp("udp6", netid, sizeof("udp6")))
+		return (&nconf_udp6);
+#endif /* INET6 */
+	else
+		return (NULL);
+}
+
+/*
+ * Helper function used by most test cases
+ * param recvdstaddr	If non-null, the uaddr on which the request was received
+ */
+static char*
+do_addrmerge4(const char* recvdstaddr)
+{
+	struct netbuf caller;
+	struct sockaddr_in caller_in;
+	const char *serv_uaddr, *clnt_uaddr, *netid;
+	
+	/* caller contains the client's IP address */
+	caller.maxlen = sizeof(struct sockaddr_storage);
+	caller.len = sizeof(caller_in);
+	caller_in.sin_family = AF_INET;
+	caller_in.sin_len = sizeof(caller_in);
+	caller_in.sin_port = 1234;
+	caller_in.sin_addr.s_addr = inet_addr("192.0.2.1");
+	caller.buf = (void*)&caller_in;
+	if (recvdstaddr != NULL)
+		clnt_uaddr = recvdstaddr;
+	else
+		clnt_uaddr = "192.0.2.1.3.46";
+
+	/* assume server is bound in INADDR_ANY port 814 */
+	serv_uaddr = "0.0.0.0.3.46";
+
+	netid = "udp";
+	return (addrmerge(&caller, serv_uaddr, clnt_uaddr, netid));
+}
+
+#ifdef INET6
+/*
+ * Variant of do_addrmerge4 where the caller has an IPv6 address
+ * param recvdstaddr	If non-null, the uaddr on which the request was received
+ */
+static char*
+do_addrmerge6(const char* recvdstaddr)
+{
+	struct netbuf caller;
+	struct sockaddr_in6 caller_in6;
+	const char *serv_uaddr, *clnt_uaddr, *netid;
+	
+	/* caller contains the client's IP address */
+	caller.maxlen = sizeof(struct sockaddr_storage);
+	caller.len = sizeof(caller_in6);
+	caller_in6.sin6_family = AF_INET6;
+	caller_in6.sin6_len = sizeof(caller_in6);
+	caller_in6.sin6_port = 1234;
+	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, "2001:db8::1",
+	    (void*)&caller_in6.sin6_addr));
+	caller.buf = (void*)&caller_in6;
+	if (recvdstaddr != NULL)
+		clnt_uaddr = recvdstaddr;
+	else
+		clnt_uaddr = "2001:db8::1.3.46";
+
+	/* assume server is bound in INADDR_ANY port 814 */
+	serv_uaddr = "::1.3.46";
+
+	netid = "udp6";
+	return (addrmerge(&caller, serv_uaddr, clnt_uaddr, netid));
+}
+
+/* Variant of do_addrmerge6 where the caller uses a link local address */
+static char*
+do_addrmerge6_ll(void)
+{
+	struct netbuf caller;
+	struct sockaddr_in6 caller_in6;
+	const char *serv_uaddr, *clnt_uaddr, *netid;
+	
+	/* caller contains the client's IP address */
+	caller.maxlen = sizeof(struct sockaddr_storage);
+	caller.len = sizeof(caller_in6);
+	caller_in6.sin6_family = AF_INET6;
+	caller_in6.sin6_len = sizeof(caller_in6);
+	caller_in6.sin6_port = 1234;
+	caller_in6.sin6_scope_id = 2; /* same as igb0 */
+	ATF_REQUIRE_EQ(1, inet_pton(AF_INET6, "fe80::beef",
+	    (void*)&caller_in6.sin6_addr));
+	caller.buf = (void*)&caller_in6;
+	clnt_uaddr = "fe80::beef.3.46";
+
+	/* assume server is bound in INADDR_ANY port 814 */
+	serv_uaddr = "::1.3.46";
+
+	netid = "udp6";
+	return (addrmerge(&caller, serv_uaddr, clnt_uaddr, netid));
+}
+#endif /* INET6 */
+
+ATF_TC_WITHOUT_HEAD(addrmerge_noifaddrs);
+ATF_TC_BODY(addrmerge_noifaddrs, tc)
+{
+	char* maddr;
+
+	maddr = do_addrmerge4(NULL);
+
+	/* Since getifaddrs returns null, addrmerge must too */
+	ATF_CHECK_EQ(NULL, maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only);
+ATF_TC_BODY(addrmerge_localhost_only, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return localhost only */
+	mock_lo0();
+
+	maddr = do_addrmerge4(NULL);
+
+	/* We must return localhost if there is nothing better */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("127.0.0.1.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed);
+ATF_TC_BODY(addrmerge_singlehomed, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address */
+	mock_lo0();
+	mock_igb0();
+
+	maddr = do_addrmerge4(NULL);
+
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet);
+ATF_TC_BODY(addrmerge_one_addr_on_each_subnet, tc)
+{
+	char *maddr;
+	
+	mock_lo0();
+	mock_igb0();
+	mock_igb2();
+
+	maddr = do_addrmerge4(NULL);
+
+	/* We must return the address on the caller's subnet */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
+	free(maddr);
+}
+
+
+/*
+ * Like addrmerge_one_addr_on_each_subnet, but getifaddrs returns a different
+ * order
+ */
+ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet_rev);
+ATF_TC_BODY(addrmerge_one_addr_on_each_subnet_rev, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address on each of two subnets */
+	mock_igb2();
+	mock_igb0();
+	mock_lo0();
+
+	maddr = do_addrmerge4(NULL);
+
+	/* We must return the address on the caller's subnet */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_point2point);
+ATF_TC_BODY(addrmerge_point2point, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one normal and one p2p address */
+	mock_lo0();
+	mock_igb2();
+	mock_tun0();
+
+	maddr = do_addrmerge4(NULL);
+
+	/* addrmerge should disprefer P2P interfaces */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.130.3.46", maddr);
+	free(maddr);
+}
+
+/* Like addrerge_point2point, but getifaddrs returns a different order */
+ATF_TC_WITHOUT_HEAD(addrmerge_point2point_rev);
+ATF_TC_BODY(addrmerge_point2point_rev, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one normal and one p2p address */
+	mock_tun0();
+	mock_igb2();
+	mock_lo0();
+
+	maddr = do_addrmerge4(NULL);
+
+	/* addrmerge should disprefer P2P interfaces */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.130.3.46", maddr);
+	free(maddr);
+}
+
+/*
+ * Simulate using rpcbind -h to select just one ip when the subnet has
+ * multiple
+ */
+ATF_TC_WITHOUT_HEAD(addrmerge_bindip);
+ATF_TC_BODY(addrmerge_bindip, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address on each of two subnets */
+	mock_lo0();
+	mock_igb0();
+	mock_igb1(true);
+
+	maddr = do_addrmerge4(NULL);
+
+	/* We must return the address to which we are bound */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.3.3.46", maddr);
+	free(maddr);
+}
+
+/* Like addrmerge_bindip, but getifaddrs returns a different order */
+ATF_TC_WITHOUT_HEAD(addrmerge_bindip_rev);
+ATF_TC_BODY(addrmerge_bindip_rev, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address on each of two subnets */
+	mock_igb1(true);
+	mock_igb0();
+	mock_lo0();
+
+	maddr = do_addrmerge4(NULL);
+
+	/* We must return the address to which we are bound */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.3.3.46", maddr);
+	free(maddr);
+}
+
+/* 
+ * The address on which the request was received is known, and is provided as
+ * the hint.
+ */
+ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr);
+ATF_TC_BODY(addrmerge_recvdstaddr, tc)
+{
+	char *maddr;
+	
+	mock_lo0();
+	mock_igb0();
+	mock_igb1(false);
+
+	maddr = do_addrmerge4("192.0.2.2.3.46");
+
+	/* We must return the address on which the request was received */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr_rev);
+ATF_TC_BODY(addrmerge_recvdstaddr_rev, tc)
+{
+	char *maddr;
+	
+	mock_igb1(false);
+	mock_igb0();
+	mock_lo0();
+
+	maddr = do_addrmerge4("192.0.2.2.3.46");
+
+	/* We must return the address on which the request was received */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("192.0.2.2.3.46", maddr);
+	free(maddr);
+}
+
+#ifdef INET6
+ATF_TC_WITHOUT_HEAD(addrmerge_localhost_only6);
+ATF_TC_BODY(addrmerge_localhost_only6, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return localhost only */
+	mock_lo0();
+
+	maddr = do_addrmerge6(NULL);
+
+	/* We must return localhost if there is nothing better */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("::1.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_singlehomed6);
+ATF_TC_BODY(addrmerge_singlehomed6, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address */
+	mock_lo0();
+	mock_igb0();
+
+	maddr = do_addrmerge6(NULL);
+
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6);
+ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6, tc)
+{
+	char *maddr;
+	
+	mock_lo0();
+	mock_igb0();
+	mock_igb2();
+
+	maddr = do_addrmerge6(NULL);
+
+	/* We must return the address on the caller's subnet */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
+	free(maddr);
+}
+
+
+/*
+ * Like addrmerge_one_addr_on_each_subnet6, but getifaddrs returns a different
+ * order
+ */
+ATF_TC_WITHOUT_HEAD(addrmerge_one_addr_on_each_subnet6_rev);
+ATF_TC_BODY(addrmerge_one_addr_on_each_subnet6_rev, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address on each of two subnets */
+	mock_igb2();
+	mock_igb0();
+	mock_lo0();
+
+	maddr = do_addrmerge6(NULL);
+
+	/* We must return the address on the caller's subnet */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_point2point6);
+ATF_TC_BODY(addrmerge_point2point6, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one normal and one p2p address */
+	mock_lo0();
+	mock_igb2();
+	mock_tun0();
+
+	maddr = do_addrmerge6(NULL);
+
+	/* addrmerge should disprefer P2P interfaces */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8:1::2.3.46", maddr);
+	free(maddr);
+}
+
+/* Like addrerge_point2point, but getifaddrs returns a different order */
+ATF_TC_WITHOUT_HEAD(addrmerge_point2point6_rev);
+ATF_TC_BODY(addrmerge_point2point6_rev, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one normal and one p2p address */
+	mock_tun0();
+	mock_igb2();
+	mock_lo0();
+
+	maddr = do_addrmerge6(NULL);
+
+	/* addrmerge should disprefer P2P interfaces */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8:1::2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_bindip6);
+ATF_TC_BODY(addrmerge_bindip6, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address on each of two subnets */
+	mock_lo0();
+	mock_igb0();
+	mock_igb1(true);
+
+	maddr = do_addrmerge6(NULL);
+
+	/* We must return the address to which we are bound */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8::3.3.46", maddr);
+	free(maddr);
+}
+
+/* Like addrerge_bindip, but getifaddrs returns a different order */
+ATF_TC_WITHOUT_HEAD(addrmerge_bindip6_rev);
+ATF_TC_BODY(addrmerge_bindip6_rev, tc)
+{
+	char *maddr;
+	
+	/* getifaddrs will return one public address on each of two subnets */
+	mock_igb1(true);
+	mock_igb0();
+	mock_lo0();
+
+	maddr = do_addrmerge6(NULL);
+
+	/* We must return the address to which we are bound */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8::3.3.46", maddr);
+	free(maddr);
+}
+
+/* 
+ * IPv6 Link Local addresses with the same scope id as the caller, if the caller
+ * is also a link local address, should be preferred
+ */
+ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal);
+ATF_TC_BODY(addrmerge_ipv6_linklocal, tc)
+{
+	char *maddr;
+	
+	/* 
+	 * getifaddrs will return two link local addresses with the same netmask
+	 * and prefix but different scope IDs
+	 */
+	mock_igb1(false);
+	mock_igb0();
+	mock_lo0();
+
+	maddr = do_addrmerge6_ll();
+
+	/* We must return the address to which we are bound */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("fe80::2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_ipv6_linklocal_rev);
+ATF_TC_BODY(addrmerge_ipv6_linklocal_rev, tc)
+{
+	char *maddr;
+	
+	/* 
+	 * getifaddrs will return two link local addresses with the same netmask
+	 * and prefix but different scope IDs
+	 */
+	mock_lo0();
+	mock_igb0();
+	mock_igb1(false);
+
+	maddr = do_addrmerge6_ll();
+
+	/* We must return the address to which we are bound */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("fe80::2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6);
+ATF_TC_BODY(addrmerge_recvdstaddr6, tc)
+{
+	char *maddr;
+	
+	mock_lo0();
+	mock_igb0();
+	mock_igb1(false);
+
+	maddr = do_addrmerge6("2001:db8::2.3.46");
+
+	/* We must return the address on which the request was received */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
+	free(maddr);
+}
+
+ATF_TC_WITHOUT_HEAD(addrmerge_recvdstaddr6_rev);
+ATF_TC_BODY(addrmerge_recvdstaddr6_rev, tc)
+{
+	char *maddr;
+	
+	mock_igb1(false);
+	mock_igb0();
+	mock_lo0();
+
+	maddr = do_addrmerge6("2001:db8::2.3.46");
+
+	/* We must return the address on which the request was received */
+	ATF_REQUIRE(maddr != NULL);
+	ATF_CHECK_STREQ("2001:db8::2.3.46", maddr);
+	free(maddr);
+}
+#endif /* INET6 */
+
+
+ATF_TP_ADD_TCS(tp)
+{
+	ATF_TP_ADD_TC(tp, addrmerge_noifaddrs);
+	ATF_TP_ADD_TC(tp, addrmerge_localhost_only);
+	ATF_TP_ADD_TC(tp, addrmerge_singlehomed);
+	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet);
+	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet_rev);
+	ATF_TP_ADD_TC(tp, addrmerge_point2point);
+	ATF_TP_ADD_TC(tp, addrmerge_point2point_rev);
+	ATF_TP_ADD_TC(tp, addrmerge_bindip);
+	ATF_TP_ADD_TC(tp, addrmerge_bindip_rev);
+	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr);
+	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr_rev);
+#ifdef INET6
+	ATF_TP_ADD_TC(tp, addrmerge_localhost_only6);
+	ATF_TP_ADD_TC(tp, addrmerge_singlehomed6);
+	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet6);
+	ATF_TP_ADD_TC(tp, addrmerge_one_addr_on_each_subnet6_rev);
+	ATF_TP_ADD_TC(tp, addrmerge_point2point6);
+	ATF_TP_ADD_TC(tp, addrmerge_point2point6_rev);
+	ATF_TP_ADD_TC(tp, addrmerge_bindip6);
+	ATF_TP_ADD_TC(tp, addrmerge_bindip6_rev);
+	ATF_TP_ADD_TC(tp, addrmerge_ipv6_linklocal);
+	ATF_TP_ADD_TC(tp, addrmerge_ipv6_linklocal_rev);
+	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr6);
+	ATF_TP_ADD_TC(tp, addrmerge_recvdstaddr6_rev);
+#endif
+
+	return (atf_no_error());
+}


Property changes on: trunk/usr.sbin/rpcbind/tests/addrmerge_test.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+MidnightBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: trunk/usr.sbin/rpcbind/util.c
===================================================================
--- trunk/usr.sbin/rpcbind/util.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/util.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,6 +1,7 @@
+/* $MidnightBSD$ */
 /*
  * $NetBSD: util.c,v 1.4 2000/08/03 00:04:30 fvdl Exp $
- * $MidnightBSD$
+ * $FreeBSD: stable/10/usr.sbin/rpcbind/util.c 301646 2016-06-08 17:11:42Z ngie $
  */
 
 /*-
@@ -56,7 +57,7 @@
 static struct sockaddr_in6 *local_in6;
 #endif
 
-static int bitmaskcmp(void *, void *, void *, int);
+static int bitmaskcmp(struct sockaddr *, struct sockaddr *, struct sockaddr *);
 
 /*
  * For all bits set in "mask", compare the corresponding bits in
@@ -64,11 +65,35 @@
  * match.
  */
 static int
-bitmaskcmp(void *dst, void *src, void *mask, int bytelen)
+bitmaskcmp(struct sockaddr *dst, struct sockaddr *src, struct sockaddr *mask)
 {
 	int i;
-	u_int8_t *p1 = dst, *p2 = src, *netmask = mask;
+	u_int8_t *p1, *p2, *netmask;
+	int bytelen;
 
+	if (dst->sa_family != src->sa_family ||
+	    dst->sa_family != mask->sa_family)
+		return (1);
+
+	switch (dst->sa_family) {
+	case AF_INET:
+		p1 = (uint8_t*) &SA2SINADDR(dst);
+		p2 = (uint8_t*) &SA2SINADDR(src);
+		netmask = (uint8_t*) &SA2SINADDR(mask);
+		bytelen = sizeof(struct in_addr);
+		break;
+#ifdef INET6
+	case AF_INET6:
+		p1 = (uint8_t*) &SA2SIN6ADDR(dst);
+		p2 = (uint8_t*) &SA2SIN6ADDR(src);
+		netmask = (uint8_t*) &SA2SIN6ADDR(mask);
+		bytelen = sizeof(struct in6_addr);
+		break;
+#endif
+	default:
+		return (1);
+	}
+
 	for (i = 0; i < bytelen; i++)
 		if ((p1[i] & netmask[i]) != (p2[i] & netmask[i]))
 			return (1);
@@ -86,8 +111,8 @@
  * string which should be freed by the caller. On error, returns NULL.
  */
 char *
-addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
-	  char *netid)
+addrmerge(struct netbuf *caller, const char *serv_uaddr, const char *clnt_uaddr,
+	  const char *netid)
 {
 	struct ifaddrs *ifap, *ifp = NULL, *bestif;
 	struct netbuf *serv_nbp = NULL, *hint_nbp = NULL, tbuf;
@@ -94,8 +119,12 @@
 	struct sockaddr *caller_sa, *hint_sa, *ifsa, *ifmasksa, *serv_sa;
 	struct sockaddr_storage ss;
 	struct netconfig *nconf;
-	char *caller_uaddr = NULL, *hint_uaddr = NULL;
+	char *caller_uaddr = NULL;
+#ifdef ND_DEBUG
+	const char *hint_uaddr = NULL;
+#endif
 	char *ret = NULL;
+	int bestif_goodness;
 
 #ifdef ND_DEBUG
 	if (debugging)
@@ -114,13 +143,17 @@
 	 */
 	hint_sa = NULL;
 	if (clnt_uaddr != NULL) {
+#ifdef ND_DEBUG
 		hint_uaddr = clnt_uaddr;
+#endif
 		if ((hint_nbp = uaddr2taddr(nconf, clnt_uaddr)) == NULL)
 			goto freeit;
 		hint_sa = hint_nbp->buf;
 	}
 	if (hint_sa == NULL || hint_sa->sa_family != caller_sa->sa_family) {
+#ifdef ND_DEBUG
 		hint_uaddr = caller_uaddr;
+#endif
 		hint_sa = caller->buf;
 	}
 
@@ -139,19 +172,29 @@
 		goto freeit;
 
 	/*
-	 * 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.
+	 * Loop through all interface addresses.  We are listening to an address
+	 * if any of the following are true:
+	 * a) It's a loopback address
+	 * b) It was specified with the -h command line option
+	 * c) There were no -h command line options.
+	 *
+	 * Among addresses on which we are listening, choose in order of
+	 * preference an address that is:
+	 *
+	 * a) Equal to the hint
+	 * b) A link local address with the same scope ID as the client's
+	 *    address, if the client's address is also link local
+	 * c) An address on the same subnet as the client's address
+	 * d) A non-localhost, non-p2p address
+	 * e) Any usable address
 	 */
 	bestif = NULL;
+	bestif_goodness = 0;
 	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
 		ifsa = ifap->ifa_addr;
 		ifmasksa = ifap->ifa_netmask;
 
+		/* Skip addresses where we don't listen */
 		if (ifsa == NULL || ifsa->sa_family != hint_sa->sa_family ||
 		    !(ifap->ifa_flags & IFF_UP))
 			continue;
@@ -159,21 +202,29 @@
 		if (!(ifap->ifa_flags & IFF_LOOPBACK) && !listen_addr(ifsa))
 			continue;
 
-		switch (hint_sa->sa_family) {
-		case AF_INET:
-			/*
-			 * If the hint address matches this interface
-			 * address/netmask, then we're done.
-			 */
-			if (!bitmaskcmp(&SA2SINADDR(ifsa),
-			    &SA2SINADDR(hint_sa), &SA2SINADDR(ifmasksa),
-			    sizeof(struct in_addr))) {
-				bestif = ifap;
-				goto found;
-			}
-			break;
+		if ((hint_sa->sa_family == AF_INET) &&
+		    ((((struct sockaddr_in*)hint_sa)->sin_addr.s_addr == 
+		      ((struct sockaddr_in*)ifsa)->sin_addr.s_addr))) {
+			const int goodness = 4;
+
+			bestif_goodness = goodness;
+			bestif = ifap;
+			goto found;
+		}
 #ifdef INET6
-		case AF_INET6:
+		if ((hint_sa->sa_family == AF_INET6) &&
+		    (0 == memcmp(&((struct sockaddr_in6*)hint_sa)->sin6_addr,
+				 &((struct sockaddr_in6*)ifsa)->sin6_addr,
+				 sizeof(struct in6_addr))) &&
+		    (((struct sockaddr_in6*)hint_sa)->sin6_scope_id ==
+		    (((struct sockaddr_in6*)ifsa)->sin6_scope_id))) {
+			const int goodness = 4;
+
+			bestif_goodness = goodness;
+			bestif = ifap;
+			goto found;
+		}
+		if (hint_sa->sa_family == AF_INET6) {
 			/*
 			 * For v6 link local addresses, if the caller is on
 			 * a link-local address then use the scope id to see
@@ -184,28 +235,33 @@
 			    IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(hint_sa))) {
 				if (SA2SIN6(ifsa)->sin6_scope_id ==
 				    SA2SIN6(caller_sa)->sin6_scope_id) {
-					bestif = ifap;
-					goto found;
+					const int goodness = 3;
+
+					if (bestif_goodness < goodness) {
+						bestif = ifap;
+						bestif_goodness = goodness;
+					}
 				}
-			} else if (!bitmaskcmp(&SA2SIN6ADDR(ifsa),
-			    &SA2SIN6ADDR(hint_sa), &SA2SIN6ADDR(ifmasksa),
-			    sizeof(struct in6_addr))) {
+			}
+		}
+#endif /* INET6 */
+		if (0 == bitmaskcmp(hint_sa, ifsa, ifmasksa)) {
+			const int goodness = 2;
+
+			if (bestif_goodness < goodness) {
 				bestif = ifap;
-				goto found;
+				bestif_goodness = goodness;
 			}
-			break;
-#endif
-		default:
-			continue;
 		}
+		if (!(ifap->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))) {
+			const int goodness = 1;
 
-		/*
-		 * Remember the first possibly useful interface, preferring
-		 * "normal" to point-to-point and loopback ones.
-		 */
-		if (bestif == NULL ||
-		    (!(ifap->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
-		    (bestif->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))))
+			if (bestif_goodness < goodness) {
+				bestif = ifap;
+				bestif_goodness = goodness;
+			}
+		}
+		if (bestif == NULL)
 			bestif = ifap;
 	}
 	if (bestif == NULL)
@@ -238,8 +294,7 @@
 	ret = taddr2uaddr(nconf, &tbuf);
 
 freeit:
-	if (caller_uaddr != NULL)
-		free(caller_uaddr);
+	free(caller_uaddr);
 	if (hint_nbp != NULL) {
 		free(hint_nbp->buf);
 		free(hint_nbp);
@@ -281,8 +336,10 @@
 		if (local_in4 == NULL) {
 			if (debugging)
 				fprintf(stderr, "can't alloc local ip4 addr\n");
+			exit(1);
 		}
 		memcpy(local_in4, res->ai_addr, sizeof *local_in4);
+		freeaddrinfo(res);
 	}
 
 #ifdef INET6
@@ -296,8 +353,10 @@
 		if (local_in6 == NULL) {
 			if (debugging)
 				fprintf(stderr, "can't alloc local ip6 addr\n");
+			exit(1);
 		}
 		memcpy(local_in6, res->ai_addr, sizeof *local_in6);
+		freeaddrinfo(res);
 	}
 
 	/*
@@ -310,6 +369,11 @@
 	inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, &mreq6.ipv6mr_multiaddr);
 
 	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+	if (s == -1) {
+		if (debugging)
+			fprintf(stderr, "couldn't create ip6 socket");
+		goto done_inet6;
+	}
 
 	/*
 	 * Loop through all interfaces. For each IPv6 multicast-capable
@@ -331,6 +395,8 @@
 			if (debugging)
 				perror("setsockopt v6 multicast");
 	}
+done_inet6:
+	freeifaddrs(ifp);
 #endif
 
 	/* close(s); */

Modified: trunk/usr.sbin/rpcbind/warmstart.c
===================================================================
--- trunk/usr.sbin/rpcbind/warmstart.c	2018-06-03 22:45:22 UTC (rev 10343)
+++ trunk/usr.sbin/rpcbind/warmstart.c	2018-06-03 22:46:25 UTC (rev 10344)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
 /*
  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  * unrestricted use provided that this legend is included on all tape
@@ -35,7 +36,7 @@
 
 /*
  * #ident	"@(#)warmstart.c	1.7	93/07/05 SMI"
- * $MidnightBSD$/
+ * $FreeBSD: stable/10/usr.sbin/rpcbind/warmstart.c 224001 2011-07-14 07:28:49Z delphij $/
  */
 #include <sys/types.h>
 #include <sys/stat.h>



More information about the Midnightbsd-cvs mailing list