]>
git.saurik.com Git - apple/libc.git/blob - net/FreeBSD/sourcefilter.c
a5a3cca16b4edda8e65823c17454f8013cee707b
2 * Copyright (c) 2007-2009 Bruce Simpson.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD: src/lib/libc/net/sourcefilter.c,v 1.5 2009/04/29 09:58:31 bms Exp $");
30 /* 8120237: enable INET6 */
31 #define __APPLE_USE_RFC_3542
33 #include "namespace.h"
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/ioctl.h>
38 #include <sys/socket.h>
40 #include <net/if_dl.h>
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44 #include <netinet/ip.h>
45 #include <netinet/ip_var.h>
53 #include "un-namespace.h"
56 * Advanced (Full-state) multicast group membership APIs [RFC3678]
57 * Currently this module assumes IPv4 support (INET) in the base system.
62 /* 8120237: enable INET6 */
68 struct sockaddr_storage ss
;
70 struct sockaddr_dl sdl
;
72 struct sockaddr_in sin
;
75 struct sockaddr_in6 sin6
;
78 typedef union sockunion sockunion_t
;
81 #define MIN(a, b) ((a) < (b) ? (a) : (b))
85 * Internal: Map an IPv4 unicast address to an interface index.
86 * This is quite inefficient so it is recommended applications use
87 * the newer, more portable, protocol independent API.
90 __inaddr_to_index(in_addr_t ifaddr
)
93 struct ifaddrs
*ifaddrs
;
98 if (getifaddrs(&ifaddrs
) < 0)
105 * Pass #1: Find the ifaddr entry corresponding to the
106 * supplied IPv4 address. We should really use the ifindex
107 * consistently for matches, however it is not available to
110 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
111 psu
= (sockunion_t
*)ifa
->ifa_addr
;
112 if (psu
&& psu
->ss
.ss_family
== AF_INET
&&
113 psu
->sin
.sin_addr
.s_addr
== ifaddr
) {
114 ifname
= ifa
->ifa_name
;
122 * Pass #2: Find the index of the interface matching the name
123 * we obtained from looking up the IPv4 ifaddr in pass #1.
124 * There must be a better way of doing this.
126 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
127 psu
= (sockunion_t
*)ifa
->ifa_addr
;
128 if (psu
&& psu
->ss
.ss_family
== AF_LINK
&&
129 strcmp(ifa
->ifa_name
, ifname
) == 0) {
130 ifindex
= psu
->sdl
.sdl_index
;
134 assert(ifindex
!= 0);
137 freeifaddrs(ifaddrs
);
142 * Set IPv4 source filter list in use on socket.
144 * Stubbed to setsourcefilter(). Performs conversion of structures which
145 * may be inefficient; applications are encouraged to use the
146 * protocol-independent API.
149 setipv4sourcefilter(int s
, struct in_addr interface
, struct in_addr group
,
150 uint32_t fmode
, uint32_t numsrc
, struct in_addr
*slist
)
153 sockunion_t tmpgroup
;
154 struct in_addr
*pina
;
155 sockunion_t
*psu
, *tmpslist
;
164 if (!IN_MULTICAST(ntohl(group
.s_addr
)) ||
165 (fmode
!= MCAST_INCLUDE
&& fmode
!= MCAST_EXCLUDE
)) {
170 ifindex
= __inaddr_to_index(interface
.s_addr
);
172 errno
= EADDRNOTAVAIL
;
176 memset(&tmpgroup
, 0, sizeof(sockunion_t
));
177 tmpgroup
.sin
.sin_family
= AF_INET
;
178 tmpgroup
.sin
.sin_len
= sizeof(struct sockaddr_in
);
179 tmpgroup
.sin
.sin_addr
= group
;
181 if (numsrc
!= 0 || slist
!= NULL
) {
182 tmpslist
= calloc(numsrc
, sizeof(sockunion_t
));
183 if (tmpslist
== NULL
) {
190 for (i
= 0; i
< numsrc
; i
++, pina
++, psu
++) {
191 psu
->sin
.sin_family
= AF_INET
;
192 psu
->sin
.sin_len
= sizeof(struct sockaddr_in
);
193 psu
->sin
.sin_addr
= *pina
;
197 err
= setsourcefilter(s
, ifindex
, (struct sockaddr
*)&tmpgroup
,
198 sizeof(struct sockaddr_in
), fmode
, numsrc
,
199 (struct sockaddr_storage
*)tmpslist
);
201 if (tmpslist
!= NULL
)
206 return (EAFNOSUPPORT
);
211 * Get IPv4 source filter list in use on socket.
213 * Stubbed to getsourcefilter(). Performs conversion of structures which
214 * may be inefficient; applications are encouraged to use the
215 * protocol-independent API.
216 * An slist of NULL may be used for guessing the required buffer size.
219 getipv4sourcefilter(int s
, struct in_addr interface
, struct in_addr group
,
220 uint32_t *fmode
, uint32_t *numsrc
, struct in_addr
*slist
)
222 sockunion_t
*psu
, *tmpslist
;
223 sockunion_t tmpgroup
;
224 struct in_addr
*pina
;
227 uint32_t ifindex
, onumsrc
;
230 assert(fmode
!= NULL
);
231 assert(numsrc
!= NULL
);
237 if (!IN_MULTICAST(ntohl(group
.s_addr
)) ||
238 (onumsrc
!= 0 && slist
== NULL
)) {
243 ifindex
= __inaddr_to_index(interface
.s_addr
);
245 errno
= EADDRNOTAVAIL
;
249 memset(&tmpgroup
, 0, sizeof(sockunion_t
));
250 tmpgroup
.sin
.sin_family
= AF_INET
;
251 tmpgroup
.sin
.sin_len
= sizeof(struct sockaddr_in
);
252 tmpgroup
.sin
.sin_addr
= group
;
254 if (onumsrc
!= 0 || slist
!= NULL
) {
255 tmpslist
= calloc(onumsrc
, sizeof(sockunion_t
));
256 if (tmpslist
== NULL
) {
262 err
= getsourcefilter(s
, ifindex
, (struct sockaddr
*)&tmpgroup
,
263 sizeof(struct sockaddr_in
), fmode
, numsrc
,
264 (struct sockaddr_storage
*)tmpslist
);
266 if (tmpslist
!= NULL
&& *numsrc
!= 0) {
269 for (i
= 0; i
< MIN(onumsrc
, *numsrc
); i
++, psu
++) {
270 if (psu
->ss
.ss_family
!= AF_INET
)
272 *pina
++ = psu
->sin
.sin_addr
;
281 * Set protocol-independent source filter list in use on socket.
284 setsourcefilter(int s
, uint32_t interface
, struct sockaddr
*group
,
285 socklen_t grouplen
, uint32_t fmode
, uint32_t numsrc
,
286 struct sockaddr_storage
*slist
)
288 struct __msfilterreq msfr
;
292 if (fmode
!= MCAST_INCLUDE
&& fmode
!= MCAST_EXCLUDE
) {
297 psu
= (sockunion_t
*)group
;
298 switch (psu
->ss
.ss_family
) {
301 if ((grouplen
!= sizeof(struct sockaddr_in
) ||
302 !IN_MULTICAST(ntohl(psu
->sin
.sin_addr
.s_addr
)))) {
307 optname
= IP_MSFILTER
;
312 if (grouplen
!= sizeof(struct sockaddr_in6
) ||
313 !IN6_IS_ADDR_MULTICAST(&psu
->sin6
.sin6_addr
)) {
317 level
= IPPROTO_IPV6
;
318 optname
= IPV6_MSFILTER
;
322 errno
= EAFNOSUPPORT
;
326 memset(&msfr
, 0, sizeof(msfr
));
327 msfr
.msfr_ifindex
= interface
;
328 msfr
.msfr_fmode
= fmode
;
329 msfr
.msfr_nsrcs
= numsrc
;
330 memcpy(&msfr
.msfr_group
, &psu
->ss
, psu
->ss
.ss_len
);
331 msfr
.msfr_srcs
= slist
; /* pointer */
333 return (_setsockopt(s
, level
, optname
, &msfr
, sizeof(msfr
)));
337 * Get protocol-independent source filter list in use on socket.
338 * An slist of NULL may be used for guessing the required buffer size.
341 getsourcefilter(int s
, uint32_t interface
, struct sockaddr
*group
,
342 socklen_t grouplen
, uint32_t *fmode
, uint32_t *numsrc
,
343 struct sockaddr_storage
*slist
)
345 struct __msfilterreq msfr
;
347 int err
, level
, nsrcs
, optlen
, optname
;
349 if (interface
== 0 || group
== NULL
|| numsrc
== NULL
||
359 psu
= (sockunion_t
*)group
;
360 switch (psu
->ss
.ss_family
) {
363 if ((grouplen
!= sizeof(struct sockaddr_in
) ||
364 !IN_MULTICAST(ntohl(psu
->sin
.sin_addr
.s_addr
)))) {
369 optname
= IP_MSFILTER
;
374 if (grouplen
!= sizeof(struct sockaddr_in6
) ||
375 !IN6_IS_ADDR_MULTICAST(&psu
->sin6
.sin6_addr
)) {
379 level
= IPPROTO_IPV6
;
380 optname
= IPV6_MSFILTER
;
384 errno
= EAFNOSUPPORT
;
389 optlen
= sizeof(struct __msfilterreq
);
390 memset(&msfr
, 0, optlen
);
391 msfr
.msfr_ifindex
= interface
;
393 msfr
.msfr_nsrcs
= nsrcs
;
394 memcpy(&msfr
.msfr_group
, &psu
->ss
, psu
->ss
.ss_len
);
397 * msfr_srcs is a pointer to a vector of sockaddr_storage. It
398 * may be NULL. The kernel will always return the total number
399 * of filter entries for the group in msfr.msfr_nsrcs.
401 msfr
.msfr_srcs
= slist
;
402 err
= _getsockopt(s
, level
, optname
, &msfr
, &optlen
);
404 *numsrc
= msfr
.msfr_nsrcs
;
405 *fmode
= msfr
.msfr_fmode
;