[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