mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
Allow for files to be specified that will contain IPs that can be used to
accept or deny client connections. svn path=/icecast/trunk/icecast/; revision=14039
This commit is contained in:
parent
9379e4e051
commit
4b5f00993d
@ -66,19 +66,6 @@ static void htpasswd_clear(auth_t *self) {
|
|||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_line(FILE *file, char *buf, int len)
|
|
||||||
{
|
|
||||||
if(fgets(buf, len, file)) {
|
|
||||||
int len = strlen(buf);
|
|
||||||
if(len > 0 && buf[len-1] == '\n') {
|
|
||||||
buf[--len] = 0;
|
|
||||||
if(len > 0 && buf[len-1] == '\r')
|
|
||||||
buf[--len] = 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* md5 hash */
|
/* md5 hash */
|
||||||
static char *get_hash(const char *data, int len)
|
static char *get_hash(const char *data, int len)
|
||||||
@ -95,8 +82,6 @@ static char *get_hash(const char *data, int len)
|
|||||||
return util_bin_to_hex(digest, 16);
|
return util_bin_to_hex(digest, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_LINE_LEN 512
|
|
||||||
|
|
||||||
|
|
||||||
static int compare_users (void *arg, void *a, void *b)
|
static int compare_users (void *arg, void *a, void *b)
|
||||||
{
|
{
|
||||||
|
@ -192,6 +192,8 @@ void config_clear(ice_config_t *c)
|
|||||||
if (c->cert_file) xmlFree(c->cert_file);
|
if (c->cert_file) xmlFree(c->cert_file);
|
||||||
if (c->pidfile)
|
if (c->pidfile)
|
||||||
xmlFree(c->pidfile);
|
xmlFree(c->pidfile);
|
||||||
|
if (c->banfile) xmlFree(c->banfile);
|
||||||
|
if (c->allowfile) xmlFree(c->allowfile);
|
||||||
if (c->playlist_log) xmlFree(c->playlist_log);
|
if (c->playlist_log) xmlFree(c->playlist_log);
|
||||||
if (c->access_log) xmlFree(c->access_log);
|
if (c->access_log) xmlFree(c->access_log);
|
||||||
if (c->error_log) xmlFree(c->error_log);
|
if (c->error_log) xmlFree(c->error_log);
|
||||||
@ -906,6 +908,12 @@ static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
} else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) {
|
} else if (xmlStrcmp (node->name, XMLSTR("pidfile")) == 0) {
|
||||||
if (configuration->pidfile) xmlFree(configuration->pidfile);
|
if (configuration->pidfile) xmlFree(configuration->pidfile);
|
||||||
configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
configuration->pidfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
|
} else if (xmlStrcmp (node->name, XMLSTR("deny-ip")) == 0) {
|
||||||
|
if (configuration->banfile) xmlFree(configuration->banfile);
|
||||||
|
configuration->banfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
|
} else if (xmlStrcmp (node->name, XMLSTR("allow-ip")) == 0) {
|
||||||
|
if (configuration->allowfile) xmlFree(configuration->allowfile);
|
||||||
|
configuration->allowfile = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
} else if (xmlStrcmp (node->name, XMLSTR("ssl-certificate")) == 0) {
|
} else if (xmlStrcmp (node->name, XMLSTR("ssl-certificate")) == 0) {
|
||||||
if (configuration->cert_file) xmlFree(configuration->cert_file);
|
if (configuration->cert_file) xmlFree(configuration->cert_file);
|
||||||
configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
|
@ -156,6 +156,8 @@ typedef struct ice_config_tag
|
|||||||
char *base_dir;
|
char *base_dir;
|
||||||
char *log_dir;
|
char *log_dir;
|
||||||
char *pidfile;
|
char *pidfile;
|
||||||
|
char *banfile;
|
||||||
|
char *allowfile;
|
||||||
char *cert_file;
|
char *cert_file;
|
||||||
char *webroot_dir;
|
char *webroot_dir;
|
||||||
char *adminroot_dir;
|
char *adminroot_dir;
|
||||||
|
147
src/connection.c
147
src/connection.c
@ -22,6 +22,8 @@
|
|||||||
#ifdef HAVE_POLL
|
#ifdef HAVE_POLL
|
||||||
#include <sys/poll.h>
|
#include <sys/poll.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@ -93,6 +95,14 @@ 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 mutex_t _connection_mutex;
|
static mutex_t _connection_mutex;
|
||||||
static volatile unsigned long _current_id = 0;
|
static volatile unsigned long _current_id = 0;
|
||||||
static int _initialized = 0;
|
static int _initialized = 0;
|
||||||
@ -108,10 +118,29 @@ static int ssl_ok;
|
|||||||
static SSL_CTX *ssl_ctx;
|
static SSL_CTX *ssl_ctx;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* filtering client connection based on IP */
|
||||||
|
cache_file_contents banned_ip, allowed_ip;
|
||||||
|
|
||||||
rwlock_t _source_shutdown_rwlock;
|
rwlock_t _source_shutdown_rwlock;
|
||||||
|
|
||||||
static void *_handle_connection(void *arg);
|
static void *_handle_connection(void *arg);
|
||||||
|
|
||||||
|
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) return;
|
if (_initialized) return;
|
||||||
@ -127,6 +156,12 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +172,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);
|
||||||
|
if (allowed_ip.contents) avl_tree_free (allowed_ip.contents, free_filtered_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);
|
||||||
@ -275,6 +312,101 @@ 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)
|
||||||
|
{
|
||||||
|
WARN2 ("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)
|
||||||
|
{
|
||||||
|
WARN2("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);
|
||||||
|
INFO2 ("%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 */
|
||||||
|
static int accept_ip_address (char *ip)
|
||||||
|
{
|
||||||
|
void *result;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
DEBUG1 ("%s is banned", ip);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allowed_ip.contents)
|
||||||
|
{
|
||||||
|
if (avl_get_by_key (allowed_ip.contents, ip, &result) == 0)
|
||||||
|
{
|
||||||
|
DEBUG1 ("%s is allowed", ip);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG1 ("%s is not allowed", ip);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
connection_t *connection_create (sock_t sock, sock_t serversock, char *ip)
|
connection_t *connection_create (sock_t sock, sock_t serversock, char *ip)
|
||||||
{
|
{
|
||||||
connection_t *con;
|
connection_t *con;
|
||||||
@ -392,7 +524,6 @@ static int wait_for_serversock(int timeout)
|
|||||||
static connection_t *_accept_connection(void)
|
static connection_t *_accept_connection(void)
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
connection_t *con;
|
|
||||||
char *ip;
|
char *ip;
|
||||||
int serversock;
|
int serversock;
|
||||||
|
|
||||||
@ -406,10 +537,12 @@ static connection_t *_accept_connection(void)
|
|||||||
sock = sock_accept(serversock, ip, MAX_ADDR_LEN);
|
sock = sock_accept(serversock, ip, MAX_ADDR_LEN);
|
||||||
if (sock >= 0)
|
if (sock >= 0)
|
||||||
{
|
{
|
||||||
|
connection_t *con = NULL;
|
||||||
/* Make any IPv4 mapped IPv6 address look like a normal IPv4 address */
|
/* Make any IPv4 mapped IPv6 address look like a normal IPv4 address */
|
||||||
if (strncmp (ip, "::ffff:", 7) == 0)
|
if (strncmp (ip, "::ffff:", 7) == 0)
|
||||||
memmove (ip, ip+7, strlen (ip+7)+1);
|
memmove (ip, ip+7, strlen (ip+7)+1);
|
||||||
|
|
||||||
|
if (accept_ip_address (ip))
|
||||||
con = connection_create (sock, serversock, ip);
|
con = connection_create (sock, serversock, ip);
|
||||||
if (con)
|
if (con)
|
||||||
return con;
|
return con;
|
||||||
@ -1218,6 +1351,11 @@ 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)
|
||||||
{
|
{
|
||||||
@ -1232,6 +1370,13 @@ int connection_setup_sockets (ice_config_t *config)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* setup the banned/allowed IP filenames from the xml */
|
||||||
|
if (config->banfile)
|
||||||
|
banned_ip.filename = strdup (config->banfile);
|
||||||
|
|
||||||
|
if (config->allowfile)
|
||||||
|
allowed_ip.filename = strdup (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));
|
||||||
|
|
||||||
|
15
src/util.c
15
src/util.c
@ -673,3 +673,18 @@ char *util_conv_string (const char *string, const char *in_charset, const char *
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int get_line(FILE *file, char *buf, size_t siz)
|
||||||
|
{
|
||||||
|
if(fgets(buf, (int)siz, file)) {
|
||||||
|
size_t len = strlen(buf);
|
||||||
|
if(len > 0 && buf[len-1] == '\n') {
|
||||||
|
buf[--len] = 0;
|
||||||
|
if(len > 0 && buf[len-1] == '\r')
|
||||||
|
buf[--len] = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#define READ_ENTIRE_HEADER 1
|
#define READ_ENTIRE_HEADER 1
|
||||||
#define READ_LINE 0
|
#define READ_LINE 0
|
||||||
|
|
||||||
|
#define MAX_LINE_LEN 512
|
||||||
|
|
||||||
int util_timed_wait_for_fd(int fd, int timeout);
|
int util_timed_wait_for_fd(int fd, int timeout);
|
||||||
int util_read_header(int sock, char *buff, unsigned long len, int entire);
|
int util_read_header(int sock, char *buff, unsigned long len, int entire);
|
||||||
int util_check_valid_extension(const char *uri);
|
int util_check_valid_extension(const char *uri);
|
||||||
@ -53,4 +55,5 @@ struct tm *localtime_r (const time_t *timep, struct tm *result);
|
|||||||
#endif
|
#endif
|
||||||
char *util_conv_string (const char *string, const char *in_charset, const char *out_charset);
|
char *util_conv_string (const char *string, const char *in_charset, const char *out_charset);
|
||||||
|
|
||||||
|
int get_line(FILE *file, char *buf, size_t siz);
|
||||||
#endif /* __UTIL_H__ */
|
#endif /* __UTIL_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user