xref: /minix/tests/fs/nfs/nfsservice/rpcbind/util.c (revision 11be35a1)
1*11be35a1SLionel Sambuc /*	$NetBSD: util.c,v 1.2 2011/06/11 18:03:17 christos Exp $	*/
2*11be35a1SLionel Sambuc 
3*11be35a1SLionel Sambuc /*-
4*11be35a1SLionel Sambuc  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5*11be35a1SLionel Sambuc  * All rights reserved.
6*11be35a1SLionel Sambuc  *
7*11be35a1SLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
8*11be35a1SLionel Sambuc  * by Frank van der Linden.
9*11be35a1SLionel Sambuc  *
10*11be35a1SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11*11be35a1SLionel Sambuc  * modification, are permitted provided that the following conditions
12*11be35a1SLionel Sambuc  * are met:
13*11be35a1SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14*11be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15*11be35a1SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16*11be35a1SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17*11be35a1SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18*11be35a1SLionel Sambuc  *
19*11be35a1SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*11be35a1SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*11be35a1SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*11be35a1SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*11be35a1SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*11be35a1SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*11be35a1SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*11be35a1SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*11be35a1SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*11be35a1SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*11be35a1SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
30*11be35a1SLionel Sambuc  */
31*11be35a1SLionel Sambuc 
32*11be35a1SLionel Sambuc #include <sys/types.h>
33*11be35a1SLionel Sambuc #include <sys/socket.h>
34*11be35a1SLionel Sambuc #include <sys/queue.h>
35*11be35a1SLionel Sambuc #include <net/if.h>
36*11be35a1SLionel Sambuc #include <netinet/in.h>
37*11be35a1SLionel Sambuc #include <assert.h>
38*11be35a1SLionel Sambuc #include <ifaddrs.h>
39*11be35a1SLionel Sambuc #include <poll.h>
40*11be35a1SLionel Sambuc #include <rpc/rpc.h>
41*11be35a1SLionel Sambuc #include <errno.h>
42*11be35a1SLionel Sambuc #include <stdlib.h>
43*11be35a1SLionel Sambuc #include <string.h>
44*11be35a1SLionel Sambuc #include <unistd.h>
45*11be35a1SLionel Sambuc #include <netdb.h>
46*11be35a1SLionel Sambuc #include <netconfig.h>
47*11be35a1SLionel Sambuc #include <stdio.h>
48*11be35a1SLionel Sambuc #include <arpa/inet.h>
49*11be35a1SLionel Sambuc 
50*11be35a1SLionel Sambuc #include <rump/rump.h>
51*11be35a1SLionel Sambuc #include <rump/rump_syscalls.h>
52*11be35a1SLionel Sambuc 
53*11be35a1SLionel Sambuc #include "rpcbind.h"
54*11be35a1SLionel Sambuc 
55*11be35a1SLionel Sambuc static struct sockaddr_in *local_in4;
56*11be35a1SLionel Sambuc #ifdef INET6
57*11be35a1SLionel Sambuc static struct sockaddr_in6 *local_in6;
58*11be35a1SLionel Sambuc #endif
59*11be35a1SLionel Sambuc 
60*11be35a1SLionel Sambuc static int bitmaskcmp(void *, void *, void *, int);
61*11be35a1SLionel Sambuc #ifdef INET6
62*11be35a1SLionel Sambuc static void in6_fillscopeid(struct sockaddr_in6 *);
63*11be35a1SLionel Sambuc #endif
64*11be35a1SLionel Sambuc 
65*11be35a1SLionel Sambuc /*
66*11be35a1SLionel Sambuc  * For all bits set in "mask", compare the corresponding bits in
67*11be35a1SLionel Sambuc  * "dst" and "src", and see if they match.
68*11be35a1SLionel Sambuc  */
69*11be35a1SLionel Sambuc static int
bitmaskcmp(void * dst,void * src,void * mask,int bytelen)70*11be35a1SLionel Sambuc bitmaskcmp(void *dst, void *src, void *mask, int bytelen)
71*11be35a1SLionel Sambuc {
72*11be35a1SLionel Sambuc 	int i, j;
73*11be35a1SLionel Sambuc 	u_int8_t *p1 = dst, *p2 = src, *netmask = mask;
74*11be35a1SLionel Sambuc 	u_int8_t bitmask;
75*11be35a1SLionel Sambuc 
76*11be35a1SLionel Sambuc 	for (i = 0; i < bytelen; i++) {
77*11be35a1SLionel Sambuc 		for (j = 0; j < 8; j++) {
78*11be35a1SLionel Sambuc 			bitmask = 1 << j;
79*11be35a1SLionel Sambuc 			if (!(netmask[i] & bitmask))
80*11be35a1SLionel Sambuc 				continue;
81*11be35a1SLionel Sambuc 			if ((p1[i] & bitmask) != (p2[i] & bitmask))
82*11be35a1SLionel Sambuc 				return 1;
83*11be35a1SLionel Sambuc 		}
84*11be35a1SLionel Sambuc 	}
85*11be35a1SLionel Sambuc 
86*11be35a1SLionel Sambuc 	return 0;
87*11be35a1SLionel Sambuc }
88*11be35a1SLionel Sambuc 
89*11be35a1SLionel Sambuc /*
90*11be35a1SLionel Sambuc  * Taken from ifconfig.c
91*11be35a1SLionel Sambuc  */
92*11be35a1SLionel Sambuc #ifdef INET6
93*11be35a1SLionel Sambuc static void
in6_fillscopeid(struct sockaddr_in6 * sin6)94*11be35a1SLionel Sambuc in6_fillscopeid(struct sockaddr_in6 *sin6)
95*11be35a1SLionel Sambuc {
96*11be35a1SLionel Sambuc         if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
97*11be35a1SLionel Sambuc                 sin6->sin6_scope_id =
98*11be35a1SLionel Sambuc                         ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
99*11be35a1SLionel Sambuc                 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
100*11be35a1SLionel Sambuc         }
101*11be35a1SLionel Sambuc }
102*11be35a1SLionel Sambuc #endif
103*11be35a1SLionel Sambuc 
104*11be35a1SLionel Sambuc char *
addrmerge(struct netbuf * caller,char * serv_uaddr,char * clnt_uaddr,char * netid)105*11be35a1SLionel Sambuc addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
106*11be35a1SLionel Sambuc 	  char *netid)
107*11be35a1SLionel Sambuc {
108*11be35a1SLionel Sambuc 	struct ifaddrs *ifap, *ifp, *bestif;
109*11be35a1SLionel Sambuc #ifdef INET6
110*11be35a1SLionel Sambuc 	struct sockaddr_in6 *servsin6, *sin6mask, *clntsin6, *ifsin6, *realsin6;
111*11be35a1SLionel Sambuc 	struct sockaddr_in6 *newsin6;
112*11be35a1SLionel Sambuc #endif
113*11be35a1SLionel Sambuc 	struct sockaddr_in *servsin, *sinmask, *clntsin, *newsin, *ifsin;
114*11be35a1SLionel Sambuc 	struct netbuf *serv_nbp, *clnt_nbp = NULL, tbuf;
115*11be35a1SLionel Sambuc 	struct sockaddr *serv_sa;
116*11be35a1SLionel Sambuc 	struct sockaddr *clnt_sa;
117*11be35a1SLionel Sambuc 	struct sockaddr_storage ss;
118*11be35a1SLionel Sambuc 	struct netconfig *nconf;
119*11be35a1SLionel Sambuc 	struct sockaddr *clnt = caller->buf;
120*11be35a1SLionel Sambuc 	char *ret = NULL;
121*11be35a1SLionel Sambuc 
122*11be35a1SLionel Sambuc #ifdef INET6
123*11be35a1SLionel Sambuc 	servsin6 = ifsin6 = newsin6 = NULL;	/* XXXGCC -Wuninitialized */
124*11be35a1SLionel Sambuc #endif
125*11be35a1SLionel Sambuc 	servsin = newsin = NULL;		/* XXXGCC -Wuninitialized */
126*11be35a1SLionel Sambuc 
127*11be35a1SLionel Sambuc #ifdef RPCBIND_DEBUG
128*11be35a1SLionel Sambuc 	if (debugging)
129*11be35a1SLionel Sambuc 		fprintf(stderr, "addrmerge(caller, %s, %s, %s\n", serv_uaddr,
130*11be35a1SLionel Sambuc 		    clnt_uaddr, netid);
131*11be35a1SLionel Sambuc #endif
132*11be35a1SLionel Sambuc 	nconf = getnetconfigent(netid);
133*11be35a1SLionel Sambuc 	if (nconf == NULL)
134*11be35a1SLionel Sambuc 		return NULL;
135*11be35a1SLionel Sambuc 
136*11be35a1SLionel Sambuc 	/*
137*11be35a1SLionel Sambuc 	 * Local merge, just return a duplicate.
138*11be35a1SLionel Sambuc 	 */
139*11be35a1SLionel Sambuc 	if (clnt_uaddr != NULL && strncmp(clnt_uaddr, "0.0.0.0.", 8) == 0)
140*11be35a1SLionel Sambuc 		return strdup(clnt_uaddr);
141*11be35a1SLionel Sambuc 
142*11be35a1SLionel Sambuc 	serv_nbp = uaddr2taddr(nconf, serv_uaddr);
143*11be35a1SLionel Sambuc 	if (serv_nbp == NULL)
144*11be35a1SLionel Sambuc 		return NULL;
145*11be35a1SLionel Sambuc 
146*11be35a1SLionel Sambuc 	serv_sa = (struct sockaddr *)serv_nbp->buf;
147*11be35a1SLionel Sambuc 	if (clnt_uaddr != NULL) {
148*11be35a1SLionel Sambuc 		clnt_nbp = uaddr2taddr(nconf, clnt_uaddr);
149*11be35a1SLionel Sambuc 		if (clnt_nbp == NULL) {
150*11be35a1SLionel Sambuc 			free(serv_nbp);
151*11be35a1SLionel Sambuc 			return NULL;
152*11be35a1SLionel Sambuc 		}
153*11be35a1SLionel Sambuc 		clnt_sa = (struct sockaddr *)clnt_nbp->buf;
154*11be35a1SLionel Sambuc 		if (clnt_sa->sa_family == AF_LOCAL) {
155*11be35a1SLionel Sambuc 			free(serv_nbp);
156*11be35a1SLionel Sambuc 			free(clnt_nbp);
157*11be35a1SLionel Sambuc 			free(clnt_sa);
158*11be35a1SLionel Sambuc 			return strdup(serv_uaddr);
159*11be35a1SLionel Sambuc 		}
160*11be35a1SLionel Sambuc 	} else {
161*11be35a1SLionel Sambuc 		clnt_sa = (struct sockaddr *)
162*11be35a1SLionel Sambuc 		    malloc(sizeof (struct sockaddr_storage));
163*11be35a1SLionel Sambuc 		memcpy(clnt_sa, clnt, clnt->sa_len);
164*11be35a1SLionel Sambuc 	}
165*11be35a1SLionel Sambuc 
166*11be35a1SLionel Sambuc 	if (getifaddrs(&ifp) < 0) {
167*11be35a1SLionel Sambuc 		free(serv_nbp);
168*11be35a1SLionel Sambuc 		free(clnt_sa);
169*11be35a1SLionel Sambuc 		if (clnt_nbp != NULL)
170*11be35a1SLionel Sambuc 			free(clnt_nbp);
171*11be35a1SLionel Sambuc 		return 0;
172*11be35a1SLionel Sambuc 	}
173*11be35a1SLionel Sambuc 
174*11be35a1SLionel Sambuc 	/*
175*11be35a1SLionel Sambuc 	 * Loop through all interfaces. For each interface, see if the
176*11be35a1SLionel Sambuc 	 * network portion of its address is equal to that of the client.
177*11be35a1SLionel Sambuc 	 * If so, we have found the interface that we want to use.
178*11be35a1SLionel Sambuc 	 */
179*11be35a1SLionel Sambuc 	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
180*11be35a1SLionel Sambuc 		if (ifap->ifa_addr->sa_family != clnt->sa_family ||
181*11be35a1SLionel Sambuc 		    !(ifap->ifa_flags & IFF_UP))
182*11be35a1SLionel Sambuc 			continue;
183*11be35a1SLionel Sambuc 
184*11be35a1SLionel Sambuc 		switch (clnt->sa_family) {
185*11be35a1SLionel Sambuc 		case AF_INET:
186*11be35a1SLionel Sambuc 			/*
187*11be35a1SLionel Sambuc 			 * realsin: address that recvfrom gave us.
188*11be35a1SLionel Sambuc 			 * ifsin: address of interface being examined.
189*11be35a1SLionel Sambuc 			 * clntsin: address that client want us to contact
190*11be35a1SLionel Sambuc 			 *           it on
191*11be35a1SLionel Sambuc 			 * servsin: local address of RPC service.
192*11be35a1SLionel Sambuc 			 * sinmask: netmask of this interface
193*11be35a1SLionel Sambuc 			 * newsin: initially a copy of clntsin, eventually
194*11be35a1SLionel Sambuc 			 *         the merged address
195*11be35a1SLionel Sambuc 			 */
196*11be35a1SLionel Sambuc 			servsin = (struct sockaddr_in *)serv_sa;
197*11be35a1SLionel Sambuc 			clntsin = (struct sockaddr_in *)clnt_sa;
198*11be35a1SLionel Sambuc 			sinmask = (struct sockaddr_in *)ifap->ifa_netmask;
199*11be35a1SLionel Sambuc 			newsin = (struct sockaddr_in *)&ss;
200*11be35a1SLionel Sambuc 			ifsin = (struct sockaddr_in *)ifap->ifa_addr;
201*11be35a1SLionel Sambuc 			if (!bitmaskcmp(&ifsin->sin_addr, &clntsin->sin_addr,
202*11be35a1SLionel Sambuc 			    &sinmask->sin_addr, sizeof (struct in_addr))) {
203*11be35a1SLionel Sambuc 				goto found;
204*11be35a1SLionel Sambuc 			}
205*11be35a1SLionel Sambuc 			break;
206*11be35a1SLionel Sambuc #ifdef INET6
207*11be35a1SLionel Sambuc 		case AF_INET6:
208*11be35a1SLionel Sambuc 			/*
209*11be35a1SLionel Sambuc 			 * realsin6: address that recvfrom gave us.
210*11be35a1SLionel Sambuc 			 * ifsin6: address of interface being examined.
211*11be35a1SLionel Sambuc 			 * clntsin6: address that client want us to contact
212*11be35a1SLionel Sambuc 			 *           it on
213*11be35a1SLionel Sambuc 			 * servsin6: local address of RPC service.
214*11be35a1SLionel Sambuc 			 * sin6mask: netmask of this interface
215*11be35a1SLionel Sambuc 			 * newsin6: initially a copy of clntsin, eventually
216*11be35a1SLionel Sambuc 			 *          the merged address
217*11be35a1SLionel Sambuc 			 *
218*11be35a1SLionel Sambuc 			 * For v6 link local addresses, if the client contacted
219*11be35a1SLionel Sambuc 			 * us via a link-local address, and wants us to reply
220*11be35a1SLionel Sambuc 			 * to one, use the scope id to see which one.
221*11be35a1SLionel Sambuc 			 */
222*11be35a1SLionel Sambuc 			realsin6 = (struct sockaddr_in6 *)clnt;
223*11be35a1SLionel Sambuc 			ifsin6 = (struct sockaddr_in6 *)ifap->ifa_addr;
224*11be35a1SLionel Sambuc 			in6_fillscopeid(ifsin6);
225*11be35a1SLionel Sambuc 			clntsin6 = (struct sockaddr_in6 *)clnt_sa;
226*11be35a1SLionel Sambuc 			servsin6 = (struct sockaddr_in6 *)serv_sa;
227*11be35a1SLionel Sambuc 			sin6mask = (struct sockaddr_in6 *)ifap->ifa_netmask;
228*11be35a1SLionel Sambuc 			newsin6 = (struct sockaddr_in6 *)&ss;
229*11be35a1SLionel Sambuc 			if (IN6_IS_ADDR_LINKLOCAL(&ifsin6->sin6_addr) &&
230*11be35a1SLionel Sambuc 			    IN6_IS_ADDR_LINKLOCAL(&realsin6->sin6_addr) &&
231*11be35a1SLionel Sambuc 			    IN6_IS_ADDR_LINKLOCAL(&clntsin6->sin6_addr)) {
232*11be35a1SLionel Sambuc 				if (ifsin6->sin6_scope_id !=
233*11be35a1SLionel Sambuc 				    realsin6->sin6_scope_id)
234*11be35a1SLionel Sambuc 					continue;
235*11be35a1SLionel Sambuc 				goto found;
236*11be35a1SLionel Sambuc 			}
237*11be35a1SLionel Sambuc 			if (!bitmaskcmp(&ifsin6->sin6_addr,
238*11be35a1SLionel Sambuc 			    &clntsin6->sin6_addr, &sin6mask->sin6_addr,
239*11be35a1SLionel Sambuc 			    sizeof (struct in6_addr)))
240*11be35a1SLionel Sambuc 				goto found;
241*11be35a1SLionel Sambuc 			break;
242*11be35a1SLionel Sambuc #endif
243*11be35a1SLionel Sambuc 		default:
244*11be35a1SLionel Sambuc 			goto freeit;
245*11be35a1SLionel Sambuc 		}
246*11be35a1SLionel Sambuc 	}
247*11be35a1SLionel Sambuc 	/*
248*11be35a1SLionel Sambuc 	 * Didn't find anything. Get the first possibly useful interface,
249*11be35a1SLionel Sambuc 	 * preferring "normal" interfaces to point-to-point and loopback
250*11be35a1SLionel Sambuc 	 * ones.
251*11be35a1SLionel Sambuc 	 */
252*11be35a1SLionel Sambuc 	bestif = NULL;
253*11be35a1SLionel Sambuc 	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
254*11be35a1SLionel Sambuc 		if (ifap->ifa_addr->sa_family != clnt->sa_family ||
255*11be35a1SLionel Sambuc 		    !(ifap->ifa_flags & IFF_UP))
256*11be35a1SLionel Sambuc 			continue;
257*11be35a1SLionel Sambuc 		if (!(ifap->ifa_flags & IFF_LOOPBACK) &&
258*11be35a1SLionel Sambuc 		    !(ifap->ifa_flags & IFF_POINTOPOINT)) {
259*11be35a1SLionel Sambuc 			bestif = ifap;
260*11be35a1SLionel Sambuc 			break;
261*11be35a1SLionel Sambuc 		}
262*11be35a1SLionel Sambuc 		if (bestif == NULL)
263*11be35a1SLionel Sambuc 			bestif = ifap;
264*11be35a1SLionel Sambuc 		else if ((bestif->ifa_flags & IFF_LOOPBACK) &&
265*11be35a1SLionel Sambuc 		    !(ifap->ifa_flags & IFF_LOOPBACK))
266*11be35a1SLionel Sambuc 			bestif = ifap;
267*11be35a1SLionel Sambuc 	}
268*11be35a1SLionel Sambuc 	ifap = bestif;
269*11be35a1SLionel Sambuc found:
270*11be35a1SLionel Sambuc 	switch (clnt->sa_family) {
271*11be35a1SLionel Sambuc 	case AF_INET:
272*11be35a1SLionel Sambuc 		memcpy(newsin, ifap->ifa_addr, clnt_sa->sa_len);
273*11be35a1SLionel Sambuc 		newsin->sin_port = servsin->sin_port;
274*11be35a1SLionel Sambuc 		tbuf.len = clnt_sa->sa_len;
275*11be35a1SLionel Sambuc 		tbuf.maxlen = sizeof (struct sockaddr_storage);
276*11be35a1SLionel Sambuc 		tbuf.buf = newsin;
277*11be35a1SLionel Sambuc 		break;
278*11be35a1SLionel Sambuc #ifdef INET6
279*11be35a1SLionel Sambuc 	case AF_INET6:
280*11be35a1SLionel Sambuc 		assert(newsin6);
281*11be35a1SLionel Sambuc 		memcpy(newsin6, ifsin6, clnt_sa->sa_len);
282*11be35a1SLionel Sambuc 		newsin6->sin6_port = servsin6->sin6_port;
283*11be35a1SLionel Sambuc 		tbuf.maxlen = sizeof (struct sockaddr_storage);
284*11be35a1SLionel Sambuc 		tbuf.len = clnt_sa->sa_len;
285*11be35a1SLionel Sambuc 		tbuf.buf = newsin6;
286*11be35a1SLionel Sambuc 		break;
287*11be35a1SLionel Sambuc #endif
288*11be35a1SLionel Sambuc 	default:
289*11be35a1SLionel Sambuc 		goto freeit;
290*11be35a1SLionel Sambuc 	}
291*11be35a1SLionel Sambuc 	if (ifap != NULL)
292*11be35a1SLionel Sambuc 		ret = taddr2uaddr(nconf, &tbuf);
293*11be35a1SLionel Sambuc freeit:
294*11be35a1SLionel Sambuc 	freenetconfigent(nconf);
295*11be35a1SLionel Sambuc 	free(serv_sa);
296*11be35a1SLionel Sambuc 	free(serv_nbp);
297*11be35a1SLionel Sambuc 	if (clnt_sa != NULL)
298*11be35a1SLionel Sambuc 		free(clnt_sa);
299*11be35a1SLionel Sambuc 	if (clnt_nbp != NULL)
300*11be35a1SLionel Sambuc 		free(clnt_nbp);
301*11be35a1SLionel Sambuc 	freeifaddrs(ifp);
302*11be35a1SLionel Sambuc 
303*11be35a1SLionel Sambuc #ifdef RPCBIND_DEBUG
304*11be35a1SLionel Sambuc 	if (debugging)
305*11be35a1SLionel Sambuc 		fprintf(stderr, "addrmerge: returning %s\n", ret);
306*11be35a1SLionel Sambuc #endif
307*11be35a1SLionel Sambuc 	return ret;
308*11be35a1SLionel Sambuc }
309*11be35a1SLionel Sambuc 
310*11be35a1SLionel Sambuc void
network_init()311*11be35a1SLionel Sambuc network_init()
312*11be35a1SLionel Sambuc {
313*11be35a1SLionel Sambuc #ifdef INET6
314*11be35a1SLionel Sambuc 	struct ifaddrs *ifap, *ifp;
315*11be35a1SLionel Sambuc 	struct ipv6_mreq mreq6;
316*11be35a1SLionel Sambuc 	int ifindex, s;
317*11be35a1SLionel Sambuc #endif
318*11be35a1SLionel Sambuc 	int ecode;
319*11be35a1SLionel Sambuc 	struct addrinfo hints, *res;
320*11be35a1SLionel Sambuc 
321*11be35a1SLionel Sambuc 	memset(&hints, 0, sizeof hints);
322*11be35a1SLionel Sambuc 	hints.ai_family = AF_INET;
323*11be35a1SLionel Sambuc 	if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) {
324*11be35a1SLionel Sambuc 		if (debugging)
325*11be35a1SLionel Sambuc 			fprintf(stderr, "can't get local ip4 address: %s\n",
326*11be35a1SLionel Sambuc 			    gai_strerror(ecode));
327*11be35a1SLionel Sambuc 	} else {
328*11be35a1SLionel Sambuc 		local_in4 = (struct sockaddr_in *)malloc(sizeof *local_in4);
329*11be35a1SLionel Sambuc 		if (local_in4 == NULL) {
330*11be35a1SLionel Sambuc 			if (debugging)
331*11be35a1SLionel Sambuc 				fprintf(stderr, "can't alloc local ip4 addr\n");
332*11be35a1SLionel Sambuc 		}
333*11be35a1SLionel Sambuc 		memcpy(local_in4, res->ai_addr, sizeof *local_in4);
334*11be35a1SLionel Sambuc 	}
335*11be35a1SLionel Sambuc 
336*11be35a1SLionel Sambuc #ifdef INET6
337*11be35a1SLionel Sambuc 	hints.ai_family = AF_INET6;
338*11be35a1SLionel Sambuc 	if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) {
339*11be35a1SLionel Sambuc 		if (debugging)
340*11be35a1SLionel Sambuc 			fprintf(stderr, "can't get local ip6 address: %s\n",
341*11be35a1SLionel Sambuc 			    gai_strerror(ecode));
342*11be35a1SLionel Sambuc 	} else {
343*11be35a1SLionel Sambuc 		local_in6 = (struct sockaddr_in6 *)malloc(sizeof *local_in6);
344*11be35a1SLionel Sambuc 		if (local_in6 == NULL) {
345*11be35a1SLionel Sambuc 			if (debugging)
346*11be35a1SLionel Sambuc 				fprintf(stderr, "can't alloc local ip6 addr\n");
347*11be35a1SLionel Sambuc 		}
348*11be35a1SLionel Sambuc 		memcpy(local_in6, res->ai_addr, sizeof *local_in6);
349*11be35a1SLionel Sambuc 	}
350*11be35a1SLionel Sambuc 
351*11be35a1SLionel Sambuc 	/*
352*11be35a1SLionel Sambuc 	 * Now join the RPC ipv6 multicast group on all interfaces.
353*11be35a1SLionel Sambuc 	 */
354*11be35a1SLionel Sambuc 	if (getifaddrs(&ifp) < 0)
355*11be35a1SLionel Sambuc 		return;
356*11be35a1SLionel Sambuc 
357*11be35a1SLionel Sambuc 	mreq6.ipv6mr_interface = 0;
358*11be35a1SLionel Sambuc 	inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, &mreq6.ipv6mr_multiaddr);
359*11be35a1SLionel Sambuc 
360*11be35a1SLionel Sambuc 	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
361*11be35a1SLionel Sambuc 
362*11be35a1SLionel Sambuc 	/*
363*11be35a1SLionel Sambuc 	 * Loop through all interfaces. For each interface, see if the
364*11be35a1SLionel Sambuc 	 * network portion of its address is equal to that of the client.
365*11be35a1SLionel Sambuc 	 * If so, we have found the interface that we want to use.
366*11be35a1SLionel Sambuc 	 */
367*11be35a1SLionel Sambuc 	for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
368*11be35a1SLionel Sambuc 		if (ifap->ifa_addr->sa_family != AF_INET6 ||
369*11be35a1SLionel Sambuc 		    !(ifap->ifa_flags & IFF_MULTICAST))
370*11be35a1SLionel Sambuc 			continue;
371*11be35a1SLionel Sambuc 		ifindex = if_nametoindex(ifap->ifa_name);
372*11be35a1SLionel Sambuc 		if (ifindex == mreq6.ipv6mr_interface)
373*11be35a1SLionel Sambuc 			/*
374*11be35a1SLionel Sambuc 			 * Already did this one.
375*11be35a1SLionel Sambuc 			 */
376*11be35a1SLionel Sambuc 			continue;
377*11be35a1SLionel Sambuc 		mreq6.ipv6mr_interface = ifindex;
378*11be35a1SLionel Sambuc 		if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
379*11be35a1SLionel Sambuc 		    sizeof mreq6) < 0)
380*11be35a1SLionel Sambuc 			if (debugging)
381*11be35a1SLionel Sambuc 				warn("setsockopt v6 multicast");
382*11be35a1SLionel Sambuc 	}
383*11be35a1SLionel Sambuc #endif
384*11be35a1SLionel Sambuc 
385*11be35a1SLionel Sambuc 	/* close(s); */
386*11be35a1SLionel Sambuc }
387*11be35a1SLionel Sambuc 
388*11be35a1SLionel Sambuc struct sockaddr *
local_sa(int af)389*11be35a1SLionel Sambuc local_sa(int af)
390*11be35a1SLionel Sambuc {
391*11be35a1SLionel Sambuc 	switch (af) {
392*11be35a1SLionel Sambuc 	case AF_INET:
393*11be35a1SLionel Sambuc 		return (struct sockaddr *)local_in4;
394*11be35a1SLionel Sambuc #ifdef INET6
395*11be35a1SLionel Sambuc 	case AF_INET6:
396*11be35a1SLionel Sambuc 		return (struct sockaddr *)local_in6;
397*11be35a1SLionel Sambuc #endif
398*11be35a1SLionel Sambuc 	default:
399*11be35a1SLionel Sambuc 		return NULL;
400*11be35a1SLionel Sambuc 	}
401*11be35a1SLionel Sambuc }
402