Fri Jun 19 12:10:53 2009

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_start (struct ast_tcptls_session_args *desc)
 A generic client routine for a TCP client and starts a thread for handling accept().
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 324 of file tcptls.c.

References __ssl_setup().

00325 {
00326    return __ssl_setup(cfg, 0);
00327 }

struct ast_tcptls_session_instance* ast_tcptls_client_start ( struct ast_tcptls_session_args desc  ) 

A generic client routine for a TCP client 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 329 of file tcptls.c.

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

Referenced by sip_prepare_socket().

00330 {
00331    int flags;
00332    int x = 1;
00333    struct ast_tcptls_session_instance *tcptls_session = NULL;
00334 
00335    /* Do nothing if nothing has changed */
00336    if (!memcmp(&desc->old_address, &desc->remote_address, sizeof(desc->old_address))) {
00337       ast_debug(1, "Nothing changed in %s\n", desc->name);
00338       return NULL;
00339    }
00340 
00341    desc->old_address = desc->remote_address;
00342 
00343    if (desc->accept_fd != -1)
00344       close(desc->accept_fd);
00345 
00346    desc->accept_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
00347    if (desc->accept_fd < 0) {
00348       ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n",
00349          desc->name, strerror(errno));
00350       return NULL;
00351    }
00352 
00353    /* if a local address was specified, bind to it so the connection will
00354       originate from the desired address */
00355    if (desc->local_address.sin_family != 0) {
00356       setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00357       if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) {
00358          ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n",
00359          desc->name,
00360             ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port),
00361             strerror(errno));
00362          goto error;
00363       }
00364    }
00365 
00366    if (connect(desc->accept_fd, (const struct sockaddr *) &desc->remote_address, sizeof(desc->remote_address))) {
00367       ast_log(LOG_ERROR, "Unable to connect %s to %s:%d: %s\n",
00368          desc->name,
00369          ast_inet_ntoa(desc->remote_address.sin_addr), ntohs(desc->remote_address.sin_port),
00370          strerror(errno));
00371       goto error;
00372    }
00373 
00374    if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor)))
00375       goto error;
00376 
00377    ast_mutex_init(&tcptls_session->lock);
00378 
00379    flags = fcntl(desc->accept_fd, F_GETFL);
00380    fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK);
00381 
00382    tcptls_session->fd = desc->accept_fd;
00383    tcptls_session->parent = desc;
00384    tcptls_session->parent->worker_fn = NULL;
00385    memcpy(&tcptls_session->remote_address, &desc->remote_address, sizeof(tcptls_session->remote_address));
00386 
00387    tcptls_session->client = 1;
00388 
00389    if (desc->tls_cfg) {
00390       desc->tls_cfg->enabled = 1;
00391       __ssl_setup(desc->tls_cfg, 1);
00392    }
00393 
00394    ao2_ref(tcptls_session, +1);
00395    if (!handle_tls_connection(tcptls_session))
00396       goto error;
00397 
00398    return tcptls_session;
00399 
00400 error:
00401    close(desc->accept_fd);
00402    desc->accept_fd = -1;
00403    if (tcptls_session)
00404       ao2_ref(tcptls_session, -1);
00405    return NULL;
00406 }

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

Definition at line 85 of file tcptls.c.

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

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 224 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_tls_connection(), LOG_WARNING, and session_instance_destructor().

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

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

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

00409 {
00410    int flags;
00411    int x = 1;
00412    
00413    /* Do nothing if nothing has changed */
00414    if (!memcmp(&desc->old_address, &desc->local_address, sizeof(desc->old_address))) {
00415       ast_debug(1, "Nothing changed in %s\n", desc->name);
00416       return;
00417    }
00418    
00419    desc->old_address = desc->local_address;
00420    
00421    /* Shutdown a running server if there is one */
00422    if (desc->master != AST_PTHREADT_NULL) {
00423       pthread_cancel(desc->master);
00424       pthread_kill(desc->master, SIGURG);
00425       pthread_join(desc->master, NULL);
00426    }
00427    
00428    if (desc->accept_fd != -1)
00429       close(desc->accept_fd);
00430 
00431    /* If there's no new server, stop here */
00432    if (desc->local_address.sin_family == 0) {
00433       return;
00434    }
00435 
00436    desc->accept_fd = socket(AF_INET, SOCK_STREAM, 0);
00437    if (desc->accept_fd < 0) {
00438       ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n",
00439          desc->name, strerror(errno));
00440       return;
00441    }
00442    
00443    setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x));
00444    if (bind(desc->accept_fd, (struct sockaddr *) &desc->local_address, sizeof(desc->local_address))) {
00445       ast_log(LOG_ERROR, "Unable to bind %s to %s:%d: %s\n",
00446          desc->name,
00447          ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port),
00448          strerror(errno));
00449       goto error;
00450    }
00451    if (listen(desc->accept_fd, 10)) {
00452       ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name);
00453       goto error;
00454    }
00455    flags = fcntl(desc->accept_fd, F_GETFL);
00456    fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK);
00457    if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) {
00458       ast_log(LOG_ERROR, "Unable to launch thread for %s on %s:%d: %s\n",
00459          desc->name,
00460          ast_inet_ntoa(desc->local_address.sin_addr), ntohs(desc->local_address.sin_port),
00461          strerror(errno));
00462       goto error;
00463    }
00464    return;
00465 
00466 error:
00467    close(desc->accept_fd);
00468    desc->accept_fd = -1;
00469 }

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

References AST_PTHREADT_NULL, and desc.

Referenced by unload_module().

00472 {
00473    if (desc->master != AST_PTHREADT_NULL) {
00474       pthread_cancel(desc->master);
00475       pthread_kill(desc->master, SIGURG);
00476       pthread_join(desc->master, NULL);
00477    }
00478    if (desc->accept_fd != -1)
00479       close(desc->accept_fd);
00480    desc->accept_fd = -1;
00481 }

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, ast_tcptls_session_instance::ssl, and ssl_write().

Referenced by __sip_xmit().

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 Fri Jun 19 12:10:53 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7