xref: /illumos-gate/usr/src/lib/libsocket/inet/sourcefilter.c (revision 5e989a96186a37eb528fb7bb4d28a150874ec799)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <stropts.h>
34 #include <errno.h>
35 #include <sys/sysmacros.h>
36 #include <sys/socket.h>
37 #include <sys/sockio.h>
38 #include <netinet/in.h>
39 
40 int
41 getsourcefilter(int s, uint32_t interface, struct sockaddr *group,
42     socklen_t grouplen, uint32_t *fmode, uint_t *numsrc,
43     struct sockaddr_storage *slist)
44 {
45 	struct group_filter *gf;
46 	int mallocsize, orig_numsrc, cpsize, rtnerr;
47 
48 	mallocsize = (*numsrc == 0) ?
49 	    sizeof (struct group_filter) : GROUP_FILTER_SIZE(*numsrc);
50 	gf = (struct group_filter *)malloc(mallocsize);
51 	if (gf == NULL) {
52 		errno = ENOMEM;
53 		return (-1);
54 	}
55 
56 	gf->gf_interface = interface;
57 	gf->gf_numsrc = orig_numsrc = *numsrc;
58 	switch (group->sa_family) {
59 	case AF_INET:
60 		if (grouplen < sizeof (struct sockaddr_in)) {
61 			rtnerr = ENOPROTOOPT;
62 			goto done;
63 		}
64 		(void) memcpy((void *)&gf->gf_group, (void *)group,
65 		    sizeof (struct sockaddr_in));
66 		break;
67 	case AF_INET6:
68 		if (grouplen < sizeof (struct sockaddr_in6)) {
69 			rtnerr = ENOPROTOOPT;
70 			goto done;
71 		}
72 		(void) memcpy((void *)&gf->gf_group, (void *)group,
73 		    sizeof (struct sockaddr_in6));
74 		break;
75 	default:
76 		rtnerr = EAFNOSUPPORT;
77 		goto done;
78 	}
79 
80 	rtnerr = ioctl(s, SIOCGMSFILTER, (void *)gf);
81 	if (rtnerr == -1) {
82 		rtnerr = errno;
83 		goto done;
84 	}
85 
86 	*fmode = gf->gf_fmode;
87 	*numsrc = gf->gf_numsrc;
88 	cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct sockaddr_storage);
89 	(void) memcpy((void *)slist, (void *)gf->gf_slist, cpsize);
90 
91 done:
92 	free(gf);
93 	errno = rtnerr;
94 	if (errno != 0)
95 		return (-1);
96 
97 	return (0);
98 }
99 
100 int
101 setsourcefilter(int s, uint32_t interface, struct sockaddr *group,
102     socklen_t grouplen, uint32_t fmode, uint_t numsrc,
103     struct sockaddr_storage *slist)
104 {
105 	struct group_filter *gf;
106 	int mallocsize, rtnerr;
107 
108 	mallocsize = (numsrc == 0) ?
109 	    sizeof (struct group_filter) : GROUP_FILTER_SIZE(numsrc);
110 	gf = (struct group_filter *)malloc(mallocsize);
111 	if (gf == NULL) {
112 		errno = ENOMEM;
113 		return (-1);
114 	}
115 
116 	switch (group->sa_family) {
117 	case AF_INET:
118 		if (grouplen < sizeof (struct sockaddr_in)) {
119 			rtnerr = ENOPROTOOPT;
120 			goto done;
121 		}
122 		(void) memcpy((void *)&gf->gf_group, (void *)group,
123 		    sizeof (struct sockaddr_in));
124 		break;
125 	case AF_INET6:
126 		if (grouplen < sizeof (struct sockaddr_in6)) {
127 			rtnerr = ENOPROTOOPT;
128 			goto done;
129 		}
130 		(void) memcpy((void *)&gf->gf_group, (void *)group,
131 		    sizeof (struct sockaddr_in6));
132 		break;
133 	default:
134 		rtnerr = EAFNOSUPPORT;
135 		goto done;
136 	}
137 	gf->gf_interface = interface;
138 	gf->gf_fmode = fmode;
139 	gf->gf_numsrc = numsrc;
140 	(void) memcpy((void *)gf->gf_slist, (void *)slist,
141 	    (numsrc * sizeof (struct sockaddr_storage)));
142 
143 	rtnerr = ioctl(s, SIOCSMSFILTER, (void *)gf);
144 	if (rtnerr == -1) {
145 		rtnerr = errno;
146 	}
147 
148 done:
149 	free(gf);
150 	errno = rtnerr;
151 	if (errno != 0)
152 		return (-1);
153 
154 	return (0);
155 }
156 
157 int
158 getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
159     uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist)
160 {
161 	struct ip_msfilter *imsf;
162 	int mallocsize, orig_numsrc, cpsize, rtnerr;
163 
164 	mallocsize = (*numsrc == 0) ?
165 	    sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(*numsrc);
166 	imsf = (struct ip_msfilter *)malloc(mallocsize);
167 	if (imsf == NULL) {
168 		errno = ENOMEM;
169 		return (-1);
170 	}
171 
172 	imsf->imsf_interface = interface;
173 	imsf->imsf_numsrc = orig_numsrc = *numsrc;
174 	imsf->imsf_multiaddr = group;
175 
176 	rtnerr = ioctl(s, SIOCGIPMSFILTER, (void *)imsf);
177 	if (rtnerr == -1) {
178 		rtnerr = errno;
179 		goto done;
180 	}
181 
182 	*fmode = imsf->imsf_fmode;
183 	*numsrc = imsf->imsf_numsrc;
184 	cpsize = MIN(orig_numsrc, *numsrc) * sizeof (struct in_addr);
185 	(void) memcpy((void *)slist, (void *)imsf->imsf_slist, cpsize);
186 
187 done:
188 	free(imsf);
189 	errno = rtnerr;
190 	if (errno != 0)
191 		return (-1);
192 
193 	return (0);
194 }
195 
196 int
197 setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
198     uint32_t fmode, uint32_t numsrc, struct in_addr *slist)
199 {
200 	struct ip_msfilter *imsf;
201 	int mallocsize, rtnerr;
202 
203 	mallocsize = (numsrc == 0) ?
204 	    sizeof (struct ip_msfilter) : IP_MSFILTER_SIZE(numsrc);
205 	imsf = (struct ip_msfilter *)malloc(mallocsize);
206 	if (imsf == NULL) {
207 		errno = ENOMEM;
208 		return (-1);
209 	}
210 
211 	imsf->imsf_multiaddr = group;
212 	imsf->imsf_interface = interface;
213 	imsf->imsf_fmode = fmode;
214 	imsf->imsf_numsrc = numsrc;
215 	(void) memcpy((void *)imsf->imsf_slist, (void *)slist,
216 	    (numsrc * sizeof (struct in_addr)));
217 
218 	rtnerr = ioctl(s, SIOCSIPMSFILTER, (void *)imsf);
219 	if (rtnerr == -1) {
220 		rtnerr = errno;
221 	}
222 
223 	free(imsf);
224 	errno = rtnerr;
225 	if (errno != 0)
226 		return (-1);
227 
228 	return (0);
229 }
230