mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-03 09:01:50 -05:00
add IP address ACL subsystem
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@1123 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
4a59581a4c
commit
30ada90fd2
4 changed files with 377 additions and 1 deletions
|
|
@ -194,7 +194,8 @@ noinst_PROGRAMS = \
|
||||||
channelmap-test \
|
channelmap-test \
|
||||||
thread-mainloop-test \
|
thread-mainloop-test \
|
||||||
utf8-test \
|
utf8-test \
|
||||||
get-binary-name-test
|
get-binary-name-test \
|
||||||
|
ipacl-test
|
||||||
|
|
||||||
if HAVE_SIGXCPU
|
if HAVE_SIGXCPU
|
||||||
noinst_PROGRAMS += \
|
noinst_PROGRAMS += \
|
||||||
|
|
@ -227,6 +228,11 @@ get_binary_name_test_CFLAGS = $(AM_CFLAGS)
|
||||||
get_binary_name_test_LDADD = $(AM_LDADD) libpulse.la
|
get_binary_name_test_LDADD = $(AM_LDADD) libpulse.la
|
||||||
get_binary_name_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
|
get_binary_name_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
|
||||||
|
|
||||||
|
ipacl_test_SOURCES = tests/ipacl-test.c pulsecore/ipacl.c pulsecore/ipacl.h
|
||||||
|
ipacl_test_CFLAGS = $(AM_CFLAGS)
|
||||||
|
ipacl_test_LDADD = $(AM_LDADD) libpulsecore.la
|
||||||
|
ipacl_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
|
||||||
|
|
||||||
mcalign_test_SOURCES = tests/mcalign-test.c
|
mcalign_test_SOURCES = tests/mcalign-test.c
|
||||||
mcalign_test_CFLAGS = $(AM_CFLAGS)
|
mcalign_test_CFLAGS = $(AM_CFLAGS)
|
||||||
mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la
|
mcalign_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) libpulsecore.la
|
||||||
|
|
@ -586,6 +592,7 @@ pulsecoreinclude_HEADERS += \
|
||||||
pulsecore/socket-util.h \
|
pulsecore/socket-util.h \
|
||||||
pulsecore/iochannel.h \
|
pulsecore/iochannel.h \
|
||||||
pulsecore/socket-server.h \
|
pulsecore/socket-server.h \
|
||||||
|
pulsecore/ipacl.h \
|
||||||
pulsecore/socket-client.h \
|
pulsecore/socket-client.h \
|
||||||
pulsecore/parseaddr.h \
|
pulsecore/parseaddr.h \
|
||||||
pulsecore/packet.h \
|
pulsecore/packet.h \
|
||||||
|
|
@ -615,6 +622,7 @@ modlibexec_LTLIBRARIES = \
|
||||||
libsocket-util.la \
|
libsocket-util.la \
|
||||||
libiochannel.la \
|
libiochannel.la \
|
||||||
libsocket-server.la \
|
libsocket-server.la \
|
||||||
|
libipacl.la \
|
||||||
libparseaddr.la \
|
libparseaddr.la \
|
||||||
libsocket-client.la \
|
libsocket-client.la \
|
||||||
libpacket.la \
|
libpacket.la \
|
||||||
|
|
@ -668,6 +676,10 @@ libsocket_server_la_SOURCES = \
|
||||||
libsocket_server_la_LDFLAGS = -avoid-version
|
libsocket_server_la_LDFLAGS = -avoid-version
|
||||||
libsocket_server_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS)
|
libsocket_server_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la $(LIBWRAP_LIBS) $(WINSOCK_LIBS)
|
||||||
|
|
||||||
|
libipacl_la_SOURCES = pulsecore/ipacl.h pulsecore/ipacl.c
|
||||||
|
libipacl_la_LDFLAGS = -avoid-version
|
||||||
|
libipacl_la_LIBADD = $(AM_LIBADD) libpulsecore.la $(WINSOCK_LIBS)
|
||||||
|
|
||||||
libsocket_client_la_SOURCES = pulsecore/socket-client.c pulsecore/socket-client.h
|
libsocket_client_la_SOURCES = pulsecore/socket-client.c pulsecore/socket-client.h
|
||||||
libsocket_client_la_LDFLAGS = -avoid-version
|
libsocket_client_la_LDFLAGS = -avoid-version
|
||||||
libsocket_client_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS)
|
libsocket_client_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) $(WINSOCK_LIBS)
|
||||||
|
|
|
||||||
216
src/pulsecore/ipacl.c
Normal file
216
src/pulsecore/ipacl.c
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of PulseAudio.
|
||||||
|
|
||||||
|
PulseAudio is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
PulseAudio is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with PulseAudio; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
USA.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <pulsecore/core-util.h>
|
||||||
|
#include <pulsecore/llist.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
|
#include "ipacl.h"
|
||||||
|
|
||||||
|
struct acl_entry {
|
||||||
|
PA_LLIST_FIELDS(struct acl_entry);
|
||||||
|
int family;
|
||||||
|
struct in_addr address_ipv4;
|
||||||
|
struct in6_addr address_ipv6;
|
||||||
|
int bits;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pa_ip_acl {
|
||||||
|
PA_LLIST_HEAD(struct acl_entry, entries);
|
||||||
|
};
|
||||||
|
|
||||||
|
pa_ip_acl* pa_ip_acl_new(const char *s) {
|
||||||
|
const char *state = NULL;
|
||||||
|
char *a;
|
||||||
|
pa_ip_acl *acl;
|
||||||
|
|
||||||
|
assert(s);
|
||||||
|
|
||||||
|
acl = pa_xnew(pa_ip_acl, 1);
|
||||||
|
PA_LLIST_HEAD_INIT(struct acl_entry, acl->entries);
|
||||||
|
|
||||||
|
while ((a = pa_split(s, ";", &state))) {
|
||||||
|
char *slash;
|
||||||
|
struct acl_entry e, *n;
|
||||||
|
uint32_t bits;
|
||||||
|
|
||||||
|
if ((slash = strchr(a, '/'))) {
|
||||||
|
*slash = 0;
|
||||||
|
slash++;
|
||||||
|
if (pa_atou(slash, &bits) < 0) {
|
||||||
|
pa_log(__FILE__": failed to parse number of bits: %s", slash);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
bits = (uint32_t) -1;
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET, a, &e.address_ipv4) > 0) {
|
||||||
|
|
||||||
|
e.bits = bits == (uint32_t) -1 ? 32 : (int) bits;
|
||||||
|
|
||||||
|
if (e.bits > 32) {
|
||||||
|
pa_log(__FILE__": number of bits out of range: %i", e.bits);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.family = AF_INET;
|
||||||
|
|
||||||
|
if (e.bits < 32 && (uint32_t) (ntohl(e.address_ipv4.s_addr) << e.bits) != 0)
|
||||||
|
pa_log_warn(__FILE__": WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
|
||||||
|
|
||||||
|
} else if (inet_pton(AF_INET6, a, &e.address_ipv6) > 0) {
|
||||||
|
|
||||||
|
e.bits = bits == (uint32_t) -1 ? 128 : (int) bits;
|
||||||
|
|
||||||
|
if (e.bits > 128) {
|
||||||
|
pa_log(__FILE__": number of bits out of range: %i", e.bits);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
e.family = AF_INET6;
|
||||||
|
|
||||||
|
if (e.bits < 128) {
|
||||||
|
int t = 0, i;
|
||||||
|
|
||||||
|
for (i = 0, bits = e.bits; i < 16; i++) {
|
||||||
|
|
||||||
|
if (bits >= 8)
|
||||||
|
bits -= 8;
|
||||||
|
else {
|
||||||
|
if ((uint8_t) ((e.address_ipv6.s6_addr[i]) << bits) != 0) {
|
||||||
|
t = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bits = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t)
|
||||||
|
pa_log_warn(__FILE__": WARNING: Host part of ACL entry '%s/%u' is not zero!", a, e.bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pa_log(__FILE__": failed to parse address: %s", a);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = pa_xmemdup(&e, sizeof(struct acl_entry));
|
||||||
|
PA_LLIST_PREPEND(struct acl_entry, acl->entries, n);
|
||||||
|
|
||||||
|
pa_xfree(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acl;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
pa_xfree(a);
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pa_ip_acl_free(pa_ip_acl *acl) {
|
||||||
|
assert(acl);
|
||||||
|
|
||||||
|
while (acl->entries) {
|
||||||
|
struct acl_entry *e = acl->entries;
|
||||||
|
PA_LLIST_REMOVE(struct acl_entry, acl->entries, e);
|
||||||
|
pa_xfree(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_xfree(acl);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pa_ip_acl_check(pa_ip_acl *acl, int fd) {
|
||||||
|
struct sockaddr_storage sa;
|
||||||
|
struct acl_entry *e;
|
||||||
|
socklen_t salen;
|
||||||
|
|
||||||
|
assert(acl);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
salen = sizeof(sa);
|
||||||
|
if (getpeername(fd, (struct sockaddr*) &sa, &salen) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sa.ss_family != AF_INET && sa.ss_family != AF_INET6)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sa.ss_family == AF_INET && salen != sizeof(struct sockaddr_in))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (sa.ss_family == AF_INET6 && salen != sizeof(struct sockaddr_in6))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (e = acl->entries; e; e = e->next) {
|
||||||
|
|
||||||
|
if (e->family != sa.ss_family)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (e->family == AF_INET) {
|
||||||
|
struct sockaddr_in *sai = (struct sockaddr_in*) &sa;
|
||||||
|
|
||||||
|
if (e->bits == 0 || /* this needs special handling because >> takes the right-hand side modulo 32 */
|
||||||
|
(ntohl(sai->sin_addr.s_addr ^ e->address_ipv4.s_addr) >> (32 - e->bits)) == 0)
|
||||||
|
return 1;
|
||||||
|
} else if (e->family == AF_INET6) {
|
||||||
|
int i, bits ;
|
||||||
|
struct sockaddr_in6 *sai = (struct sockaddr_in6*) &sa;
|
||||||
|
|
||||||
|
if (e->bits == 128)
|
||||||
|
return memcmp(&sai->sin6_addr, &e->address_ipv6, 16) == 0;
|
||||||
|
|
||||||
|
if (e->bits == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (i = 0, bits = e->bits; i < 16; i++) {
|
||||||
|
|
||||||
|
if (bits >= 8) {
|
||||||
|
if (sai->sin6_addr.s6_addr[i] != e->address_ipv6.s6_addr[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
bits -= 8;
|
||||||
|
} else {
|
||||||
|
if ((sai->sin6_addr.s6_addr[i] ^ e->address_ipv6.s6_addr[i]) >> (8 - bits) != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bits == 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
31
src/pulsecore/ipacl.h
Normal file
31
src/pulsecore/ipacl.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef fooparseaddrhfoo
|
||||||
|
#define fooparseaddrhfoo
|
||||||
|
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of PulseAudio.
|
||||||
|
|
||||||
|
PulseAudio is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
PulseAudio is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with PulseAudio; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||||
|
USA.
|
||||||
|
***/
|
||||||
|
|
||||||
|
typedef struct pa_ip_acl pa_ip_acl;
|
||||||
|
|
||||||
|
pa_ip_acl* pa_ip_acl_new(const char *s);
|
||||||
|
void pa_ip_acl_free(pa_ip_acl *acl);
|
||||||
|
int pa_ip_acl_check(pa_ip_acl *acl, int fd);
|
||||||
|
|
||||||
|
#endif
|
||||||
117
src/tests/ipacl-test.c
Normal file
117
src/tests/ipacl-test.c
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* $Id$ */
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <pulsecore/ipacl.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
struct sockaddr_in sa;
|
||||||
|
struct sockaddr_in6 sa6;
|
||||||
|
int fd;
|
||||||
|
int r;
|
||||||
|
pa_ip_acl *acl;
|
||||||
|
|
||||||
|
fd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
sa.sin_family = AF_INET;
|
||||||
|
sa.sin_port = htons(22);
|
||||||
|
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
|
||||||
|
|
||||||
|
r = connect(fd, (struct sockaddr*) &sa, sizeof(sa));
|
||||||
|
assert(r >= 0);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("127.0.0.1");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("127.0.0.2/0");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("127.0.0.1/32");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("127.0.0.1/7");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("127.0.0.2");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("127.0.0.0/8;0.0.0.0/32");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("128.0.0.2/9");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("::1/9");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
fd = socket(PF_INET6, SOCK_STREAM, 0);
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
memset(&sa6, 0, sizeof(sa6));
|
||||||
|
sa6.sin6_family = AF_INET6;
|
||||||
|
sa6.sin6_port = htons(22);
|
||||||
|
inet_pton(AF_INET6, "::1", &sa6.sin6_addr);
|
||||||
|
|
||||||
|
r = connect(fd, (struct sockaddr*) &sa6, sizeof(sa6));
|
||||||
|
assert(r >= 0);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("::1");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("::1/9");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("::/0");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("::2/128");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("::2/127");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 0)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
acl = pa_ip_acl_new("::2/126");
|
||||||
|
assert(acl);
|
||||||
|
printf("result=%u (should be 1)\n", pa_ip_acl_check(acl, fd));
|
||||||
|
pa_ip_acl_free(acl);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue