Thu Oct 11 06:49:52 2012

Asterisk developer's documentation


tcptls.h File Reference

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

#include "asterisk/utils.h"

Include dependency graph for tcptls.h:

This graph shows which files directly or indirectly include this file:

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)
struct
ast_tcptls_session_instance
ast_tcptls_client_create (struct ast_tcptls_session_args *desc)
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.
HOOK_T ast_tcptls_server_read (struct ast_tcptls_session_instance *ser, void *buf, size_t count)
 replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging.
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, const 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(), __init_manager(), and reload_config().

#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

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 339 of file tcptls.c.

References __ssl_setup().

Referenced by __ast_http_load(), __init_manager(), and reload_config().

00340 {
00341    return __ssl_setup(cfg, 0);
00342 }

struct ast_tcptls_session_instance* ast_tcptls_client_create ( struct ast_tcptls_session_args desc  )  [read]

Definition at line 381 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, ao2_alloc, ao2_ref, ast_debug, ast_inet_ntoa(), ast_log(), ast_mutex_init(), ast_tcptls_session_instance::client, errno, ast_tcptls_session_instance::fd, ast_tcptls_session_args::local_address, ast_tcptls_session_instance::lock, LOG_ERROR, LOG_WARNING, ast_tcptls_session_args::name, ast_tcptls_session_args::old_address, ast_tcptls_session_instance::parent, ast_tcptls_session_instance::remote_address, ast_tcptls_session_args::remote_address, session_instance_destructor(), and ast_tcptls_session_args::worker_fn.

Referenced by app_exec(), and sip_prepare_socket().

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

struct ast_tcptls_session_instance* ast_tcptls_client_start ( struct ast_tcptls_session_instance tcptls_session  )  [read]

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 344 of file tcptls.c.

References __ssl_setup(), ast_tcptls_session_args::accept_fd, ao2_ref, ast_inet_ntoa(), ast_log(), desc, ast_tls_config::enabled, errno, handle_tcptls_connection(), LOG_ERROR, ast_tcptls_session_args::name, ast_tcptls_session_instance::parent, ast_tcptls_session_args::remote_address, and ast_tcptls_session_args::tls_cfg.

Referenced by _sip_tcp_helper_thread(), and app_exec().

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

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

replacement read/write functions for SSL support. We use wrappers rather than SSL_read/SSL_write directly so we can put in some debugging.

Definition at line 86 of file tcptls.c.

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

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 238 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, ao2_alloc, ao2_ref, ast_log(), ast_mutex_init(), ast_pthread_create_detached_background, ast_wait_for_input(), ast_tcptls_session_instance::client, desc, errno, ast_tcptls_session_instance::fd, handle_tcptls_connection(), ast_tcptls_session_instance::lock, LOG_WARNING, ast_tcptls_session_instance::parent, ast_tcptls_session_args::periodic_fn, ast_tcptls_session_args::poll_timeout, ast_tcptls_session_instance::remote_address, and session_instance_destructor().

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

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 440 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, ast_tcptls_session_args::accept_fn, ast_debug, ast_inet_ntoa(), ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, errno, ast_tcptls_session_args::local_address, LOG_ERROR, ast_tcptls_session_args::master, ast_tcptls_session_args::name, and ast_tcptls_session_args::old_address.

Referenced by __ast_http_load(), __init_manager(), and reload_config().

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

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 507 of file tcptls.c.

References ast_tcptls_session_args::accept_fd, ast_debug, AST_PTHREADT_NULL, ast_tcptls_session_args::master, and ast_tcptls_session_args::name.

Referenced by unload_module().

00508 {
00509    if (desc->master != AST_PTHREADT_NULL) {
00510       pthread_cancel(desc->master);
00511       pthread_kill(desc->master, SIGURG);
00512       pthread_join(desc->master, NULL);
00513       desc->master = AST_PTHREADT_NULL;
00514    }
00515    if (desc->accept_fd != -1)
00516       close(desc->accept_fd);
00517    desc->accept_fd = -1;
00518    ast_debug(2, "Stopped server :: %s\n", desc->name);
00519 }

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

Definition at line 101 of file tcptls.c.

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

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 Thu Oct 11 06:49:52 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6