Commit 4b5f0099 authored by Karl Heyes's avatar Karl Heyes

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
parent 9379e4e0
......@@ -66,19 +66,6 @@ static void htpasswd_clear(auth_t *self) {
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 */
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);
}
#define MAX_LINE_LEN 512
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->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->access_log) xmlFree(c->access_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) {
if (configuration->pidfile) xmlFree(configuration->pidfile);
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) {
if (configuration->cert_file) xmlFree(configuration->cert_file);
configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
......
......@@ -156,6 +156,8 @@ typedef struct ice_config_tag
char *base_dir;
char *log_dir;
char *pidfile;
char *banfile;
char *allowfile;
char *cert_file;
char *webroot_dir;
char *adminroot_dir;
......
......@@ -22,6 +22,8 @@
#ifdef HAVE_POLL
#include <sys/poll.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <sys/time.h>
......@@ -93,6 +95,14 @@ typedef struct _thread_queue_tag {
struct _thread_queue_tag *next;
} 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 volatile unsigned long _current_id = 0;
static int _initialized = 0;
......@@ -108,10 +118,29 @@ static int ssl_ok;
static SSL_CTX *ssl_ctx;
#endif
/* filtering client connection based on IP */
cache_file_contents banned_ip, allowed_ip;
rwlock_t _source_shutdown_rwlock;
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)
{
if (_initialized) return;
......@@ -127,6 +156,12 @@ void connection_initialize(void)
_con_queue = NULL;
_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;
}
......@@ -137,7 +172,9 @@ void connection_shutdown(void)
#ifdef HAVE_OPENSSL
SSL_CTX_free (ssl_ctx);
#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_rwlock_destroy(&_source_shutdown_rwlock);
thread_mutex_destroy(&_con_queue_mutex);
......@@ -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 *con;
......@@ -392,7 +524,6 @@ static int wait_for_serversock(int timeout)
static connection_t *_accept_connection(void)
{
int sock;
connection_t *con;
char *ip;
int serversock;
......@@ -406,11 +537,13 @@ static connection_t *_accept_connection(void)
sock = sock_accept(serversock, ip, MAX_ADDR_LEN);
if (sock >= 0)
{
connection_t *con = NULL;
/* Make any IPv4 mapped IPv6 address look like a normal IPv4 address */
if (strncmp (ip, "::ffff:", 7) == 0)
memmove (ip, ip+7, strlen (ip+7)+1);
con = connection_create (sock, serversock, ip);
if (accept_ip_address (ip))
con = connection_create (sock, serversock, ip);
if (con)
return con;
sock_close (sock);
......@@ -1218,6 +1351,11 @@ int connection_setup_sockets (ice_config_t *config)
int count = 0;
listener_t *listener, **prev;
free (banned_ip.filename);
banned_ip.filename = NULL;
free (allowed_ip.filename);
allowed_ip.filename = NULL;
global_lock();
if (global.serversock)
{
......@@ -1232,6 +1370,13 @@ int connection_setup_sockets (ice_config_t *config)
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;
global.serversock = calloc (config->listen_sock_count, sizeof (sock_t));
......
......@@ -673,3 +673,18 @@ char *util_conv_string (const char *string, const char *in_charset, const char *
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_LINE 0
#define MAX_LINE_LEN 512
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_check_valid_extension(const char *uri);
......@@ -53,4 +55,5 @@ struct tm *localtime_r (const time_t *timep, struct tm *result);
#endif
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__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment