mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
AST-2014-007: Fix DOS by consuming the number of allowed HTTP connections.
Simply establishing a TCP connection and never sending anything to the configured HTTP port in http.conf will tie up a HTTP connection. Since there is a maximum number of open HTTP sessions allowed at a time you can block legitimate connections. A similar problem exists if a HTTP request is started but never finished. * Added http.conf session_inactivity timer option to close HTTP connections that aren't doing anything. Defaults to 30000 ms. * Removed the undocumented manager.conf block-sockets option. It interferes with TCP/TLS inactivity timeouts. * AMI and SIP TLS connections now have better authentication timeout protection. Though I didn't remove the bizzare TLS timeout polling code from chan_sip. * chan_sip can now handle SSL certificate renegotiations in the middle of a session. It couldn't do that before because the socket was non-blocking and the SSL calls were not restarted as documented by the OpenSSL documentation. * Fixed an off nominal leak of the ssl struct in handle_tcptls_connection() if the FILE stream failed to open and the SSL certificate negotiations failed. The patch creates a custom FILE stream handler to give the created FILE streams inactivity timeout and timeout after a specific moment in time capability. This approach eliminates the need for code using the FILE stream to be redesigned to deal with the timeouts. This patch indirectly fixes most of ASTERISK-18345 by fixing the usage of the SSL_read/SSL_write operations. ASTERISK-23673 #close Reported by: Richard Mudgett ........ Merged revisions 415841 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 415854 from http://svn.asterisk.org/svn/asterisk/branches/11 ........ Merged revisions 415896 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@415907 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
538
main/tcptls.c
538
main/tcptls.c
@@ -50,102 +50,483 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||
#include "asterisk/astobj2.h"
|
||||
#include "asterisk/pbx.h"
|
||||
|
||||
/*! \brief
|
||||
* replacement read/write functions for SSL support.
|
||||
* We use wrappers rather than SSL_read/SSL_write directly so
|
||||
* we can put in some debugging.
|
||||
/*! ao2 object used for the FILE stream fopencookie()/funopen() cookie. */
|
||||
struct ast_tcptls_stream {
|
||||
/*! SSL state if not NULL */
|
||||
SSL *ssl;
|
||||
/*!
|
||||
* \brief Start time from when an I/O sequence must complete
|
||||
* by struct ast_tcptls_stream.timeout.
|
||||
*
|
||||
* \note If struct ast_tcptls_stream.start.tv_sec is zero then
|
||||
* start time is the current I/O request.
|
||||
*/
|
||||
struct timeval start;
|
||||
/*!
|
||||
* \brief The socket returned by accept().
|
||||
*
|
||||
* \note Set to -1 if the stream is closed.
|
||||
*/
|
||||
int fd;
|
||||
/*!
|
||||
* \brief Timeout in ms relative to struct ast_tcptls_stream.start
|
||||
* to wait for an event on struct ast_tcptls_stream.fd.
|
||||
*
|
||||
* \note Set to -1 to disable timeout.
|
||||
* \note The socket needs to be set to non-blocking for the timeout
|
||||
* feature to work correctly.
|
||||
*/
|
||||
int timeout;
|
||||
};
|
||||
|
||||
void ast_tcptls_stream_set_timeout_disable(struct ast_tcptls_stream *stream)
|
||||
{
|
||||
ast_assert(stream != NULL);
|
||||
|
||||
stream->timeout = -1;
|
||||
}
|
||||
|
||||
void ast_tcptls_stream_set_timeout_inactivity(struct ast_tcptls_stream *stream, int timeout)
|
||||
{
|
||||
ast_assert(stream != NULL);
|
||||
|
||||
stream->start.tv_sec = 0;
|
||||
stream->timeout = timeout;
|
||||
}
|
||||
|
||||
void ast_tcptls_stream_set_timeout_sequence(struct ast_tcptls_stream *stream, struct timeval start, int timeout)
|
||||
{
|
||||
ast_assert(stream != NULL);
|
||||
|
||||
stream->start = start;
|
||||
stream->timeout = timeout;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief fopencookie()/funopen() stream read function.
|
||||
*
|
||||
* \param cookie Stream control data.
|
||||
* \param buf Where to put read data.
|
||||
* \param size Size of the buffer.
|
||||
*
|
||||
* \retval number of bytes put into buf.
|
||||
* \retval 0 on end of file.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
|
||||
#ifdef DO_SSL
|
||||
static HOOK_T ssl_read(void *cookie, char *buf, LEN_T len)
|
||||
static HOOK_T tcptls_stream_read(void *cookie, char *buf, LEN_T size)
|
||||
{
|
||||
int i = SSL_read(cookie, buf, len-1);
|
||||
#if 0
|
||||
if (i >= 0) {
|
||||
buf[i] = '\0';
|
||||
struct ast_tcptls_stream *stream = cookie;
|
||||
struct timeval start;
|
||||
int ms;
|
||||
int res;
|
||||
|
||||
if (!size) {
|
||||
/* You asked for no data you got no data. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!stream || stream->fd == -1) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->start.tv_sec) {
|
||||
start = stream->start;
|
||||
} else {
|
||||
start = ast_tvnow();
|
||||
}
|
||||
|
||||
#if defined(DO_SSL)
|
||||
if (stream->ssl) {
|
||||
for (;;) {
|
||||
res = SSL_read(stream->ssl, buf, size);
|
||||
if (0 < res) {
|
||||
/* We read some payload data. */
|
||||
return res;
|
||||
}
|
||||
switch (SSL_get_error(stream->ssl, res)) {
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
/* Report EOF for a shutdown */
|
||||
ast_debug(1, "TLS clean shutdown alert reading data\n");
|
||||
return 0;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
while ((ms = ast_remaining_ms(start, stream->timeout))) {
|
||||
res = ast_wait_for_input(stream->fd, ms);
|
||||
if (0 < res) {
|
||||
/* Socket is ready to be read. */
|
||||
break;
|
||||
}
|
||||
if (res < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
/* Try again. */
|
||||
continue;
|
||||
}
|
||||
ast_debug(1, "TLS socket error waiting for read data: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
while ((ms = ast_remaining_ms(start, stream->timeout))) {
|
||||
res = ast_wait_for_output(stream->fd, ms);
|
||||
if (0 < res) {
|
||||
/* Socket is ready to be written. */
|
||||
break;
|
||||
}
|
||||
if (res < 0) {
|
||||
if (errno == EINTR || errno == EAGAIN) {
|
||||
/* Try again. */
|
||||
continue;
|
||||
}
|
||||
ast_debug(1, "TLS socket error waiting for write space: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Report EOF for an undecoded SSL or transport error. */
|
||||
ast_debug(1, "TLS transport or SSL error reading data\n");
|
||||
return 0;
|
||||
}
|
||||
if (!ms) {
|
||||
/* Report EOF for a timeout */
|
||||
ast_debug(1, "TLS timeout reading data\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(DO_SSL) */
|
||||
|
||||
for (;;) {
|
||||
res = read(stream->fd, buf, size);
|
||||
if (0 <= res) {
|
||||
return res;
|
||||
}
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
/* Not a retryable error. */
|
||||
ast_debug(1, "TCP socket error reading data: %s\n",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ms = ast_remaining_ms(start, stream->timeout);
|
||||
if (!ms) {
|
||||
/* Report EOF for a timeout */
|
||||
ast_debug(1, "TCP timeout reading data\n");
|
||||
return 0;
|
||||
}
|
||||
ast_wait_for_input(stream->fd, ms);
|
||||
}
|
||||
ast_verb(0, "ssl read size %d returns %d <%s>\n", (int)len, i, buf);
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
|
||||
static HOOK_T ssl_write(void *cookie, const char *buf, LEN_T len)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief fopencookie()/funopen() stream write function.
|
||||
*
|
||||
* \param cookie Stream control data.
|
||||
* \param buf Where to get data to write.
|
||||
* \param size Size of the buffer.
|
||||
*
|
||||
* \retval number of bytes written from buf.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
static HOOK_T tcptls_stream_write(void *cookie, const char *buf, LEN_T size)
|
||||
{
|
||||
#if 0
|
||||
char *s = ast_alloca(len+1);
|
||||
struct ast_tcptls_stream *stream = cookie;
|
||||
struct timeval start;
|
||||
int ms;
|
||||
int res;
|
||||
int written;
|
||||
int remaining;
|
||||
|
||||
strncpy(s, buf, len);
|
||||
s[len] = '\0';
|
||||
ast_verb(0, "ssl write size %d <%s>\n", (int)len, s);
|
||||
#endif
|
||||
return SSL_write(cookie, buf, len);
|
||||
if (!size) {
|
||||
/* You asked to write no data you wrote no data. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!stream || stream->fd == -1) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->start.tv_sec) {
|
||||
start = stream->start;
|
||||
} else {
|
||||
start = ast_tvnow();
|
||||
}
|
||||
|
||||
#if defined(DO_SSL)
|
||||
if (stream->ssl) {
|
||||
written = 0;
|
||||
remaining = size;
|
||||
for (;;) {
|
||||
res = SSL_write(stream->ssl, buf + written, remaining);
|
||||
if (res == remaining) {
|
||||
/* Everything was written. */
|
||||
return size;
|
||||
}
|
||||
if (0 < res) {
|
||||
/* Successfully wrote part of the buffer. Try to write the rest. */
|
||||
written += res;
|
||||
remaining -= res;
|
||||
continue;
|
||||
}
|
||||
switch (SSL_get_error(stream->ssl, res)) {
|
||||
case SSL_ERROR_ZERO_RETURN:
|
||||
ast_debug(1, "TLS clean shutdown alert writing data\n");
|
||||
if (written) {
|
||||
/* Report partial write. */
|
||||
return written;
|
||||
}
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
ms = ast_remaining_ms(start, stream->timeout);
|
||||
if (!ms) {
|
||||
/* Report partial write. */
|
||||
ast_debug(1, "TLS timeout writing data (want read)\n");
|
||||
return written;
|
||||
}
|
||||
ast_wait_for_input(stream->fd, ms);
|
||||
break;
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
ms = ast_remaining_ms(start, stream->timeout);
|
||||
if (!ms) {
|
||||
/* Report partial write. */
|
||||
ast_debug(1, "TLS timeout writing data (want write)\n");
|
||||
return written;
|
||||
}
|
||||
ast_wait_for_output(stream->fd, ms);
|
||||
break;
|
||||
default:
|
||||
/* Undecoded SSL or transport error. */
|
||||
ast_debug(1, "TLS transport or SSL error writing data\n");
|
||||
if (written) {
|
||||
/* Report partial write. */
|
||||
return written;
|
||||
}
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(DO_SSL) */
|
||||
|
||||
written = 0;
|
||||
remaining = size;
|
||||
for (;;) {
|
||||
res = write(stream->fd, buf + written, remaining);
|
||||
if (res == remaining) {
|
||||
/* Yay everything was written. */
|
||||
return size;
|
||||
}
|
||||
if (0 < res) {
|
||||
/* Successfully wrote part of the buffer. Try to write the rest. */
|
||||
written += res;
|
||||
remaining -= res;
|
||||
continue;
|
||||
}
|
||||
if (errno != EINTR && errno != EAGAIN) {
|
||||
/* Not a retryable error. */
|
||||
ast_debug(1, "TCP socket error writing: %s\n", strerror(errno));
|
||||
if (written) {
|
||||
return written;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
ms = ast_remaining_ms(start, stream->timeout);
|
||||
if (!ms) {
|
||||
/* Report partial write. */
|
||||
ast_debug(1, "TCP timeout writing data\n");
|
||||
return written;
|
||||
}
|
||||
ast_wait_for_output(stream->fd, ms);
|
||||
}
|
||||
}
|
||||
|
||||
static int ssl_close(void *cookie)
|
||||
/*!
|
||||
* \internal
|
||||
* \brief fopencookie()/funopen() stream close function.
|
||||
*
|
||||
* \param cookie Stream control data.
|
||||
*
|
||||
* \retval 0 on success.
|
||||
* \retval -1 on error.
|
||||
*/
|
||||
static int tcptls_stream_close(void *cookie)
|
||||
{
|
||||
int cookie_fd = SSL_get_fd(cookie);
|
||||
int ret;
|
||||
struct ast_tcptls_stream *stream = cookie;
|
||||
|
||||
if (!stream) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->fd != -1) {
|
||||
#if defined(DO_SSL)
|
||||
if (stream->ssl) {
|
||||
int res;
|
||||
|
||||
/*
|
||||
* According to the TLS standard, it is acceptable for an
|
||||
* application to only send its shutdown alert and then
|
||||
* close the underlying connection without waiting for
|
||||
* the peer's response (this way resources can be saved,
|
||||
* as the process can already terminate or serve another
|
||||
* connection).
|
||||
*/
|
||||
res = SSL_shutdown(stream->ssl);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n",
|
||||
SSL_get_error(stream->ssl, res));
|
||||
}
|
||||
|
||||
if (!stream->ssl->server) {
|
||||
/* For client threads, ensure that the error stack is cleared */
|
||||
ERR_remove_state(0);
|
||||
}
|
||||
|
||||
SSL_free(stream->ssl);
|
||||
stream->ssl = NULL;
|
||||
}
|
||||
#endif /* defined(DO_SSL) */
|
||||
|
||||
if (cookie_fd > -1) {
|
||||
/*
|
||||
* According to the TLS standard, it is acceptable for an application to only send its shutdown
|
||||
* alert and then close the underlying connection without waiting for the peer's response (this
|
||||
* way resources can be saved, as the process can already terminate or serve another connection).
|
||||
* Issuing shutdown() is necessary here to avoid a race
|
||||
* condition where the last data written may not appear
|
||||
* in the TCP stream. See ASTERISK-23548
|
||||
*/
|
||||
if ((ret = SSL_shutdown(cookie)) < 0) {
|
||||
ast_log(LOG_ERROR, "SSL_shutdown() failed: %d\n", SSL_get_error(cookie, ret));
|
||||
}
|
||||
|
||||
if (!((SSL*)cookie)->server) {
|
||||
/* For client threads, ensure that the error stack is cleared */
|
||||
ERR_remove_state(0);
|
||||
}
|
||||
|
||||
SSL_free(cookie);
|
||||
/* adding shutdown(2) here has no added benefit */
|
||||
if (close(cookie_fd)) {
|
||||
shutdown(stream->fd, SHUT_RDWR);
|
||||
if (close(stream->fd)) {
|
||||
ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
|
||||
}
|
||||
stream->fd = -1;
|
||||
}
|
||||
ao2_t_ref(stream, -1, "Closed tcptls stream cookie");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* DO_SSL */
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief fopencookie()/funopen() stream destructor function.
|
||||
*
|
||||
* \param cookie Stream control data.
|
||||
*
|
||||
* \return Nothing
|
||||
*/
|
||||
static void tcptls_stream_dtor(void *cookie)
|
||||
{
|
||||
struct ast_tcptls_stream *stream = cookie;
|
||||
|
||||
ast_assert(stream->fd == -1);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief fopencookie()/funopen() stream allocation function.
|
||||
*
|
||||
* \retval stream_cookie on success.
|
||||
* \retval NULL on error.
|
||||
*/
|
||||
static struct ast_tcptls_stream *tcptls_stream_alloc(void)
|
||||
{
|
||||
struct ast_tcptls_stream *stream;
|
||||
|
||||
stream = ao2_alloc_options(sizeof(*stream), tcptls_stream_dtor,
|
||||
AO2_ALLOC_OPT_LOCK_NOLOCK);
|
||||
if (stream) {
|
||||
stream->fd = -1;
|
||||
stream->timeout = -1;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \internal
|
||||
* \brief Open a custom FILE stream for tcptls.
|
||||
*
|
||||
* \param stream Stream cookie control data.
|
||||
* \param ssl SSL state if not NULL.
|
||||
* \param fd Socket file descriptor.
|
||||
* \param timeout ms to wait for an event on fd. -1 if timeout disabled.
|
||||
*
|
||||
* \retval fp on success.
|
||||
* \retval NULL on error.
|
||||
*/
|
||||
static FILE *tcptls_stream_fopen(struct ast_tcptls_stream *stream, SSL *ssl, int fd, int timeout)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
#if defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
|
||||
static const cookie_io_functions_t cookie_funcs = {
|
||||
tcptls_stream_read,
|
||||
tcptls_stream_write,
|
||||
NULL,
|
||||
tcptls_stream_close
|
||||
};
|
||||
#endif /* defined(HAVE_FOPENCOOKIE) */
|
||||
|
||||
if (fd == -1) {
|
||||
/* Socket not open. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
stream->ssl = ssl;
|
||||
stream->fd = fd;
|
||||
stream->timeout = timeout;
|
||||
ao2_t_ref(stream, +1, "Opening tcptls stream cookie");
|
||||
|
||||
#if defined(HAVE_FUNOPEN) /* the BSD interface */
|
||||
fp = funopen(stream, tcptls_stream_read, tcptls_stream_write, NULL,
|
||||
tcptls_stream_close);
|
||||
#elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
|
||||
fp = fopencookie(stream, "w+", cookie_funcs);
|
||||
#else
|
||||
/* could add other methods here */
|
||||
ast_debug(2, "No stream FILE methods attempted!\n");
|
||||
fp = NULL;
|
||||
#endif
|
||||
|
||||
if (!fp) {
|
||||
stream->fd = -1;
|
||||
ao2_t_ref(stream, -1, "Failed to open tcptls stream cookie");
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
HOOK_T ast_tcptls_server_read(struct ast_tcptls_session_instance *tcptls_session, void *buf, size_t count)
|
||||
{
|
||||
if (tcptls_session->fd == -1) {
|
||||
ast_log(LOG_ERROR, "server_read called with an fd of -1\n");
|
||||
if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) {
|
||||
ast_log(LOG_ERROR, "TCP/TLS read called on invalid stream.\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DO_SSL
|
||||
if (tcptls_session->ssl) {
|
||||
return ssl_read(tcptls_session->ssl, buf, count);
|
||||
}
|
||||
#endif
|
||||
return read(tcptls_session->fd, buf, count);
|
||||
return tcptls_stream_read(tcptls_session->stream_cookie, buf, count);
|
||||
}
|
||||
|
||||
HOOK_T ast_tcptls_server_write(struct ast_tcptls_session_instance *tcptls_session, const void *buf, size_t count)
|
||||
{
|
||||
if (tcptls_session->fd == -1) {
|
||||
ast_log(LOG_ERROR, "server_write called with an fd of -1\n");
|
||||
if (!tcptls_session->stream_cookie || tcptls_session->stream_cookie->fd == -1) {
|
||||
ast_log(LOG_ERROR, "TCP/TLS write called on invalid stream.\n");
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DO_SSL
|
||||
if (tcptls_session->ssl) {
|
||||
return ssl_write(tcptls_session->ssl, buf, count);
|
||||
}
|
||||
#endif
|
||||
return write(tcptls_session->fd, buf, count);
|
||||
return tcptls_stream_write(tcptls_session->stream_cookie, buf, count);
|
||||
}
|
||||
|
||||
static void session_instance_destructor(void *obj)
|
||||
{
|
||||
struct ast_tcptls_session_instance *i = obj;
|
||||
|
||||
if (i->stream_cookie) {
|
||||
ao2_t_ref(i->stream_cookie, -1, "Destroying tcptls session instance");
|
||||
i->stream_cookie = NULL;
|
||||
}
|
||||
ast_free(i->overflow_buf);
|
||||
}
|
||||
|
||||
@@ -177,12 +558,21 @@ static void *handle_tcptls_connection(void *data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tcptls_session->stream_cookie = tcptls_stream_alloc();
|
||||
if (!tcptls_session->stream_cookie) {
|
||||
ast_tcptls_close_session_file(tcptls_session);
|
||||
ao2_ref(tcptls_session, -1);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* open a FILE * as appropriate.
|
||||
*/
|
||||
if (!tcptls_session->parent->tls_cfg) {
|
||||
if ((tcptls_session->f = fdopen(tcptls_session->fd, "w+"))) {
|
||||
if(setvbuf(tcptls_session->f, NULL, _IONBF, 0)) {
|
||||
tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie, NULL,
|
||||
tcptls_session->fd, -1);
|
||||
if (tcptls_session->f) {
|
||||
if (setvbuf(tcptls_session->f, NULL, _IONBF, 0)) {
|
||||
ast_tcptls_close_session_file(tcptls_session);
|
||||
}
|
||||
}
|
||||
@@ -192,19 +582,8 @@ static void *handle_tcptls_connection(void *data)
|
||||
SSL_set_fd(tcptls_session->ssl, tcptls_session->fd);
|
||||
if ((ret = ssl_setup(tcptls_session->ssl)) <= 0) {
|
||||
ast_log(LOG_ERROR, "Problem setting up ssl connection: %s\n", ERR_error_string(ERR_get_error(), err));
|
||||
} else {
|
||||
#if defined(HAVE_FUNOPEN) /* the BSD interface */
|
||||
tcptls_session->f = funopen(tcptls_session->ssl, ssl_read, ssl_write, NULL, ssl_close);
|
||||
|
||||
#elif defined(HAVE_FOPENCOOKIE) /* the glibc/linux interface */
|
||||
static const cookie_io_functions_t cookie_funcs = {
|
||||
ssl_read, ssl_write, NULL, ssl_close
|
||||
};
|
||||
tcptls_session->f = fopencookie(tcptls_session->ssl, "w+", cookie_funcs);
|
||||
#else
|
||||
/* could add other methods here */
|
||||
ast_debug(2, "no tcptls_session->f methods attempted!\n");
|
||||
#endif
|
||||
} else if ((tcptls_session->f = tcptls_stream_fopen(tcptls_session->stream_cookie,
|
||||
tcptls_session->ssl, tcptls_session->fd, -1))) {
|
||||
if ((tcptls_session->client && !ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_DONT_VERIFY_SERVER))
|
||||
|| (!tcptls_session->client && ast_test_flag(&tcptls_session->parent->tls_cfg->flags, AST_SSL_VERIFY_CLIENT))) {
|
||||
X509 *peer;
|
||||
@@ -625,21 +1004,18 @@ error:
|
||||
void ast_tcptls_close_session_file(struct ast_tcptls_session_instance *tcptls_session)
|
||||
{
|
||||
if (tcptls_session->f) {
|
||||
/*
|
||||
* Issuing shutdown() is necessary here to avoid a race
|
||||
* condition where the last data written may not appear
|
||||
* in the TCP stream. See ASTERISK-23548
|
||||
*/
|
||||
fflush(tcptls_session->f);
|
||||
if (tcptls_session->fd != -1) {
|
||||
shutdown(tcptls_session->fd, SHUT_RDWR);
|
||||
}
|
||||
if (fclose(tcptls_session->f)) {
|
||||
ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno));
|
||||
}
|
||||
tcptls_session->f = NULL;
|
||||
tcptls_session->fd = -1;
|
||||
} else if (tcptls_session->fd != -1) {
|
||||
/*
|
||||
* Issuing shutdown() is necessary here to avoid a race
|
||||
* condition where the last data written may not appear
|
||||
* in the TCP stream. See ASTERISK-23548
|
||||
*/
|
||||
shutdown(tcptls_session->fd, SHUT_RDWR);
|
||||
if (close(tcptls_session->fd)) {
|
||||
ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno));
|
||||
|
Reference in New Issue
Block a user