186d7f5d3SJohn Marino /*-
286d7f5d3SJohn Marino * Copyright (c) 2000 The NetBSD Foundation, Inc.
386d7f5d3SJohn Marino * All rights reserved.
486d7f5d3SJohn Marino *
586d7f5d3SJohn Marino * This code is derived from software contributed to The NetBSD Foundation
686d7f5d3SJohn Marino * by Frank van der Linden.
786d7f5d3SJohn Marino *
886d7f5d3SJohn Marino * Redistribution and use in source and binary forms, with or without
986d7f5d3SJohn Marino * modification, are permitted provided that the following conditions
1086d7f5d3SJohn Marino * are met:
1186d7f5d3SJohn Marino * 1. Redistributions of source code must retain the above copyright
1286d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer.
1386d7f5d3SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
1486d7f5d3SJohn Marino * notice, this list of conditions and the following disclaimer in the
1586d7f5d3SJohn Marino * documentation and/or other materials provided with the distribution.
1686d7f5d3SJohn Marino * 3. All advertising materials mentioning features or use of this software
1786d7f5d3SJohn Marino * must display the following acknowledgement:
1886d7f5d3SJohn Marino * This product includes software developed by the NetBSD
1986d7f5d3SJohn Marino * Foundation, Inc. and its contributors.
2086d7f5d3SJohn Marino * 4. Neither the name of The NetBSD Foundation nor the names of its
2186d7f5d3SJohn Marino * contributors may be used to endorse or promote products derived
2286d7f5d3SJohn Marino * from this software without specific prior written permission.
2386d7f5d3SJohn Marino *
2486d7f5d3SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2586d7f5d3SJohn Marino * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2686d7f5d3SJohn Marino * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2786d7f5d3SJohn Marino * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2886d7f5d3SJohn Marino * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2986d7f5d3SJohn Marino * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3086d7f5d3SJohn Marino * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3186d7f5d3SJohn Marino * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3286d7f5d3SJohn Marino * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3386d7f5d3SJohn Marino * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3486d7f5d3SJohn Marino * POSSIBILITY OF SUCH DAMAGE.
3586d7f5d3SJohn Marino *
3686d7f5d3SJohn Marino * $NetBSD: util.c,v 1.4 2000/08/03 00:04:30 fvdl Exp $
3786d7f5d3SJohn Marino * $FreeBSD: src/usr.sbin/rpcbind/util.c,v 1.6 2007/11/07 10:53:39 kevlo Exp $
3886d7f5d3SJohn Marino */
3986d7f5d3SJohn Marino
4086d7f5d3SJohn Marino #include <sys/types.h>
4186d7f5d3SJohn Marino #include <sys/socket.h>
4286d7f5d3SJohn Marino #include <sys/queue.h>
4386d7f5d3SJohn Marino #include <net/if.h>
4486d7f5d3SJohn Marino #include <netinet/in.h>
4586d7f5d3SJohn Marino #include <ifaddrs.h>
4686d7f5d3SJohn Marino #include <sys/poll.h>
4786d7f5d3SJohn Marino #include <rpc/rpc.h>
4886d7f5d3SJohn Marino #include <errno.h>
4986d7f5d3SJohn Marino #include <stdlib.h>
5086d7f5d3SJohn Marino #include <string.h>
5186d7f5d3SJohn Marino #include <unistd.h>
5286d7f5d3SJohn Marino #include <netdb.h>
5386d7f5d3SJohn Marino #include <netconfig.h>
5486d7f5d3SJohn Marino #include <stdio.h>
5586d7f5d3SJohn Marino #include <arpa/inet.h>
5686d7f5d3SJohn Marino
5786d7f5d3SJohn Marino #include "rpcbind.h"
5886d7f5d3SJohn Marino
5986d7f5d3SJohn Marino #define SA2SIN(sa) ((struct sockaddr_in *)(sa))
6086d7f5d3SJohn Marino #define SA2SINADDR(sa) (SA2SIN(sa)->sin_addr)
6186d7f5d3SJohn Marino #ifdef INET6
6286d7f5d3SJohn Marino #define SA2SIN6(sa) ((struct sockaddr_in6 *)(sa))
6386d7f5d3SJohn Marino #define SA2SIN6ADDR(sa) (SA2SIN6(sa)->sin6_addr)
6486d7f5d3SJohn Marino #endif
6586d7f5d3SJohn Marino
6686d7f5d3SJohn Marino static struct sockaddr_in *local_in4;
6786d7f5d3SJohn Marino #ifdef INET6
6886d7f5d3SJohn Marino static struct sockaddr_in6 *local_in6;
6986d7f5d3SJohn Marino #endif
7086d7f5d3SJohn Marino
7186d7f5d3SJohn Marino static int bitmaskcmp(void *, void *, void *, int);
7286d7f5d3SJohn Marino #ifdef INET6
7386d7f5d3SJohn Marino static void in6_fillscopeid(struct sockaddr_in6 *);
7486d7f5d3SJohn Marino #endif
7586d7f5d3SJohn Marino
7686d7f5d3SJohn Marino /*
7786d7f5d3SJohn Marino * For all bits set in "mask", compare the corresponding bits in
7886d7f5d3SJohn Marino * "dst" and "src", and see if they match. Returns 0 if the addresses
7986d7f5d3SJohn Marino * match.
8086d7f5d3SJohn Marino */
8186d7f5d3SJohn Marino static int
bitmaskcmp(void * dst,void * src,void * mask,int bytelen)8286d7f5d3SJohn Marino bitmaskcmp(void *dst, void *src, void *mask, int bytelen)
8386d7f5d3SJohn Marino {
8486d7f5d3SJohn Marino int i;
8586d7f5d3SJohn Marino u_int8_t *p1 = dst, *p2 = src, *netmask = mask;
8686d7f5d3SJohn Marino
8786d7f5d3SJohn Marino for (i = 0; i < bytelen; i++)
8886d7f5d3SJohn Marino if ((p1[i] & netmask[i]) != (p2[i] & netmask[i]))
8986d7f5d3SJohn Marino return (1);
9086d7f5d3SJohn Marino return (0);
9186d7f5d3SJohn Marino }
9286d7f5d3SJohn Marino
9386d7f5d3SJohn Marino /*
9486d7f5d3SJohn Marino * Similar to code in ifconfig.c. Fill in the scope ID for link-local
9586d7f5d3SJohn Marino * addresses returned by getifaddrs().
9686d7f5d3SJohn Marino */
9786d7f5d3SJohn Marino #ifdef INET6
9886d7f5d3SJohn Marino static void
in6_fillscopeid(struct sockaddr_in6 * sin6)9986d7f5d3SJohn Marino in6_fillscopeid(struct sockaddr_in6 *sin6)
10086d7f5d3SJohn Marino {
10186d7f5d3SJohn Marino u_int16_t ifindex;
10286d7f5d3SJohn Marino
10386d7f5d3SJohn Marino if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
10486d7f5d3SJohn Marino ifindex = ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
10586d7f5d3SJohn Marino if (sin6->sin6_scope_id == 0 && ifindex != 0) {
10686d7f5d3SJohn Marino sin6->sin6_scope_id = ifindex;
10786d7f5d3SJohn Marino *(u_int16_t *)&sin6->sin6_addr.s6_addr[2] = 0;
10886d7f5d3SJohn Marino }
10986d7f5d3SJohn Marino }
11086d7f5d3SJohn Marino }
11186d7f5d3SJohn Marino #endif
11286d7f5d3SJohn Marino
11386d7f5d3SJohn Marino /*
11486d7f5d3SJohn Marino * Find a server address that can be used by `caller' to contact
11586d7f5d3SJohn Marino * the local service specified by `serv_uaddr'. If `clnt_uaddr' is
11686d7f5d3SJohn Marino * non-NULL, it is used instead of `caller' as a hint suggesting
11786d7f5d3SJohn Marino * the best address (e.g. the `r_addr' field of an rpc, which
11886d7f5d3SJohn Marino * contains the rpcbind server address that the caller used).
11986d7f5d3SJohn Marino *
12086d7f5d3SJohn Marino * Returns the best server address as a malloc'd "universal address"
12186d7f5d3SJohn Marino * string which should be freed by the caller. On error, returns NULL.
12286d7f5d3SJohn Marino */
12386d7f5d3SJohn Marino char *
addrmerge(struct netbuf * caller,char * serv_uaddr,char * clnt_uaddr,char * netid)12486d7f5d3SJohn Marino addrmerge(struct netbuf *caller, char *serv_uaddr, char *clnt_uaddr,
12586d7f5d3SJohn Marino char *netid)
12686d7f5d3SJohn Marino {
12786d7f5d3SJohn Marino struct ifaddrs *ifap, *ifp = NULL, *bestif;
12886d7f5d3SJohn Marino struct netbuf *serv_nbp = NULL, *hint_nbp = NULL, tbuf;
12986d7f5d3SJohn Marino struct sockaddr *caller_sa, *hint_sa, *ifsa, *ifmasksa, *serv_sa;
13086d7f5d3SJohn Marino struct sockaddr_storage ss;
13186d7f5d3SJohn Marino struct netconfig *nconf;
13286d7f5d3SJohn Marino char *caller_uaddr = NULL, *hint_uaddr = NULL;
13386d7f5d3SJohn Marino char *ret = NULL;
13486d7f5d3SJohn Marino
13586d7f5d3SJohn Marino #ifdef ND_DEBUG
13686d7f5d3SJohn Marino if (debugging)
13786d7f5d3SJohn Marino fprintf(stderr, "addrmerge(caller, %s, %s, %s\n", serv_uaddr,
13886d7f5d3SJohn Marino clnt_uaddr == NULL ? "NULL" : clnt_uaddr, netid);
13986d7f5d3SJohn Marino #endif
14086d7f5d3SJohn Marino caller_sa = caller->buf;
14186d7f5d3SJohn Marino if ((nconf = rpcbind_get_conf(netid)) == NULL)
14286d7f5d3SJohn Marino goto freeit;
14386d7f5d3SJohn Marino if ((caller_uaddr = taddr2uaddr(nconf, caller)) == NULL)
14486d7f5d3SJohn Marino goto freeit;
14586d7f5d3SJohn Marino
14686d7f5d3SJohn Marino /*
14786d7f5d3SJohn Marino * Use `clnt_uaddr' as the hint if non-NULL, but ignore it if its
14886d7f5d3SJohn Marino * address family is different from that of the caller.
14986d7f5d3SJohn Marino */
15086d7f5d3SJohn Marino hint_sa = NULL;
15186d7f5d3SJohn Marino if (clnt_uaddr != NULL) {
15286d7f5d3SJohn Marino hint_uaddr = clnt_uaddr;
15386d7f5d3SJohn Marino if ((hint_nbp = uaddr2taddr(nconf, clnt_uaddr)) == NULL)
15486d7f5d3SJohn Marino goto freeit;
15586d7f5d3SJohn Marino hint_sa = hint_nbp->buf;
15686d7f5d3SJohn Marino }
15786d7f5d3SJohn Marino if (hint_sa == NULL || hint_sa->sa_family != caller_sa->sa_family) {
15886d7f5d3SJohn Marino hint_uaddr = caller_uaddr;
15986d7f5d3SJohn Marino hint_sa = caller->buf;
16086d7f5d3SJohn Marino }
16186d7f5d3SJohn Marino
16286d7f5d3SJohn Marino #ifdef ND_DEBUG
16386d7f5d3SJohn Marino if (debugging)
16486d7f5d3SJohn Marino fprintf(stderr, "addrmerge: hint %s\n", hint_uaddr);
16586d7f5d3SJohn Marino #endif
16686d7f5d3SJohn Marino /* Local caller, just return the server address. */
16786d7f5d3SJohn Marino if (strncmp(caller_uaddr, "0.0.0.0.", 8) == 0 ||
16886d7f5d3SJohn Marino strncmp(caller_uaddr, "::.", 3) == 0 || caller_uaddr[0] == '/') {
16986d7f5d3SJohn Marino ret = strdup(serv_uaddr);
17086d7f5d3SJohn Marino goto freeit;
17186d7f5d3SJohn Marino }
17286d7f5d3SJohn Marino
17386d7f5d3SJohn Marino if (getifaddrs(&ifp) < 0)
17486d7f5d3SJohn Marino goto freeit;
17586d7f5d3SJohn Marino
17686d7f5d3SJohn Marino /*
17786d7f5d3SJohn Marino * Loop through all interfaces. For each interface, see if the
17886d7f5d3SJohn Marino * network portion of its address is equal to that of the client.
17986d7f5d3SJohn Marino * If so, we have found the interface that we want to use.
18086d7f5d3SJohn Marino */
18186d7f5d3SJohn Marino bestif = NULL;
18286d7f5d3SJohn Marino for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
18386d7f5d3SJohn Marino ifsa = ifap->ifa_addr;
18486d7f5d3SJohn Marino ifmasksa = ifap->ifa_netmask;
18586d7f5d3SJohn Marino
18686d7f5d3SJohn Marino if (ifsa == NULL || ifsa->sa_family != hint_sa->sa_family ||
18786d7f5d3SJohn Marino !(ifap->ifa_flags & IFF_UP))
18886d7f5d3SJohn Marino continue;
18986d7f5d3SJohn Marino
19086d7f5d3SJohn Marino switch (hint_sa->sa_family) {
19186d7f5d3SJohn Marino case AF_INET:
19286d7f5d3SJohn Marino /*
19386d7f5d3SJohn Marino * If the hint address matches this interface
19486d7f5d3SJohn Marino * address/netmask, then we're done.
19586d7f5d3SJohn Marino */
19686d7f5d3SJohn Marino if (!bitmaskcmp(&SA2SINADDR(ifsa),
19786d7f5d3SJohn Marino &SA2SINADDR(hint_sa), &SA2SINADDR(ifmasksa),
19886d7f5d3SJohn Marino sizeof(struct in_addr))) {
19986d7f5d3SJohn Marino bestif = ifap;
20086d7f5d3SJohn Marino goto found;
20186d7f5d3SJohn Marino }
20286d7f5d3SJohn Marino break;
20386d7f5d3SJohn Marino #ifdef INET6
20486d7f5d3SJohn Marino case AF_INET6:
20586d7f5d3SJohn Marino /*
20686d7f5d3SJohn Marino * For v6 link local addresses, if the caller is on
20786d7f5d3SJohn Marino * a link-local address then use the scope id to see
20886d7f5d3SJohn Marino * which one.
20986d7f5d3SJohn Marino */
21086d7f5d3SJohn Marino in6_fillscopeid(SA2SIN6(ifsa));
21186d7f5d3SJohn Marino if (IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(ifsa)) &&
21286d7f5d3SJohn Marino IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(caller_sa)) &&
21386d7f5d3SJohn Marino IN6_IS_ADDR_LINKLOCAL(&SA2SIN6ADDR(hint_sa))) {
21486d7f5d3SJohn Marino if (SA2SIN6(ifsa)->sin6_scope_id ==
21586d7f5d3SJohn Marino SA2SIN6(caller_sa)->sin6_scope_id) {
21686d7f5d3SJohn Marino bestif = ifap;
21786d7f5d3SJohn Marino goto found;
21886d7f5d3SJohn Marino }
21986d7f5d3SJohn Marino } else if (!bitmaskcmp(&SA2SIN6ADDR(ifsa),
22086d7f5d3SJohn Marino &SA2SIN6ADDR(hint_sa), &SA2SIN6ADDR(ifmasksa),
22186d7f5d3SJohn Marino sizeof(struct in6_addr))) {
22286d7f5d3SJohn Marino bestif = ifap;
22386d7f5d3SJohn Marino goto found;
22486d7f5d3SJohn Marino }
22586d7f5d3SJohn Marino break;
22686d7f5d3SJohn Marino #endif
22786d7f5d3SJohn Marino default:
22886d7f5d3SJohn Marino continue;
22986d7f5d3SJohn Marino }
23086d7f5d3SJohn Marino
23186d7f5d3SJohn Marino /*
23286d7f5d3SJohn Marino * Remember the first possibly useful interface, preferring
23386d7f5d3SJohn Marino * "normal" to point-to-point and loopback ones.
23486d7f5d3SJohn Marino */
23586d7f5d3SJohn Marino if (bestif == NULL ||
23686d7f5d3SJohn Marino (!(ifap->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) &&
23786d7f5d3SJohn Marino (bestif->ifa_flags & (IFF_LOOPBACK | IFF_POINTOPOINT))))
23886d7f5d3SJohn Marino bestif = ifap;
23986d7f5d3SJohn Marino }
24086d7f5d3SJohn Marino if (bestif == NULL)
24186d7f5d3SJohn Marino goto freeit;
24286d7f5d3SJohn Marino
24386d7f5d3SJohn Marino found:
24486d7f5d3SJohn Marino /*
24586d7f5d3SJohn Marino * Construct the new address using the the address from
24686d7f5d3SJohn Marino * `bestif', and the port number from `serv_uaddr'.
24786d7f5d3SJohn Marino */
24886d7f5d3SJohn Marino serv_nbp = uaddr2taddr(nconf, serv_uaddr);
24986d7f5d3SJohn Marino if (serv_nbp == NULL)
25086d7f5d3SJohn Marino goto freeit;
25186d7f5d3SJohn Marino serv_sa = serv_nbp->buf;
25286d7f5d3SJohn Marino
25386d7f5d3SJohn Marino memcpy(&ss, bestif->ifa_addr, bestif->ifa_addr->sa_len);
25486d7f5d3SJohn Marino switch (ss.ss_family) {
25586d7f5d3SJohn Marino case AF_INET:
25686d7f5d3SJohn Marino SA2SIN(&ss)->sin_port = SA2SIN(serv_sa)->sin_port;
25786d7f5d3SJohn Marino break;
25886d7f5d3SJohn Marino #ifdef INET6
25986d7f5d3SJohn Marino case AF_INET6:
26086d7f5d3SJohn Marino SA2SIN6(&ss)->sin6_port = SA2SIN6(serv_sa)->sin6_port;
26186d7f5d3SJohn Marino break;
26286d7f5d3SJohn Marino #endif
26386d7f5d3SJohn Marino }
26486d7f5d3SJohn Marino tbuf.len = ss.ss_len;
26586d7f5d3SJohn Marino tbuf.maxlen = sizeof(ss);
26686d7f5d3SJohn Marino tbuf.buf = &ss;
26786d7f5d3SJohn Marino ret = taddr2uaddr(nconf, &tbuf);
26886d7f5d3SJohn Marino
26986d7f5d3SJohn Marino freeit:
27086d7f5d3SJohn Marino if (caller_uaddr != NULL)
27186d7f5d3SJohn Marino free(caller_uaddr);
27286d7f5d3SJohn Marino if (hint_nbp != NULL) {
27386d7f5d3SJohn Marino free(hint_nbp->buf);
27486d7f5d3SJohn Marino free(hint_nbp);
27586d7f5d3SJohn Marino }
27686d7f5d3SJohn Marino if (serv_nbp != NULL) {
27786d7f5d3SJohn Marino free(serv_nbp->buf);
27886d7f5d3SJohn Marino free(serv_nbp);
27986d7f5d3SJohn Marino }
28086d7f5d3SJohn Marino if (ifp != NULL)
28186d7f5d3SJohn Marino freeifaddrs(ifp);
28286d7f5d3SJohn Marino
28386d7f5d3SJohn Marino #ifdef ND_DEBUG
28486d7f5d3SJohn Marino if (debugging)
28586d7f5d3SJohn Marino fprintf(stderr, "addrmerge: returning %s\n", ret);
28686d7f5d3SJohn Marino #endif
28786d7f5d3SJohn Marino return ret;
28886d7f5d3SJohn Marino }
28986d7f5d3SJohn Marino
29086d7f5d3SJohn Marino void
network_init(void)29186d7f5d3SJohn Marino network_init(void)
29286d7f5d3SJohn Marino {
29386d7f5d3SJohn Marino #ifdef INET6
29486d7f5d3SJohn Marino struct ifaddrs *ifap, *ifp;
29586d7f5d3SJohn Marino struct ipv6_mreq mreq6;
29686d7f5d3SJohn Marino unsigned int ifindex;
29786d7f5d3SJohn Marino int s;
29886d7f5d3SJohn Marino #endif
29986d7f5d3SJohn Marino int ecode;
30086d7f5d3SJohn Marino struct addrinfo hints, *res;
30186d7f5d3SJohn Marino
30286d7f5d3SJohn Marino memset(&hints, 0, sizeof hints);
30386d7f5d3SJohn Marino hints.ai_family = AF_INET;
30486d7f5d3SJohn Marino if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) {
30586d7f5d3SJohn Marino if (debugging)
30686d7f5d3SJohn Marino fprintf(stderr, "can't get local ip4 address: %s\n",
30786d7f5d3SJohn Marino gai_strerror(ecode));
30886d7f5d3SJohn Marino } else {
30986d7f5d3SJohn Marino local_in4 = (struct sockaddr_in *)malloc(sizeof *local_in4);
31086d7f5d3SJohn Marino if (local_in4 == NULL) {
31186d7f5d3SJohn Marino if (debugging)
31286d7f5d3SJohn Marino fprintf(stderr, "can't alloc local ip4 addr\n");
31386d7f5d3SJohn Marino }
31486d7f5d3SJohn Marino memcpy(local_in4, res->ai_addr, sizeof *local_in4);
31586d7f5d3SJohn Marino }
31686d7f5d3SJohn Marino
31786d7f5d3SJohn Marino #ifdef INET6
31886d7f5d3SJohn Marino hints.ai_family = AF_INET6;
31986d7f5d3SJohn Marino if ((ecode = getaddrinfo(NULL, "sunrpc", &hints, &res))) {
32086d7f5d3SJohn Marino if (debugging)
32186d7f5d3SJohn Marino fprintf(stderr, "can't get local ip6 address: %s\n",
32286d7f5d3SJohn Marino gai_strerror(ecode));
32386d7f5d3SJohn Marino } else {
32486d7f5d3SJohn Marino local_in6 = (struct sockaddr_in6 *)malloc(sizeof *local_in6);
32586d7f5d3SJohn Marino if (local_in6 == NULL) {
32686d7f5d3SJohn Marino if (debugging)
32786d7f5d3SJohn Marino fprintf(stderr, "can't alloc local ip6 addr\n");
32886d7f5d3SJohn Marino }
32986d7f5d3SJohn Marino memcpy(local_in6, res->ai_addr, sizeof *local_in6);
33086d7f5d3SJohn Marino }
33186d7f5d3SJohn Marino
33286d7f5d3SJohn Marino /*
33386d7f5d3SJohn Marino * Now join the RPC ipv6 multicast group on all interfaces.
33486d7f5d3SJohn Marino */
33586d7f5d3SJohn Marino if (getifaddrs(&ifp) < 0)
33686d7f5d3SJohn Marino return;
33786d7f5d3SJohn Marino
33886d7f5d3SJohn Marino mreq6.ipv6mr_interface = 0;
33986d7f5d3SJohn Marino inet_pton(AF_INET6, RPCB_MULTICAST_ADDR, &mreq6.ipv6mr_multiaddr);
34086d7f5d3SJohn Marino
34186d7f5d3SJohn Marino s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
34286d7f5d3SJohn Marino
34386d7f5d3SJohn Marino /*
34486d7f5d3SJohn Marino * Loop through all interfaces. For each IPv6 multicast-capable
34586d7f5d3SJohn Marino * interface, join the RPC multicast group on that interface.
34686d7f5d3SJohn Marino */
34786d7f5d3SJohn Marino for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
34886d7f5d3SJohn Marino if (ifap->ifa_addr->sa_family != AF_INET6 ||
34986d7f5d3SJohn Marino !(ifap->ifa_flags & IFF_MULTICAST))
35086d7f5d3SJohn Marino continue;
35186d7f5d3SJohn Marino ifindex = if_nametoindex(ifap->ifa_name);
35286d7f5d3SJohn Marino if (ifindex == mreq6.ipv6mr_interface)
35386d7f5d3SJohn Marino /*
35486d7f5d3SJohn Marino * Already did this one.
35586d7f5d3SJohn Marino */
35686d7f5d3SJohn Marino continue;
35786d7f5d3SJohn Marino mreq6.ipv6mr_interface = ifindex;
35886d7f5d3SJohn Marino if (setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6,
35986d7f5d3SJohn Marino sizeof mreq6) < 0)
36086d7f5d3SJohn Marino if (debugging)
36186d7f5d3SJohn Marino perror("setsockopt v6 multicast");
36286d7f5d3SJohn Marino }
36386d7f5d3SJohn Marino #endif
36486d7f5d3SJohn Marino
36586d7f5d3SJohn Marino /* close(s); */
36686d7f5d3SJohn Marino }
36786d7f5d3SJohn Marino
36886d7f5d3SJohn Marino struct sockaddr *
local_sa(int af)36986d7f5d3SJohn Marino local_sa(int af)
37086d7f5d3SJohn Marino {
37186d7f5d3SJohn Marino switch (af) {
37286d7f5d3SJohn Marino case AF_INET:
37386d7f5d3SJohn Marino return (struct sockaddr *)local_in4;
37486d7f5d3SJohn Marino #ifdef INET6
37586d7f5d3SJohn Marino case AF_INET6:
37686d7f5d3SJohn Marino return (struct sockaddr *)local_in6;
37786d7f5d3SJohn Marino #endif
37886d7f5d3SJohn Marino default:
37986d7f5d3SJohn Marino return NULL;
38086d7f5d3SJohn Marino }
38186d7f5d3SJohn Marino }
382