]> code.delx.au - pulseaudio/blob - src/pulsecore/ipacl.c
Optionally disable IPv6
[pulseaudio] / src / pulsecore / ipacl.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as
9 published by the Free Software Foundation; either version 2.1 of the
10 License, or (at your option) any later version.
11
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <sys/types.h>
28 #include <sys/types.h>
29 #include <string.h>
30
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_SYSTM_H
38 #include <netinet/in_systm.h>
39 #endif
40 #ifdef HAVE_NETINET_IP_H
41 #include <netinet/ip.h>
42 #endif
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
45 #endif
46
47 #include <pulse/xmalloc.h>
48
49 #include <pulsecore/core-util.h>
50 #include <pulsecore/llist.h>
51 #include <pulsecore/log.h>
52 #include <pulsecore/macro.h>
53 #include <pulsecore/winsock.h>
54
55 #ifndef HAVE_INET_PTON
56 #include "inet_pton.h"
57 #endif
58
59 #include "ipacl.h"
60
61 struct acl_entry {
62 PA_LLIST_FIELDS(struct acl_entry);
63 int family;
64 struct in_addr address_ipv4;
65 #ifdef HAVE_IPV6
66 struct in6_addr address_ipv6;
67 #endif
68 int bits;
69 };
70
71 struct pa_ip_acl {
72 PA_LLIST_HEAD(struct acl_entry, entries);
73 };
74
75 pa_ip_acl* pa_ip_acl_new(const char *s) {
76 const char *state = NULL;
77 char *a;
78 pa_ip_acl *acl;
79
80 pa_assert(s);
81
82 acl = pa_xnew(pa_ip_acl, 1);
83 PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
84
85 while ((a = pa_split(s, ";", &state))) {
86 char *slash;
87 struct acl_entry e, *n;
88 uint32_t bits;
89
90 if ((slash = strchr(a, '/'))) {
91 *slash = 0;
92 slash++;
93 if (pa_atou(slash, &bits) < 0) {
94 pa_log_warn("Failed to parse number of bits: %s", slash);
95 goto fail;
96 }
97 } else
98 bits = (uint32_t) -1;
99
100 if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) {
101
102 e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
103
104 if (e.bits > 32) {
105 pa_log_warn("Number of bits out of range: %i", e.bits);
106 goto fail;
107 }
108
109 e.family = AF_INET;
110
111 if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
112 pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
113
114 #ifdef HAVE_IPV6
115 } else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
116
117 e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
118
119 if (e.bits > 128) {
120 pa_log_warn("Number of bits out of range: %i", e.bits);
121 goto fail;
122 }
123 e.family = AF_INET6;
124
125 if (e.bits < 128) {
126 int t = 0, i;
127
128 for (i = 0, bits = (uint32_t) e.bits; i < 16; i++) {
129
130 if (bits >= 8)
131 bits -= 8;
132 else {
133 if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
134 t = 1;
135 break;
136 }
137 bits = 0;
138 }
139 }
140
141 if (t)
142 pa_log_warn("Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
143 }
144 #endif
145
146 } else {
147 pa_log_warn("Failed to parse address: %s", a);
148 goto fail;
149 }
150
151 n = pa_xmemdup(&e, sizeof(struct acl_entry));
152 PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
153
154 pa_xfree(a);
155 }
156
157 return acl;
158
159 fail:
160 pa_xfree(a);
161 pa_ip_acl_free(acl);
162
163 return NULL;
164 }
165
166 void pa_ip_acl_free(pa_ip_acl *acl) {
167 pa_assert(acl);
168
169 while (acl->entries) {
170 struct acl_entry *e = acl->entries;
171 PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
172 pa_xfree(e);
173 }
174
175 pa_xfree(acl);
176 }
177
178 int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
179 struct sockaddr_storage sa;
180 struct acl_entry *e;
181 socklen_t salen;
182
183 pa_assert(acl);
184 pa_assert(fd >= 0);
185
186 salen = sizeof(sa);
187 if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
188 return -1;
189
190 #ifdef HAVE_IPV6
191 if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6)
192 #else
193 if (sa.ss_family != AF_INET)
194 #endif
195 return -1;
196
197 if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
198 return -1;
199
200 #ifdef HAVE_IPV6
201 if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
202 return -1;
203 #endif
204
205 for (e = acl->entries; e; e = e->next) {
206
207 if (e->family != sa.ss_family)
208 continue;
209
210 if (e->family == AF_INET) {
211 struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
212
213 if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
214 (ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
215 return 1;
216 #ifdef HAVE_IPV6
217 } else if (e->family == AF_INET6) {
218 int i, bits ;
219 struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
220
221 if (e->bits == 128)
222 return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0;
223
224 if (e->bits == 0)
225 return 1;
226
227 for (i = 0, bits = e->bits; i < 16; i++) {
228
229 if (bits >= 8) {
230 if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i])
231 break;
232
233 bits -= 8;
234 } else {
235 if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0)
236 break;
237
238 bits = 0;
239 }
240
241 if (bits == 0)
242 return 1;
243 }
244 #endif
245 }
246 }
247
248 return 0;
249 }