]>
git.saurik.com Git - apple/libc.git/blob - net/FreeBSD/sourcefilter.c
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 #include "namespace.h"
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
37 #include <net/if_dl.h>
39 #include <netinet/in.h>
40 #include <netinet/in_systm.h>
41 #include <netinet/ip.h>
42 #include <netinet/ip_var.h>
50 #include "un-namespace.h"
53 * Advanced (Full-state) multicast group membership APIs [RFC3678]
54 * Currently this module assumes IPv4 support (INET) in the base system.
61 struct sockaddr_storage ss
;
63 struct sockaddr_dl sdl
;
65 struct sockaddr_in sin
;
68 struct sockaddr_in6 sin6
;
71 typedef union sockunion sockunion_t
;
74 #define MIN(a, b) ((a) < (b) ? (a) : (b))
78 * Internal: Map an IPv4 unicast address to an interface index.
79 * This is quite inefficient so it is recommended applications use
80 * the newer, more portable, protocol independent API.
83 __inaddr_to_index(in_addr_t ifaddr
)
86 struct ifaddrs
*ifaddrs
;
91 if (getifaddrs(&ifaddrs
) < 0)
98 * Pass #1: Find the ifaddr entry corresponding to the
99 * supplied IPv4 address. We should really use the ifindex
100 * consistently for matches, however it is not available to
103 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
104 psu
= (sockunion_t
*)ifa
->ifa_addr
;
105 if (psu
&& psu
->ss
.ss_family
== AF_INET
&&
106 psu
->sin
.sin_addr
.s_addr
== ifaddr
) {
107 ifname
= ifa
->ifa_name
;
115 * Pass #2: Find the index of the interface matching the name
116 * we obtained from looking up the IPv4 ifaddr in pass #1.
117 * There must be a better way of doing this.
119 for (ifa
= ifaddrs
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
120 psu
= (sockunion_t
*)ifa
->ifa_addr
;
121 if (psu
&& psu
->ss
.ss_family
== AF_LINK
&&
122 strcmp(ifa
->ifa_name
, ifname
) == 0) {
123 ifindex
= psu
->sdl
.sdl_index
;
127 assert(ifindex
!= 0);
130 freeifaddrs(ifaddrs
);
135 * Set IPv4 source filter list in use on socket.
137 * Stubbed to setsourcefilter(). Performs conversion of structures which
138 * may be inefficient; applications are encouraged to use the
139 * protocol-independent API.
142 setipv4sourcefilter(int s
, struct in_addr interface
, struct in_addr group
,
143 uint32_t fmode
, uint32_t numsrc
, struct in_addr
*slist
)
146 sockunion_t tmpgroup
;
147 struct in_addr
*pina
;
148 sockunion_t
*psu
, *tmpslist
;
157 if (!IN_MULTICAST(ntohl(group
.s_addr
)) ||
158 (fmode
!= MCAST_INCLUDE
&& fmode
!= MCAST_EXCLUDE
)) {
163 ifindex
= __inaddr_to_index(interface
.s_addr
);
165 errno
= EADDRNOTAVAIL
;
169 memset(&tmpgroup
, 0, sizeof(sockunion_t
));
170 tmpgroup
.sin
.sin_family
= AF_INET
;
171 tmpgroup
.sin
.sin_len
= sizeof(struct sockaddr_in
);
172 tmpgroup
.sin
.sin_addr
= group
;
174 if (numsrc
!= 0 || slist
!= NULL
) {
175 tmpslist
= calloc(numsrc
, sizeof(sockunion_t
));
176 if (tmpslist
== NULL
) {
183 for (i
= 0; i
< numsrc
; i
++, pina
++, psu
++) {
184 psu
->sin
.sin_family
= AF_INET
;
185 psu
->sin
.sin_len
= sizeof(struct sockaddr_in
);
186 psu
->sin
.sin_addr
= *pina
;
190 err
= setsourcefilter(s
, ifindex
, (struct sockaddr
*)&tmpgroup
,
191 sizeof(struct sockaddr_in
), fmode
, numsrc
,
192 (struct sockaddr_storage
*)tmpslist
);
194 if (tmpslist
!= NULL
)
199 return (EAFNOSUPPORT
);
204 * Get IPv4 source filter list in use on socket.
206 * Stubbed to getsourcefilter(). Performs conversion of structures which
207 * may be inefficient; applications are encouraged to use the
208 * protocol-independent API.
209 * An slist of NULL may be used for guessing the required buffer size.
212 getipv4sourcefilter(int s
, struct in_addr interface
, struct in_addr group
,
213 uint32_t *fmode
, uint32_t *numsrc
, struct in_addr
*slist
)
215 sockunion_t
*psu
, *tmpslist
;
216 sockunion_t tmpgroup
;
217 struct in_addr
*pina
;
220 uint32_t ifindex
, onumsrc
;
223 assert(fmode
!= NULL
);
224 assert(numsrc
!= NULL
);
230 if (!IN_MULTICAST(ntohl(group
.s_addr
)) ||
231 (onumsrc
!= 0 && slist
== NULL
)) {
236 ifindex
= __inaddr_to_index(interface
.s_addr
);
238 errno
= EADDRNOTAVAIL
;
242 memset(&tmpgroup
, 0, sizeof(sockunion_t
));
243 tmpgroup
.sin
.sin_family
= AF_INET
;
244 tmpgroup
.sin
.sin_len
= sizeof(struct sockaddr_in
);
245 tmpgroup
.sin
.sin_addr
= group
;
247 if (onumsrc
!= 0 || slist
!= NULL
) {
248 tmpslist
= calloc(onumsrc
, sizeof(sockunion_t
));
249 if (tmpslist
== NULL
) {
255 err
= getsourcefilter(s
, ifindex
, (struct sockaddr
*)&tmpgroup
,
256 sizeof(struct sockaddr_in
), fmode
, numsrc
,
257 (struct sockaddr_storage
*)tmpslist
);
259 if (tmpslist
!= NULL
&& *numsrc
!= 0) {
262 for (i
= 0; i
< MIN(onumsrc
, *numsrc
); i
++, psu
++) {
263 if (psu
->ss
.ss_family
!= AF_INET
)
265 *pina
++ = psu
->sin
.sin_addr
;
274 * Set protocol-independent source filter list in use on socket.
277 setsourcefilter(int s
, uint32_t interface
, struct sockaddr
*group
,
278 socklen_t grouplen
, uint32_t fmode
, uint32_t numsrc
,
279 struct sockaddr_storage
*slist
)
281 struct __msfilterreq msfr
;
285 if (fmode
!= MCAST_INCLUDE
&& fmode
!= MCAST_EXCLUDE
) {
290 psu
= (sockunion_t
*)group
;
291 switch (psu
->ss
.ss_family
) {
294 if ((grouplen
!= sizeof(struct sockaddr_in
) ||
295 !IN_MULTICAST(ntohl(psu
->sin
.sin_addr
.s_addr
)))) {
300 optname
= IP_MSFILTER
;
305 if (grouplen
!= sizeof(struct sockaddr_in6
) ||
306 !IN6_IS_ADDR_MULTICAST(&psu
->sin6
.sin6_addr
)) {
310 level
= IPPROTO_IPV6
;
311 optname
= IPV6_MSFILTER
;
315 errno
= EAFNOSUPPORT
;
319 memset(&msfr
, 0, sizeof(msfr
));
320 msfr
.msfr_ifindex
= interface
;
321 msfr
.msfr_fmode
= fmode
;
322 msfr
.msfr_nsrcs
= numsrc
;
323 memcpy(&msfr
.msfr_group
, &psu
->ss
, psu
->ss
.ss_len
);
324 msfr
.msfr_srcs
= slist
; /* pointer */
326 return (_setsockopt(s
, level
, optname
, &msfr
, sizeof(msfr
)));
330 * Get protocol-independent source filter list in use on socket.
331 * An slist of NULL may be used for guessing the required buffer size.
334 getsourcefilter(int s
, uint32_t interface
, struct sockaddr
*group
,
335 socklen_t grouplen
, uint32_t *fmode
, uint32_t *numsrc
,
336 struct sockaddr_storage
*slist
)
338 struct __msfilterreq msfr
;
340 int err
, level
, nsrcs
, optlen
, optname
;
342 if (interface
== 0 || group
== NULL
|| numsrc
== NULL
||
352 psu
= (sockunion_t
*)group
;
353 switch (psu
->ss
.ss_family
) {
356 if ((grouplen
!= sizeof(struct sockaddr_in
) ||
357 !IN_MULTICAST(ntohl(psu
->sin
.sin_addr
.s_addr
)))) {
362 optname
= IP_MSFILTER
;
367 if (grouplen
!= sizeof(struct sockaddr_in6
) ||
368 !IN6_IS_ADDR_MULTICAST(&psu
->sin6
.sin6_addr
)) {
372 level
= IPPROTO_IPV6
;
373 optname
= IPV6_MSFILTER
;
377 errno
= EAFNOSUPPORT
;
382 optlen
= sizeof(struct __msfilterreq
);
383 memset(&msfr
, 0, optlen
);
384 msfr
.msfr_ifindex
= interface
;
386 msfr
.msfr_nsrcs
= nsrcs
;
387 memcpy(&msfr
.msfr_group
, &psu
->ss
, psu
->ss
.ss_len
);
390 * msfr_srcs is a pointer to a vector of sockaddr_storage. It
391 * may be NULL. The kernel will always return the total number
392 * of filter entries for the group in msfr.msfr_nsrcs.
394 msfr
.msfr_srcs
= slist
;
395 err
= _getsockopt(s
, level
, optname
, &msfr
, &optlen
);
397 *numsrc
= msfr
.msfr_nsrcs
;
398 *fmode
= msfr
.msfr_fmode
;