Thu Apr 8 01:23:41 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>
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

Defines

#define AST_CERTFILE   "asterisk.pem"
#define DO_SSL
#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 DO_SSL

Definition at line 54 of file tcptls.h.

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

References __ssl_setup().

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

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

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

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

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

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

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

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

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

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

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

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

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

Referenced by unload_module().

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

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 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1