1 /* $NetBSD: util.c,v 1.2 2011/06/11 18:03:17 christos Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Frank van der Linden.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <sys/queue.h>
36 #include <netinet/in.h>
46 #include <netconfig.h>
48 #include <arpa/inet.h>
50 #include <rump/rump.h>
51 #include <rump/rump_syscalls.h>
55 static struct sockaddr_in
*local_in4
;
57 static struct sockaddr_in6
*local_in6
;
60 static int bitmaskcmp(void *, void *, void *, int);
62 static void in6_fillscopeid(struct sockaddr_in6
*);
66 * For all bits set in "mask", compare the corresponding bits in
67 * "dst" and "src", and see if they match.
70 bitmaskcmp(void *dst
, void *src
, void *mask
, int bytelen
)
73 u_int8_t
*p1
= dst
, *p2
= src
, *netmask
= mask
;
76 for (i
= 0; i
< bytelen
; i
++) {
77 for (j
= 0; j
< 8; j
++) {
79 if (!(netmask
[i
] & bitmask
))
81 if ((p1
[i
] & bitmask
) != (p2
[i
] & bitmask
))
90 * Taken from ifconfig.c
94 in6_fillscopeid(struct sockaddr_in6
*sin6
)
96 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
)) {
98 ntohs(*(u_int16_t
*)&sin6
->sin6_addr
.s6_addr
[2]);
99 sin6
->sin6_addr
.s6_addr
[2] = sin6
->sin6_addr
.s6_addr
[3] = 0;
105 addrmerge(struct netbuf
*caller
, char *serv_uaddr
, char *clnt_uaddr
,
108 struct ifaddrs
*ifap
, *ifp
, *bestif
;
110 struct sockaddr_in6
*servsin6
, *sin6mask
, *clntsin6
, *ifsin6
, *realsin6
;
111 struct sockaddr_in6
*newsin6
;
113 struct sockaddr_in
*servsin
, *sinmask
, *clntsin
, *newsin
, *ifsin
;
114 struct netbuf
*serv_nbp
, *clnt_nbp
= NULL
, tbuf
;
115 struct sockaddr
*serv_sa
;
116 struct sockaddr
*clnt_sa
;
117 struct sockaddr_storage ss
;
118 struct netconfig
*nconf
;
119 struct sockaddr
*clnt
= caller
->buf
;
123 servsin6
= ifsin6
= newsin6
= NULL
; /* XXXGCC -Wuninitialized */
125 servsin
= newsin
= NULL
; /* XXXGCC -Wuninitialized */
129 fprintf(stderr
, "addrmerge(caller, %s, %s, %s\n", serv_uaddr
,
132 nconf
= getnetconfigent(netid
);
137 * Local merge, just return a duplicate.
139 if (clnt_uaddr
!= NULL
&& strncmp(clnt_uaddr
, "0.0.0.0.", 8) == 0)
140 return strdup(clnt_uaddr
);
142 serv_nbp
= uaddr2taddr(nconf
, serv_uaddr
);
143 if (serv_nbp
== NULL
)
146 serv_sa
= (struct sockaddr
*)serv_nbp
->buf
;
147 if (clnt_uaddr
!= NULL
) {
148 clnt_nbp
= uaddr2taddr(nconf
, clnt_uaddr
);
149 if (clnt_nbp
== NULL
) {
153 clnt_sa
= (struct sockaddr
*)clnt_nbp
->buf
;
154 if (clnt_sa
->sa_family
== AF_LOCAL
) {
158 return strdup(serv_uaddr
);
161 clnt_sa
= (struct sockaddr
*)
162 malloc(sizeof (struct sockaddr_storage
));
163 memcpy(clnt_sa
, clnt
, clnt
->sa_len
);
166 if (getifaddrs(&ifp
) < 0) {
169 if (clnt_nbp
!= NULL
)
175 * Loop through all interfaces. For each interface, see if the
176 * network portion of its address is equal to that of the client.
177 * If so, we have found the interface that we want to use.
179 for (ifap
= ifp
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
180 if (ifap
->ifa_addr
->sa_family
!= clnt
->sa_family
||
181 !(ifap
->ifa_flags
& IFF_UP
))
184 switch (clnt
->sa_family
) {
187 * realsin: address that recvfrom gave us.
188 * ifsin: address of interface being examined.
189 * clntsin: address that client want us to contact
191 * servsin: local address of RPC service.
192 * sinmask: netmask of this interface
193 * newsin: initially a copy of clntsin, eventually
196 servsin
= (struct sockaddr_in
*)serv_sa
;
197 clntsin
= (struct sockaddr_in
*)clnt_sa
;
198 sinmask
= (struct sockaddr_in
*)ifap
->ifa_netmask
;
199 newsin
= (struct sockaddr_in
*)&ss
;
200 ifsin
= (struct sockaddr_in
*)ifap
->ifa_addr
;
201 if (!bitmaskcmp(&ifsin
->sin_addr
, &clntsin
->sin_addr
,
202 &sinmask
->sin_addr
, sizeof (struct in_addr
))) {
209 * realsin6: address that recvfrom gave us.
210 * ifsin6: address of interface being examined.
211 * clntsin6: address that client want us to contact
213 * servsin6: local address of RPC service.
214 * sin6mask: netmask of this interface
215 * newsin6: initially a copy of clntsin, eventually
218 * For v6 link local addresses, if the client contacted
219 * us via a link-local address, and wants us to reply
220 * to one, use the scope id to see which one.
222 realsin6
= (struct sockaddr_in6
*)clnt
;
223 ifsin6
= (struct sockaddr_in6
*)ifap
->ifa_addr
;
224 in6_fillscopeid(ifsin6
);
225 clntsin6
= (struct sockaddr_in6
*)clnt_sa
;
226 servsin6
= (struct sockaddr_in6
*)serv_sa
;
227 sin6mask
= (struct sockaddr_in6
*)ifap
->ifa_netmask
;
228 newsin6
= (struct sockaddr_in6
*)&ss
;
229 if (IN6_IS_ADDR_LINKLOCAL(&ifsin6
->sin6_addr
) &&
230 IN6_IS_ADDR_LINKLOCAL(&realsin6
->sin6_addr
) &&
231 IN6_IS_ADDR_LINKLOCAL(&clntsin6
->sin6_addr
)) {
232 if (ifsin6
->sin6_scope_id
!=
233 realsin6
->sin6_scope_id
)
237 if (!bitmaskcmp(&ifsin6
->sin6_addr
,
238 &clntsin6
->sin6_addr
, &sin6mask
->sin6_addr
,
239 sizeof (struct in6_addr
)))
248 * Didn't find anything. Get the first possibly useful interface,
249 * preferring "normal" interfaces to point-to-point and loopback
253 for (ifap
= ifp
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
254 if (ifap
->ifa_addr
->sa_family
!= clnt
->sa_family
||
255 !(ifap
->ifa_flags
& IFF_UP
))
257 if (!(ifap
->ifa_flags
& IFF_LOOPBACK
) &&
258 !(ifap
->ifa_flags
& IFF_POINTOPOINT
)) {
264 else if ((bestif
->ifa_flags
& IFF_LOOPBACK
) &&
265 !(ifap
->ifa_flags
& IFF_LOOPBACK
))
270 switch (clnt
->sa_family
) {
272 memcpy(newsin
, ifap
->ifa_addr
, clnt_sa
->sa_len
);
273 newsin
->sin_port
= servsin
->sin_port
;
274 tbuf
.len
= clnt_sa
->sa_len
;
275 tbuf
.maxlen
= sizeof (struct sockaddr_storage
);
281 memcpy(newsin6
, ifsin6
, clnt_sa
->sa_len
);
282 newsin6
->sin6_port
= servsin6
->sin6_port
;
283 tbuf
.maxlen
= sizeof (struct sockaddr_storage
);
284 tbuf
.len
= clnt_sa
->sa_len
;
292 ret
= taddr2uaddr(nconf
, &tbuf
);
294 freenetconfigent(nconf
);
299 if (clnt_nbp
!= NULL
)
305 fprintf(stderr
, "addrmerge: returning %s\n", ret
);
314 struct ifaddrs
*ifap
, *ifp
;
315 struct ipv6_mreq mreq6
;
319 struct addrinfo hints
, *res
;
321 memset(&hints
, 0, sizeof hints
);
322 hints
.ai_family
= AF_INET
;
323 if ((ecode
= getaddrinfo(NULL
, "sunrpc", &hints
, &res
))) {
325 fprintf(stderr
, "can't get local ip4 address: %s\n",
326 gai_strerror(ecode
));
328 local_in4
= (struct sockaddr_in
*)malloc(sizeof *local_in4
);
329 if (local_in4
== NULL
) {
331 fprintf(stderr
, "can't alloc local ip4 addr\n");
333 memcpy(local_in4
, res
->ai_addr
, sizeof *local_in4
);
337 hints
.ai_family
= AF_INET6
;
338 if ((ecode
= getaddrinfo(NULL
, "sunrpc", &hints
, &res
))) {
340 fprintf(stderr
, "can't get local ip6 address: %s\n",
341 gai_strerror(ecode
));
343 local_in6
= (struct sockaddr_in6
*)malloc(sizeof *local_in6
);
344 if (local_in6
== NULL
) {
346 fprintf(stderr
, "can't alloc local ip6 addr\n");
348 memcpy(local_in6
, res
->ai_addr
, sizeof *local_in6
);
352 * Now join the RPC ipv6 multicast group on all interfaces.
354 if (getifaddrs(&ifp
) < 0)
357 mreq6
.ipv6mr_interface
= 0;
358 inet_pton(AF_INET6
, RPCB_MULTICAST_ADDR
, &mreq6
.ipv6mr_multiaddr
);
360 s
= socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
363 * Loop through all interfaces. For each interface, see if the
364 * network portion of its address is equal to that of the client.
365 * If so, we have found the interface that we want to use.
367 for (ifap
= ifp
; ifap
!= NULL
; ifap
= ifap
->ifa_next
) {
368 if (ifap
->ifa_addr
->sa_family
!= AF_INET6
||
369 !(ifap
->ifa_flags
& IFF_MULTICAST
))
371 ifindex
= if_nametoindex(ifap
->ifa_name
);
372 if (ifindex
== mreq6
.ipv6mr_interface
)
374 * Already did this one.
377 mreq6
.ipv6mr_interface
= ifindex
;
378 if (setsockopt(s
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, &mreq6
,
381 warn("setsockopt v6 multicast");
393 return (struct sockaddr
*)local_in4
;
396 return (struct sockaddr
*)local_in6
;