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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
147
src/connection.c
147
src/connection.c
@ -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,6 +172,8 @@ 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);
|
||||
@ -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,10 +537,12 @@ 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);
|
||||
|
||||
if (accept_ip_address (ip))
|
||||
con = connection_create (sock, serversock, ip);
|
||||
if (con)
|
||||
return con;
|
||||
@ -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));
|
||||
|
||||
|
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;
|
||||
}
|
||||
|
||||
|
||||
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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user