1
0
mirror of https://gitlab.xiph.org/xiph/icecast-server.git synced 2024-12-04 14:46:30 -05:00

Cleanup: moved ban and allow file support into generic implementation

ban and allow file support has been moved into a generic implementation
that can be re-used by later code such as proxy matching or other
blacklisting.
See: #1959
This commit is contained in:
Philipp Schafft 2015-01-05 22:06:53 +00:00
parent 3653a1f812
commit d24dda61d0
4 changed files with 211 additions and 123 deletions

View File

@ -10,7 +10,7 @@ INCLUDES = -I./common/
noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \ noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \
global.h util.h curl.h slave.h source.h stats.h refbuf.h client.h playlist.h \ global.h util.h curl.h slave.h source.h stats.h refbuf.h client.h playlist.h \
compat.h fserve.h xslt.h yp.h md5.h \ compat.h fserve.h xslt.h yp.h md5.h matchfile.h \
event.h event_log.h event_exec.h event_url.h \ event.h event_log.h event_exec.h event_url.h \
acl.h auth.h \ acl.h auth.h \
format.h format_ogg.h format_mp3.h format_ebml.h \ format.h format_ogg.h format_mp3.h format_ebml.h \
@ -18,7 +18,7 @@ noinst_HEADERS = admin.h cfgfile.h logging.h sighandler.h connection.h \
format_kate.h format_skeleton.h format_opus.h format_kate.h format_skeleton.h format_opus.h
icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \ icecast_SOURCES = cfgfile.c main.c logging.c sighandler.c connection.c global.c \
util.c curl.c slave.c source.c stats.c refbuf.c client.c playlist.c \ util.c curl.c slave.c source.c stats.c refbuf.c client.c playlist.c \
xslt.c fserve.c admin.c md5.c \ xslt.c fserve.c admin.c md5.c matchfile.c \
format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \ format.c format_ogg.c format_mp3.c format_midi.c format_flac.c format_ebml.c \
format_kate.c format_skeleton.c format_opus.c \ format_kate.c format_skeleton.c format_opus.c \
event.c event_log.c event_exec.c \ event.c event_log.c event_exec.c \

View File

@ -25,7 +25,6 @@
#include <sys/poll.h> #include <sys/poll.h>
#endif #endif
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32 #ifndef _WIN32
#include <sys/socket.h> #include <sys/socket.h>
@ -59,6 +58,7 @@
#include "format_mp3.h" #include "format_mp3.h"
#include "admin.h" #include "admin.h"
#include "auth.h" #include "auth.h"
#include "matchfile.h"
#define CATMODULE "connection" #define CATMODULE "connection"
@ -91,14 +91,6 @@ typedef struct _thread_queue_tag {
struct _thread_queue_tag *next; struct _thread_queue_tag *next;
} thread_queue_t; } thread_queue_t;
typedef struct
{
char *filename;
time_t file_recheck;
time_t file_mtime;
avl_tree *contents;
} cache_file_contents;
static spin_t _connection_lock; // protects _current_id, _con_queue, _con_queue_tail static spin_t _connection_lock; // protects _current_id, _con_queue, _con_queue_tail
static volatile unsigned long _current_id = 0; static volatile unsigned long _current_id = 0;
static int _initialized = 0; static int _initialized = 0;
@ -111,28 +103,12 @@ static SSL_CTX *ssl_ctx;
#endif #endif
/* filtering client connection based on IP */ /* filtering client connection based on IP */
static cache_file_contents banned_ip, allowed_ip; static matchfile_t *banned_ip, *allowed_ip;
rwlock_t _source_shutdown_rwlock; rwlock_t _source_shutdown_rwlock;
static void _handle_connection(void); static void _handle_connection(void);
static int compare_ip (void *arg, void *a, void *b)
{
const char *ip = (const char *)a;
const char *pattern = (const char *)b;
return strcmp (pattern, ip);
}
static int free_filtered_ip (void*x)
{
free (x);
return 1;
}
void connection_initialize(void) void connection_initialize(void)
{ {
if (_initialized) if (_initialized)
@ -147,12 +123,6 @@ void connection_initialize(void)
_con_queue = NULL; _con_queue = NULL;
_con_queue_tail = &_con_queue; _con_queue_tail = &_con_queue;
banned_ip.contents = NULL;
banned_ip.file_mtime = 0;
allowed_ip.contents = NULL;
allowed_ip.file_mtime = 0;
_initialized = 1; _initialized = 1;
} }
@ -164,8 +134,8 @@ void connection_shutdown(void)
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
SSL_CTX_free (ssl_ctx); SSL_CTX_free (ssl_ctx);
#endif #endif
if (banned_ip.contents) avl_tree_free (banned_ip.contents, free_filtered_ip); matchfile_release(banned_ip);
if (allowed_ip.contents) avl_tree_free (allowed_ip.contents, free_filtered_ip); matchfile_release(allowed_ip);
thread_cond_destroy(&global.shutdown_cond); thread_cond_destroy(&global.shutdown_cond);
thread_rwlock_destroy(&_source_shutdown_rwlock); thread_rwlock_destroy(&_source_shutdown_rwlock);
@ -305,86 +275,23 @@ static int connection_send(connection_t *con, const void *buf, size_t len)
} }
/* function to handle the re-populating of the avl tree containing IP addresses
* for deciding whether a connection of an incoming request is to be dropped.
*/
static void recheck_ip_file(cache_file_contents *cache)
{
time_t now = time(NULL);
if (now >= cache->file_recheck) {
struct stat file_stat;
FILE *file = NULL;
int count = 0;
avl_tree *new_ips;
char line[MAX_LINE_LEN];
cache->file_recheck = now + 10;
if (cache->filename == NULL) {
if (cache->contents) {
avl_tree_free (cache->contents, free_filtered_ip);
cache->contents = NULL;
}
return;
}
if (stat(cache->filename, &file_stat) < 0) {
ICECAST_LOG_WARN("Failed to check status of \"%s\": %s", cache->filename, strerror(errno));
return;
}
if (file_stat.st_mtime == cache->file_mtime)
return; /* common case, no update to file */
cache->file_mtime = file_stat.st_mtime;
file = fopen (cache->filename, "r");
if (file == NULL) {
ICECAST_LOG_WARN("Failed to open file \"%s\": %s", cache->filename, strerror (errno));
return;
}
new_ips = avl_tree_new(compare_ip, NULL);
while (get_line(file, line, MAX_LINE_LEN)) {
char *str;
if(!line[0] || line[0] == '#')
continue;
count++;
str = strdup (line);
if (str)
avl_insert(new_ips, str);
}
fclose (file);
ICECAST_LOG_INFO("%d entries read from file \"%s\"", count, cache->filename);
if (cache->contents)
avl_tree_free(cache->contents, free_filtered_ip);
cache->contents = new_ips;
}
}
/* return 0 if the passed ip address is not to be handled by icecast, non-zero otherwise */ /* return 0 if the passed ip address is not to be handled by icecast, non-zero otherwise */
static int accept_ip_address(char *ip) static int accept_ip_address(char *ip) {
{ if (matchfile_match(banned_ip, ip) > 0) {
void *result; ICECAST_LOG_DEBUG("%s is banned", ip);
return 0;
recheck_ip_file(&banned_ip);
recheck_ip_file(&allowed_ip);
if (banned_ip.contents) {
if (avl_get_by_key (banned_ip.contents, ip, &result) == 0) {
ICECAST_LOG_DEBUG("%s is banned", ip);
return 0;
}
} }
if (allowed_ip.contents) {
if (avl_get_by_key (allowed_ip.contents, ip, &result) == 0) { if (matchfile_match(allowed_ip, ip) > 0) {
ICECAST_LOG_DEBUG("%s is allowed", ip); ICECAST_LOG_DEBUG("%s is allowed", ip);
return 1; return 1;
} else { } else if (allowed_ip) {
ICECAST_LOG_DEBUG("%s is not allowed", ip); /* we are not on allow list but there is one, so reject */
return 0; ICECAST_LOG_DEBUG("%s is not allowed", ip);
} return 0;
} }
/* default: allow */
return 1; return 1;
} }
@ -1522,11 +1429,6 @@ int connection_setup_sockets (ice_config_t *config)
int count = 0; int count = 0;
listener_t *listener, **prev; listener_t *listener, **prev;
free (banned_ip.filename);
banned_ip.filename = NULL;
free (allowed_ip.filename);
allowed_ip.filename = NULL;
global_lock(); global_lock();
if (global.serversock) { if (global.serversock) {
for (; count < global.server_sockets; count++) for (; count < global.server_sockets; count++)
@ -1540,11 +1442,17 @@ int connection_setup_sockets (ice_config_t *config)
} }
/* setup the banned/allowed IP filenames from the xml */ /* setup the banned/allowed IP filenames from the xml */
if (config->banfile) if (config->banfile) {
banned_ip.filename = strdup(config->banfile); matchfile_release(banned_ip);
banned_ip = matchfile_new(config->banfile);
if (!banned_ip)
ICECAST_LOG_ERROR("Can not create ban object, bad!");
}
if (config->allowfile) if (config->allowfile) {
allowed_ip.filename = strdup(config->allowfile); matchfile_release(allowed_ip);
allowed_ip = matchfile_new(config->allowfile);
}
count = 0; count = 0;
global.serversock = calloc(config->listen_sock_count, sizeof(sock_t)); global.serversock = calloc(config->listen_sock_count, sizeof(sock_t));

160
src/matchfile.c Normal file
View File

@ -0,0 +1,160 @@
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2015, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "matchfile.h"
#include "logging.h"
#include "util.h" /* for MAX_LINE_LEN and get_line() */
#include "common/avl/avl.h"
#define CATMODULE "matchfile"
struct matchfile_tag {
/* reference counter */
size_t refcount;
/* filename of input file */
char *filename;
time_t file_recheck;
time_t file_mtime;
avl_tree *contents;
};
static int __func_free(void *x) {
free(x);
return 1;
}
static int __func_compare (void *arg, void *a, void *b) {
return strcmp(b, a);
}
static void __func_recheck(matchfile_t *file) {
time_t now = time(NULL);
struct stat file_stat;
FILE *input = NULL;
avl_tree *new_contents;
char line[MAX_LINE_LEN];
if (now < file->file_recheck)
return;
file->file_recheck = now + 10;
if (stat(file->filename, &file_stat) < 0) {
ICECAST_LOG_WARN("failed to check status of \"%s\": %s", file->filename, strerror(errno));
return;
}
if (file_stat.st_mtime == file->file_mtime)
return; /* common case, no update to file */
file->file_mtime = file_stat.st_mtime;
input = fopen(file->filename, "r");
if (!input) {
ICECAST_LOG_WARN("Failed to open file \"%s\": %s", file->filename, strerror(errno));
return;
}
new_contents = avl_tree_new(__func_compare, NULL);
while (get_line(input, line, MAX_LINE_LEN)) {
char *str;
if(!line[0] || line[0] == '#')
continue;
str = strdup(line);
if (str)
avl_insert(new_contents, str);
}
fclose(input);
if (file->contents) avl_tree_free(file->contents, __func_free);
file->contents = new_contents;
}
matchfile_t *matchfile_new(const char *filename) {
matchfile_t *ret;
if (!filename)
return NULL;
ret = calloc(1, sizeof(matchfile_t));
if (!ret)
return NULL;
ret->refcount = 1;
ret->filename = strdup(filename);
ret->file_mtime = 0;
ret->file_recheck = 0;
if (!ret->filename) {
matchfile_release(ret);
return NULL;
}
/* load initial database */
__func_recheck(ret);
return ret;
}
int matchfile_addref(matchfile_t *file) {
if (!file)
return -1;
file->refcount++;
return 0;
}
int matchfile_release(matchfile_t *file) {
if (!file)
return -1;
file->refcount--;
if (file->refcount)
return 0;
if (file->contents)
avl_tree_free(file->contents, __func_free);
free(file->filename);
free(file);
return 0;
}
/* we are not const char *key because of avl_get_by_key()... */
int matchfile_match(matchfile_t *file, char *key) {
void *result;
if (!file)
return -1;
/* reload database if needed */
__func_recheck(file);
if (!file->contents)
return 0;
return avl_get_by_key(file->contents, (void*)key, &result) == 0 ? 1 : 0;
}

20
src/matchfile.h Normal file
View File

@ -0,0 +1,20 @@
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2015, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
*/
#ifndef __MATCHFILE_H__
#define __MATCHFILE_H__
struct matchfile_tag;
typedef struct matchfile_tag matchfile_t;
matchfile_t *matchfile_new(const char *filename);
int matchfile_addref(matchfile_t *file);
int matchfile_release(matchfile_t *file);
int matchfile_match(matchfile_t *file, char *key);
#endif /* __MATCHFILE_H__ */