Wed Oct 28 11:53:18 2009

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

References __ssl_setup().

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

00330 {
00331    return __ssl_setup(cfg, 0);
00332 }

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

Definition at line 371 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().

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

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 334 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().

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

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

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

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

void* ast_tcptls_server_root ( void *   ) 

Definition at line 228 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().

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

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 427 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().

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

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

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

Referenced by unload_module().

00491 {
00492    if (desc->master != AST_PTHREADT_NULL) {
00493       pthread_cancel(desc->master);
00494       pthread_kill(desc->master, SIGURG);
00495       pthread_join(desc->master, NULL);
00496    }
00497    if (desc->accept_fd != -1)
00498       close(desc->accept_fd);
00499    desc->accept_fd = -1;
00500 }

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

Definition at line 100 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().

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


Generated on Wed Oct 28 11:53:19 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6