4 This file is part of PulseAudio.
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
26 #include <sys/types.h>
27 #include <sys/types.h>
30 #ifdef HAVE_SYS_SOCKET_H
31 #include <sys/socket.h>
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
36 #ifdef HAVE_NETINET_IN_SYSTM_H
37 #include <netinet/in_systm.h>
39 #ifdef HAVE_NETINET_IP_H
40 #include <netinet/ip.h>
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
48 #include <pulse/xmalloc.h>
50 #include <pulsecore/core-util.h>
51 #include <pulsecore/llist.h>
52 #include <pulsecore/log.h>
54 #ifndef HAVE_INET_PTON
55 #include "inet_pton.h"
61 PA_LLIST_FIELDS(struct acl_entry
);
63 struct in_addr address_ipv4
;
64 struct in6_addr address_ipv6
;
69 PA_LLIST_HEAD(struct acl_entry
, entries
);
72 pa_ip_acl
* pa_ip_acl_new(const char *s
) {
73 const char *state
= NULL
;
79 acl
= pa_xnew(pa_ip_acl
, 1);
80 PA_LLIST_HEAD_INIT(struct acl_entry
, acl
->entries
);
82 while ((a
= pa_split(s
, ";", &state
))) {
84 struct acl_entry e
, *n
;
87 if ((slash
= strchr(a
, '/'))) {
90 if (pa_atou(slash
, &bits
) < 0) {
91 pa_log("failed to parse number of bits: %s", slash
);
97 if (inet_pton(AF_INET
, a
, &e
.address_ipv4
) > 0) {
99 e
.bits
= bits
== (uint32_t) -1 ? 32 : (int) bits
;
102 pa_log("number of bits out of range: %i", e
.bits
);
108 if (e
.bits
< 32 && (uint32_t) (ntohl(e
.address_ipv4
.s_addr
) << e
.bits
) != 0)
109 pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a
, e
.bits
);
111 } else if (inet_pton(AF_INET6
, a
, &e
.address_ipv6
) > 0) {
113 e
.bits
= bits
== (uint32_t) -1 ? 128 : (int) bits
;
116 pa_log("number of bits out of range: %i", e
.bits
);
124 for (i
= 0, bits
= e
.bits
; i
< 16; i
++) {
129 if ((uint8_t) ((e
.address_ipv6
.s6_addr
[i
]) << bits
) != 0) {
138 pa_log_warn("WARNING: Host part of ACL entry '%s/%u' is not zero!", a
, e
.bits
);
142 pa_log("failed to parse address: %s", a
);
146 n
= pa_xmemdup(&e
, sizeof(struct acl_entry
));
147 PA_LLIST_PREPEND(struct acl_entry
, acl
->entries
, n
);
161 void pa_ip_acl_free(pa_ip_acl
*acl
) {
164 while (acl
->entries
) {
165 struct acl_entry
*e
= acl
->entries
;
166 PA_LLIST_REMOVE(struct acl_entry
, acl
->entries
, e
);
173 int pa_ip_acl_check(pa_ip_acl
*acl
, int fd
) {
174 struct sockaddr_storage sa
;
182 if (getpeername(fd
, (struct sockaddr
*) &sa
, &salen
) < 0)
185 if (sa
.ss_family
!= AF_INET
&& sa
.ss_family
!= AF_INET6
)
188 if (sa
.ss_family
== AF_INET
&& salen
!= sizeof(struct sockaddr_in
))
191 if (sa
.ss_family
== AF_INET6
&& salen
!= sizeof(struct sockaddr_in6
))
194 for (e
= acl
->entries
; e
; e
= e
->next
) {
196 if (e
->family
!= sa
.ss_family
)
199 if (e
->family
== AF_INET
) {
200 struct sockaddr_in
*sai
= (struct sockaddr_in
*) &sa
;
202 if (e
->bits
== 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
203 (ntohl(sai
->sin_addr
.s_addr
^ e
->address_ipv4
.s_addr
) >> (32 - e
->bits
)) == 0)
205 } else if (e
->family
== AF_INET6
) {
207 struct sockaddr_in6
*sai
= (struct sockaddr_in6
*) &sa
;
210 return memcmp(&sai
->sin6_addr
, &e
->address_ipv6
, 16) == 0;
215 for (i
= 0, bits
= e
->bits
; i
< 16; i
++) {
218 if (sai
->sin6_addr
.s6_addr
[i
] != e
->address_ipv6
.s6_addr
[i
])
223 if ((sai
->sin6_addr
.s6_addr
[i
] ^ e
->address_ipv6
.s6_addr
[i
]) >> (8 - bits
) != 0)