mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-12-04 14:46:30 -05:00
merge work. allow sockets to be marked as ssl capable. This is mainly for /admin
requests but can be used for sources and listeners svn path=/icecast/trunk/icecast/; revision=13650
This commit is contained in:
parent
31ce005ef3
commit
7e5604b993
@ -129,6 +129,13 @@ then
|
|||||||
else
|
else
|
||||||
AC_MSG_NOTICE([YP support disabled])
|
AC_MSG_NOTICE([YP support disabled])
|
||||||
fi
|
fi
|
||||||
|
XIPH_PATH_OPENSSL([
|
||||||
|
XIPH_VAR_APPEND([XIPH_CPPFLAGS],[$OPENSSL_CFLAGS])
|
||||||
|
XIPH_VAR_APPEND([XIPH_LDFLAGS],[$OPENSSL_LDFLAGS])
|
||||||
|
XIPH_VAR_PREPEND([XIPH_LIBS],[$OPENSSL_LIBS])
|
||||||
|
],
|
||||||
|
[ AC_MSG_NOTICE([SSL disabled!])
|
||||||
|
])
|
||||||
|
|
||||||
dnl Make substitutions
|
dnl Make substitutions
|
||||||
|
|
||||||
|
@ -787,6 +787,11 @@ static void _parse_listen_socket(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
listener->port = atoi(tmp);
|
listener->port = atoi(tmp);
|
||||||
if(tmp) xmlFree(tmp);
|
if(tmp) xmlFree(tmp);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(node->name, "ssl") == 0) {
|
||||||
|
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
|
listener->ssl = atoi(tmp);
|
||||||
|
if(tmp) xmlFree(tmp);
|
||||||
|
}
|
||||||
else if (strcmp(node->name, "shoutcast-compat") == 0) {
|
else if (strcmp(node->name, "shoutcast-compat") == 0) {
|
||||||
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
tmp = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
listener->shoutcast_compat = atoi(tmp);
|
listener->shoutcast_compat = atoi(tmp);
|
||||||
@ -898,6 +903,9 @@ static void _parse_paths(xmlDocPtr doc, xmlNodePtr node,
|
|||||||
} else if (strcmp(node->name, "pidfile") == 0) {
|
} else if (strcmp(node->name, "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 (strcmp(node->name, "ssl-certificate") == 0) {
|
||||||
|
if (configuration->cert_file) xmlFree(configuration->cert_file);
|
||||||
|
configuration->cert_file = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
} else if (strcmp(node->name, "webroot") == 0) {
|
} else if (strcmp(node->name, "webroot") == 0) {
|
||||||
if (configuration->webroot_dir && configuration->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) xmlFree(configuration->webroot_dir);
|
if (configuration->webroot_dir && configuration->webroot_dir != CONFIG_DEFAULT_WEBROOT_DIR) xmlFree(configuration->webroot_dir);
|
||||||
configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
configuration->webroot_dir = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
|
||||||
|
@ -99,6 +99,7 @@ typedef struct {
|
|||||||
int port;
|
int port;
|
||||||
char *bind_address;
|
char *bind_address;
|
||||||
int shoutcast_compat;
|
int shoutcast_compat;
|
||||||
|
int ssl;
|
||||||
} listener_t;
|
} listener_t;
|
||||||
|
|
||||||
typedef struct ice_config_tag
|
typedef struct ice_config_tag
|
||||||
@ -149,6 +150,7 @@ typedef struct ice_config_tag
|
|||||||
char *base_dir;
|
char *base_dir;
|
||||||
char *log_dir;
|
char *log_dir;
|
||||||
char *pidfile;
|
char *pidfile;
|
||||||
|
char *cert_file;
|
||||||
char *webroot_dir;
|
char *webroot_dir;
|
||||||
char *adminroot_dir;
|
char *adminroot_dir;
|
||||||
aliases *aliases;
|
aliases *aliases;
|
||||||
|
27
src/client.c
27
src/client.c
@ -142,18 +142,12 @@ int client_read_bytes (client_t *client, void *buf, unsigned len)
|
|||||||
client->refbuf->len -= len;
|
client->refbuf->len -= len;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
bytes = sock_read_bytes (client->con->sock, buf, len);
|
bytes = client->con->read (client->con, buf, len);
|
||||||
if (bytes > 0)
|
|
||||||
return bytes;
|
|
||||||
|
|
||||||
if (bytes < 0)
|
if (bytes == -1 && client->con->error)
|
||||||
{
|
DEBUG0 ("reading from connection has failed");
|
||||||
if (sock_recoverable (sock_error()))
|
|
||||||
return -1;
|
return bytes;
|
||||||
WARN0 ("source connection has died");
|
|
||||||
}
|
|
||||||
client->con->error = 1;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -205,14 +199,11 @@ void client_send_403(client_t *client, const char *reason)
|
|||||||
/* helper function for sending the data to a client */
|
/* helper function for sending the data to a client */
|
||||||
int client_send_bytes (client_t *client, const void *buf, unsigned len)
|
int client_send_bytes (client_t *client, const void *buf, unsigned len)
|
||||||
{
|
{
|
||||||
int ret = sock_write_bytes (client->con->sock, buf, len);
|
int ret = client->con->send (client->con, buf, len);
|
||||||
if (ret < 0 && !sock_recoverable (sock_error()))
|
|
||||||
{
|
if (client->con->error)
|
||||||
DEBUG0 ("Client connection died");
|
DEBUG0 ("Client connection died");
|
||||||
client->con->error = 1;
|
|
||||||
}
|
|
||||||
if (ret > 0)
|
|
||||||
client->con->sent_bytes += ret;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
150
src/connection.c
150
src/connection.c
@ -103,6 +103,11 @@ static volatile client_queue_t *_con_queue = NULL, **_con_queue_tail = &_con_que
|
|||||||
static mutex_t _con_queue_mutex;
|
static mutex_t _con_queue_mutex;
|
||||||
static mutex_t _req_queue_mutex;
|
static mutex_t _req_queue_mutex;
|
||||||
|
|
||||||
|
static int ssl_ok;
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
static SSL_CTX *ssl_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
rwlock_t _source_shutdown_rwlock;
|
rwlock_t _source_shutdown_rwlock;
|
||||||
|
|
||||||
static void *_handle_connection(void *arg);
|
static void *_handle_connection(void *arg);
|
||||||
@ -129,6 +134,10 @@ void connection_shutdown(void)
|
|||||||
{
|
{
|
||||||
if (!_initialized) return;
|
if (!_initialized) return;
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
SSL_CTX_free (ssl_ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
thread_cond_destroy(&global.shutdown_cond);
|
thread_cond_destroy(&global.shutdown_cond);
|
||||||
thread_rwlock_destroy(&_source_shutdown_rwlock);
|
thread_rwlock_destroy(&_source_shutdown_rwlock);
|
||||||
thread_mutex_destroy(&_con_queue_mutex);
|
thread_mutex_destroy(&_con_queue_mutex);
|
||||||
@ -150,6 +159,126 @@ static unsigned long _next_connection_id(void)
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
static void get_ssl_certificate ()
|
||||||
|
{
|
||||||
|
SSL_METHOD *method;
|
||||||
|
ice_config_t *config;
|
||||||
|
ssl_ok = 0;
|
||||||
|
|
||||||
|
SSL_load_error_strings(); /* readable error messages */
|
||||||
|
SSL_library_init(); /* initialize library */
|
||||||
|
|
||||||
|
method = SSLv23_server_method();
|
||||||
|
ssl_ctx = SSL_CTX_new (method);
|
||||||
|
|
||||||
|
config = config_get_config ();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (config->cert_file == NULL)
|
||||||
|
break;
|
||||||
|
if (SSL_CTX_use_certificate_file (ssl_ctx, config->cert_file, SSL_FILETYPE_PEM) <= 0)
|
||||||
|
{
|
||||||
|
WARN1 ("Invalid cert file %s", config->cert_file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (SSL_CTX_use_PrivateKey_file (ssl_ctx, config->cert_file, SSL_FILETYPE_PEM) <= 0)
|
||||||
|
{
|
||||||
|
WARN1 ("Invalid private key file %s", config->cert_file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!SSL_CTX_check_private_key (ssl_ctx))
|
||||||
|
{
|
||||||
|
ERROR0 ("Invalid icecast.pem - Private key doesn't"
|
||||||
|
" match cert public key");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ssl_ok = 1;
|
||||||
|
INFO1 ("SSL certificate found at %s", config->cert_file);
|
||||||
|
} while (0);
|
||||||
|
config_release_config ();
|
||||||
|
if (ssl_ok == 0)
|
||||||
|
INFO0 ("No SSL capability on any configured ports");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* handlers for reading and writing a connection_t when there is ssl
|
||||||
|
* configured on the listening port
|
||||||
|
*/
|
||||||
|
static int connection_read_ssl (connection_t *con, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
int bytes = SSL_read (con->ssl, buf, len);
|
||||||
|
|
||||||
|
if (bytes < 0)
|
||||||
|
{
|
||||||
|
switch (SSL_get_error (con->ssl, bytes))
|
||||||
|
{
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
con->error = 1;
|
||||||
|
}
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int connection_send_ssl (connection_t *con, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
int bytes = SSL_write (con->ssl, buf, len);
|
||||||
|
|
||||||
|
if (bytes < 0)
|
||||||
|
{
|
||||||
|
switch (SSL_get_error (con->ssl, bytes))
|
||||||
|
{
|
||||||
|
case SSL_ERROR_WANT_READ:
|
||||||
|
case SSL_ERROR_WANT_WRITE:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
con->error = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
con->sent_bytes += bytes;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* SSL not compiled in, so at least log it */
|
||||||
|
static void get_ssl_certificate ()
|
||||||
|
{
|
||||||
|
ssl_ok = 0;
|
||||||
|
INFO0 ("No SSL capability");
|
||||||
|
}
|
||||||
|
#endif /* HAVE_OPENSSL */
|
||||||
|
|
||||||
|
|
||||||
|
/* handlers (default) for reading and writing a connection_t, no encrpytion
|
||||||
|
* used just straight access to the socket
|
||||||
|
*/
|
||||||
|
static int connection_read (connection_t *con, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
int bytes = sock_read_bytes (con->sock, buf, len);
|
||||||
|
if (bytes == 0)
|
||||||
|
con->error = 1;
|
||||||
|
if (bytes == -1 && !sock_recoverable (sock_error()))
|
||||||
|
con->error = 1;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int connection_send (connection_t *con, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
int bytes = sock_write_bytes (con->sock, buf, len);
|
||||||
|
if (bytes < 0)
|
||||||
|
{
|
||||||
|
if (!sock_recoverable (sock_error()))
|
||||||
|
con->error = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
con->sent_bytes += bytes;
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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;
|
||||||
@ -161,11 +290,26 @@ connection_t *connection_create (sock_t sock, sock_t serversock, char *ip)
|
|||||||
con->con_time = time(NULL);
|
con->con_time = time(NULL);
|
||||||
con->id = _next_connection_id();
|
con->id = _next_connection_id();
|
||||||
con->ip = ip;
|
con->ip = ip;
|
||||||
|
con->read = connection_read;
|
||||||
|
con->send = connection_send;
|
||||||
}
|
}
|
||||||
|
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* prepare connection for interacting over a SSL connection
|
||||||
|
*/
|
||||||
|
void connection_uses_ssl (connection_t *con)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
con->read = connection_read_ssl;
|
||||||
|
con->send = connection_send_ssl;
|
||||||
|
con->ssl = SSL_new (ssl_ctx);
|
||||||
|
SSL_set_accept_state (con->ssl);
|
||||||
|
SSL_set_fd (con->ssl, con->sock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static int wait_for_serversock(int timeout)
|
static int wait_for_serversock(int timeout)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_POLL
|
#ifdef HAVE_POLL
|
||||||
@ -437,6 +581,7 @@ void connection_accept_loop(void)
|
|||||||
{
|
{
|
||||||
connection_t *con;
|
connection_t *con;
|
||||||
|
|
||||||
|
get_ssl_certificate ();
|
||||||
tid = thread_create ("connection thread", _handle_connection, NULL, THREAD_ATTACHED);
|
tid = thread_create ("connection thread", _handle_connection, NULL, THREAD_ATTACHED);
|
||||||
|
|
||||||
while (global.running == ICE_RUNNING)
|
while (global.running == ICE_RUNNING)
|
||||||
@ -478,6 +623,8 @@ void connection_accept_loop(void)
|
|||||||
{
|
{
|
||||||
if (config->listeners[i].shoutcast_compat)
|
if (config->listeners[i].shoutcast_compat)
|
||||||
node->shoutcast = 1;
|
node->shoutcast = 1;
|
||||||
|
if (config->listeners[i].ssl && ssl_ok)
|
||||||
|
connection_uses_ssl (client->con);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config_release_config();
|
config_release_config();
|
||||||
@ -1069,5 +1216,8 @@ void connection_close(connection_t *con)
|
|||||||
sock_close(con->sock);
|
sock_close(con->sock);
|
||||||
if (con->ip) free(con->ip);
|
if (con->ip) free(con->ip);
|
||||||
if (con->host) free(con->host);
|
if (con->host) free(con->host);
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
if (con->ssl) { SSL_shutdown (con->ssl); SSL_free (con->ssl); }
|
||||||
|
#endif
|
||||||
free(con);
|
free(con);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "httpp/httpp.h"
|
#include "httpp/httpp.h"
|
||||||
#include "thread/thread.h"
|
#include "thread/thread.h"
|
||||||
@ -35,6 +40,12 @@ typedef struct connection_tag
|
|||||||
int serversock;
|
int serversock;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
#ifdef HAVE_OPENSSL
|
||||||
|
SSL *ssl; /* SSL handler */
|
||||||
|
#endif
|
||||||
|
int (*send)(struct connection_tag *handle, const void *buf, size_t len);
|
||||||
|
int (*read)(struct connection_tag *handle, void *buf, size_t len);
|
||||||
|
|
||||||
char *ip;
|
char *ip;
|
||||||
char *host;
|
char *host;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user