Wed Aug 18 22:34:34 2010

Asterisk developer's documentation


tcptls.h File Reference

Generic support for tcp/tls servers in Asterisk. More...

#include "asterisk/utils.h"
#include <openssl/ssl.h>
#include <openssl/err.h>

Go to the source code of this file.

Data Structures

struct  ast_tcptls_session_args
 arguments for the accepting thread More...
struct  ast_tcptls_session_instance
struct  ast_tls_config
struct  SSL
struct  SSL_CTX

Defines

#define AST_CERTFILE   "asterisk.pem"
#define HOOK_T   ssize_t
#define LEN_T   size_t

Enumerations

enum  ast_ssl_flags { AST_SSL_VERIFY_CLIENT = (1 << 0), AST_SSL_DONT_VERIFY_SERVER = (1 << 1), AST_SSL_IGNORE_COMMON_NAME = (1 << 2) }

Functions

int ast_ssl_setup (struct ast_tls_config *cfg)
ast_tcptls_session_instanceast_tcptls_client_create (struct ast_tcptls_session_args *desc)
ast_tcptls_session_instanceast_tcptls_client_start (struct ast_tcptls_session_instance *tcptls_session)
 attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned.
HOOK_T ast_tcptls_server_read (struct ast_tcptls_session_instance *ser, void *buf, size_t count)
void * ast_tcptls_server_root (void *)
void ast_tcptls_server_start (struct ast_tcptls_session_args *desc)
 This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a thread for handling accept().
void ast_tcptls_server_stop (struct ast_tcptls_session_args *desc)
 Shutdown a running server if there is one.
HOOK_T ast_tcptls_server_write (struct ast_tcptls_session_instance *ser, void *buf, size_t count)


Detailed Description

Generic support for tcp/tls servers in Asterisk.

Note:
In order to have TLS/SSL support, we need the openssl libraries. Still we can decide whether or not to use them by commenting in or out the DO_SSL macro.
TLS/SSL support is basically implemented by reading from a config file (currently http.conf and sip.conf) the names of the certificate and cipher to use, and then run ssl_setup() to create an appropriate SSL_CTX (ssl_ctx) If we support multiple domains, presumably we need to read multiple certificates.

When we are requested to open a TLS socket, we run make_file_from_fd() on the socket, to do the necessary setup. At the moment the context's name is hardwired in the function, but we can certainly make it into an extra parameter to the function.

We declare most of ssl support variables unconditionally, because their number is small and this simplifies the code.

Note:
The ssl-support variables (ssl_ctx, do_ssl, certfile, cipher) and their setup should be moved to a more central place, e.g. asterisk.conf and the source files that processes it. Similarly, ssl_setup() should be run earlier in the startup process so modules have it available.

Definition in file tcptls.h.


Define Documentation

#define AST_CERTFILE   "asterisk.pem"

SSL support

Definition at line 67 of file tcptls.h.

Referenced by __ast_http_load(), and __init_manager().

#define HOOK_T   ssize_t

Definition at line 148 of file tcptls.h.

#define LEN_T   size_t

Definition at line 149 of file tcptls.h.


Enumeration Type Documentation

enum ast_ssl_flags

Enumerator:
AST_SSL_VERIFY_CLIENT  Verify certificate when acting as server
AST_SSL_DONT_VERIFY_SERVER  Don't verify certificate when connecting to a server
AST_SSL_IGNORE_COMMON_NAME  Don't compare "Common Name" against IP or hostname

Definition at line 69 of file tcptls.h.

00069                    {
00070    /*! Verify certificate when acting as server */
00071    AST_SSL_VERIFY_CLIENT = (1 << 0),
00072    /*! Don't verify certificate when connecting to a server */
00073    AST_SSL_DONT_VERIFY_SERVER = (1 << 1),
00074    /*! Don't compare "Common Name" against IP or hostname */
00075    AST_SSL_IGNORE_COMMON_NAME = (1 << 2)
00076 };


Function Documentation

int ast_ssl_setup ( struct ast_tls_config cfg  ) 

Definition at line 335 of file tcptls.c.

References __ssl_setup().

00336 {
00337    return __ssl_setup(cfg, 0);
00338 }

struct ast_tcptls_session_instance* ast_tcptls_client_create ( struct ast_tcptls_session_args desc  ) 

Definition at line 377 of file tcptls.c.

References ao2_alloc, ao2_ref, ast_debug, ast_inet_ntoa(), ast_log(), ast_mutex_init(), desc, errno, LOG_ERROR, LOG_WARNING, and session_instance_destructor().

Referenced by sip_prepare_socket().

00378 {
00379    int x = 1;
00380    struct ast_tcptls_session_instance *tcptls_session = NULL;
00381 
00382    /* Do nothing if nothing has changed */
00383    if (!memcmp(&desc->old_address, &desc->remote_address, sizeof(desc->old_address))) {
00384       ast_debug(1, "Nothing changed in %s\n", desc->name);
00385       return NULL;
00386    }
00387 
00388    desc->old_address = desc->remote_address;
00389 
00390    if (desc->accept_fd != -1)
00391       close(desc->accept_fd);
00392 
00393    desc->accept_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00394    if (desc->accept_fd < 0) {
00395       ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
00396          desc->name, strerror(errno));
00397       return NULL;
00398    }
00399 
00400    /* if a local address was specified, bind to it so the connection will
00401       originate from the desired address */
00402    if (desc->local_address.sin_family != 0) {
00403       setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00404       if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) {
00405          ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n",
00406          desc->name,
00407             ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port),
00408             strerror(errno));
00409          goto error;
00410       }
00411    }
00412 
00413    if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor)))
00414       goto error;
00415 
00416    ast_mutex_init(&tcptls_session->lock);
00417    tcptls_session->client = 1;
00418    tcptls_session->fd = desc->accept_fd;
00419    tcptls_session->parent = desc;
00420    tcptls_session->parent->worker_fn = NULL;
00421    memcpy(&tcptls_session->remote_address, &desc->remote_address, sizeof(tcptls_session->remote_address));
00422 
00423    return tcptls_session;
00424 
00425 error:
00426    close(desc->accept_fd);
00427    desc->accept_fd = -1;
00428    if (tcptls_session)
00429       ao2_ref(tcptls_session, -1);
00430    return NULL;
00431 }

struct ast_tcptls_session_instance* ast_tcptls_client_start ( struct ast_tcptls_session_instance tcptls_session  ) 

attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented, fd and file are closed, and NULL is returned.

Definition at line 340 of file tcptls.c.

References __ssl_setup(), ao2_ref, ast_inet_ntoa(), ast_log(), desc, errno, handle_tcptls_connection(), LOG_ERROR, and ast_tcptls_session_instance::parent.

Referenced by _sip_tcp_helper_thread().

00341 {
00342    struct ast_tcptls_session_args *desc;
00343    int flags;
00344 
00345    if (!(desc = tcptls_session->parent)) {
00346       goto client_start_error;
00347    }
00348 
00349    if (connect(desc->accept_fd, (const struct sockaddr *) &desc->remote_address, sizeof(desc->remote_address))) {
00350       ast_log(LOG_ERROR, "Unable to connect %s to %s:%d: %s\n",
00351          desc->name,
00352          ast_inet_ntoa(desc->remote_address.sin_addr), ntohs(desc->remote_address.sin_port),
00353          strerror(errno));
00354       goto client_start_error;
00355    }
00356 
00357    flags = fcntl(desc->accept_fd, F_GETFL);
00358    fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK);
00359 
00360    if (desc->tls_cfg) {
00361       desc->tls_cfg->enabled = 1;
00362       __ssl_setup(desc->tls_cfg, 1);
00363    }
00364 
00365    return handle_tcptls_connection(tcptls_session);
00366 
00367 client_start_error:
00368    close(desc->accept_fd);
00369    desc->accept_fd = -1;
00370    if (tcptls_session) {
00371       ao2_ref(tcptls_session, -1);
00372    }
00373    return NULL;
00374 
00375 }

HOOK_T ast_tcptls_server_read ( struct ast_tcptls_session_instance ser,
void *  buf,
size_t  count 
)

Definition at line 86 of file tcptls.c.

References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_read().

00087 {
00088    if (tcptls_session->fd == -1) {
00089       ast_log(LOG_ERROR, "server_read called with an fd of -1\n");
00090       errno = EIO;
00091       return -1;
00092    }
00093 
00094 #ifdef DO_SSL
00095    if (tcptls_session->ssl)
00096       return ssl_read(tcptls_session->ssl, buf, count);
00097 #endif
00098    return read(tcptls_session->fd, buf, count);
00099 }

void* ast_tcptls_server_root ( void *   ) 

Definition at line 234 of file tcptls.c.

References ao2_alloc, ao2_ref, ast_log(), ast_mutex_init(), ast_pthread_create_detached_background, ast_wait_for_input(), desc, errno, handle_tcptls_connection(), LOG_WARNING, and session_instance_destructor().

00235 {
00236    struct ast_tcptls_session_args *desc = data;
00237    int fd;
00238    struct sockaddr_in sin;
00239    socklen_t sinlen;
00240    struct ast_tcptls_session_instance *tcptls_session;
00241    pthread_t launched;
00242    
00243    for (;;) {
00244       int i, flags;
00245 
00246       if (desc->periodic_fn)
00247          desc->periodic_fn(desc);
00248       i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout);
00249       if (i <= 0)
00250          continue;
00251       sinlen = sizeof(sin);
00252       fd = accept(desc->accept_fd, (struct sockaddr *) &sin, &sinlen);
00253       if (fd < 0) {
00254          if ((errno != EAGAIN) && (errno != EINTR))
00255             ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno));
00256          continue;
00257       }
00258       tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor);
00259       if (!tcptls_session) {
00260          ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno));
00261          close(fd);
00262          continue;
00263       }
00264 
00265       ast_mutex_init(&tcptls_session->lock);
00266 
00267       flags = fcntl(fd, F_GETFL);
00268       fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
00269       tcptls_session->fd = fd;
00270       tcptls_session->parent = desc;
00271       memcpy(&tcptls_session->remote_address, &sin, sizeof(tcptls_session->remote_address));
00272 
00273       tcptls_session->client = 0;
00274          
00275       /* This thread is now the only place that controls the single ref to tcptls_session */
00276       if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) {
00277          ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno));
00278          close(tcptls_session->fd);
00279          ao2_ref(tcptls_session, -1);
00280       }
00281    }
00282    return NULL;
00283 }

void ast_tcptls_server_start ( struct ast_tcptls_session_args desc  ) 

This is a generic (re)start routine for a TCP server, which does the socket/bind/listen and starts a thread for handling accept().

Version:
1.6.1 changed desc parameter to be of ast_tcptls_session_args type

Definition at line 433 of file tcptls.c.

References ast_debug, ast_inet_ntoa(), ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, desc, errno, and LOG_ERROR.

00434 {
00435    int flags;
00436    int x = 1;
00437    
00438    /* Do nothing if nothing has changed */
00439    if (!memcmp(&desc->old_address, &desc->local_address, sizeof(desc->old_address))) {
00440       ast_debug(1, "Nothing changed in %s\n", desc->name);
00441       return;
00442    }
00443    
00444    desc->old_address = desc->local_address;
00445    
00446    /* Shutdown a running server if there is one */
00447    if (desc->master != AST_PTHREADT_NULL) {
00448       pthread_cancel(desc->master);
00449       pthread_kill(desc->master, SIGURG);
00450       pthread_join(desc->master, NULL);
00451    }
00452    
00453    if (desc->accept_fd != -1)
00454       close(desc->accept_fd);
00455 
00456    /* If there's no new server, stop here */
00457    if (desc->local_address.sin_family == 0) {
00458       return;
00459    }
00460 
00461    desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0);
00462    if (desc->accept_fd < 0) {
00463       ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
00464          desc->name, strerror(errno));
00465       return;
00466    }
00467    
00468    setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00469    if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) {
00470       ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n",
00471          desc->name,
00472          ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port),
00473          strerror(errno));
00474       goto error;
00475    }
00476    if (listen(desc->accept_fd, 10)) {
00477       ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
00478       goto error;
00479    }
00480    flags = fcntl(desc->accept_fd, F_GETFL);
00481    fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
00482    if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
00483       ast_log(LOG_ERROR, "Unable to launch thread for %s on %s:%d: %s\n",
00484          desc->name,
00485          ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port),
00486          strerror(errno));
00487       goto error;
00488    }
00489    return;
00490 
00491 error:
00492    close(desc->accept_fd);
00493    desc->accept_fd = -1;
00494 }

void ast_tcptls_server_stop ( struct ast_tcptls_session_args desc  ) 

Shutdown a running server if there is one.

Version:
1.6.1 changed desc parameter to be of ast_tcptls_session_args type

Definition at line 496 of file tcptls.c.

References AST_PTHREADT_NULL, and desc.

Referenced by unload_module().

00497 {
00498    if (desc->master != AST_PTHREADT_NULL) {
00499       pthread_cancel(desc->master);
00500       pthread_kill(desc->master, SIGURG);
00501       pthread_join(desc->master, NULL);
00502    }
00503    if (desc->accept_fd != -1)
00504       close(desc->accept_fd);
00505    desc->accept_fd = -1;
00506 }

HOOK_T ast_tcptls_server_write ( struct ast_tcptls_session_instance ser,
void *  buf,
size_t  count 
)

Definition at line 101 of file tcptls.c.

References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_write().

Referenced by _sip_tcp_helper_thread().

00102 {
00103    if (tcptls_session->fd == -1) {
00104       ast_log(LOG_ERROR, "server_write called with an fd of -1\n");
00105       errno = EIO;
00106       return -1;
00107    }
00108 
00109 #ifdef DO_SSL
00110    if (tcptls_session->ssl)
00111       return ssl_write(tcptls_session->ssl, buf, count);
00112 #endif
00113    return write(tcptls_session->fd, buf, count);
00114 }


Generated on Wed Aug 18 22:34:34 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7