#include "asterisk/netsock2.h"
#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 |
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), AST_SSL_SSLV2_CLIENT = (1 << 3), AST_SSL_SSLV3_CLIENT = (1 << 4), AST_SSL_TLSV1_CLIENT = (1 << 5) } |
Functions | |
int | ast_ssl_setup (struct ast_tls_config *cfg) |
Set up an SSL server. | |
void | ast_ssl_teardown (struct ast_tls_config *cfg) |
free resources used by an SSL server | |
ast_tcptls_session_instance * | ast_tcptls_client_create (struct ast_tcptls_session_args *desc) |
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. | |
void | ast_tcptls_close_session_file (struct ast_tcptls_session_instance *tcptls_session) |
Closes a tcptls session instance's file and/or file descriptor. The tcptls_session will be set to NULL and it's file descriptor will be set to -1 by this function. | |
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, const void *buf, size_t count) |
int | ast_tls_read_conf (struct ast_tls_config *tls_cfg, struct ast_tcptls_session_args *tls_desc, const char *varname, const char *value) |
Used to parse conf files containing tls/ssl options. |
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.
Definition in file tcptls.h.
#define AST_CERTFILE "asterisk.pem" |
SSL support
Definition at line 68 of file tcptls.h.
Referenced by __ast_http_load(), __init_manager(), and reload_config().
enum ast_ssl_flags |
Definition at line 70 of file tcptls.h.
00070 { 00071 /*! Verify certificate when acting as server */ 00072 AST_SSL_VERIFY_CLIENT = (1 << 0), 00073 /*! Don't verify certificate when connecting to a server */ 00074 AST_SSL_DONT_VERIFY_SERVER = (1 << 1), 00075 /*! Don't compare "Common Name" against IP or hostname */ 00076 AST_SSL_IGNORE_COMMON_NAME = (1 << 2), 00077 /*! Use SSLv2 for outgoing client connections */ 00078 AST_SSL_SSLV2_CLIENT = (1 << 3), 00079 /*! Use SSLv3 for outgoing client connections */ 00080 AST_SSL_SSLV3_CLIENT = (1 << 4), 00081 /*! Use TLSv1 for outgoing client connections */ 00082 AST_SSL_TLSV1_CLIENT = (1 << 5) 00083 };
int ast_ssl_setup | ( | struct ast_tls_config * | cfg | ) |
Set up an SSL server.
cfg | Configuration for the SSL server |
1 | Success | |
0 | Failure |
Definition at line 401 of file tcptls.c.
References __ssl_setup().
00402 { 00403 return __ssl_setup(cfg, 0); 00404 }
void ast_ssl_teardown | ( | struct ast_tls_config * | cfg | ) |
free resources used by an SSL server
cfg | Configuration for the SSL server |
Definition at line 406 of file tcptls.c.
References ast_tls_config::ssl_ctx.
Referenced by unload_module().
00407 { 00408 #ifdef DO_SSL 00409 if (cfg->ssl_ctx) { 00410 SSL_CTX_free(cfg->ssl_ctx); 00411 cfg->ssl_ctx = NULL; 00412 } 00413 #endif 00414 }
struct ast_tcptls_session_instance* ast_tcptls_client_create | ( | struct ast_tcptls_session_args * | desc | ) |
Definition at line 453 of file tcptls.c.
References ao2_alloc, ao2_ref, ast_bind(), ast_debug, ast_log(), ast_mutex_init, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), desc, errno, LOG_ERROR, LOG_WARNING, and session_instance_destructor().
Referenced by sip_prepare_socket().
00454 { 00455 int x = 1; 00456 struct ast_tcptls_session_instance *tcptls_session = NULL; 00457 00458 /* Do nothing if nothing has changed */ 00459 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { 00460 ast_debug(1, "Nothing changed in %s\n", desc->name); 00461 return NULL; 00462 } 00463 00464 /* If we return early, there is no connection */ 00465 ast_sockaddr_setnull(&desc->old_address); 00466 00467 if (desc->accept_fd != -1) 00468 close(desc->accept_fd); 00469 00470 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? 00471 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); 00472 if (desc->accept_fd < 0) { 00473 ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", 00474 desc->name, strerror(errno)); 00475 return NULL; 00476 } 00477 00478 /* if a local address was specified, bind to it so the connection will 00479 originate from the desired address */ 00480 if (!ast_sockaddr_isnull(&desc->local_address)) { 00481 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00482 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00483 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00484 desc->name, 00485 ast_sockaddr_stringify(&desc->local_address), 00486 strerror(errno)); 00487 goto error; 00488 } 00489 } 00490 00491 if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) 00492 goto error; 00493 00494 ast_mutex_init(&tcptls_session->lock); 00495 tcptls_session->client = 1; 00496 tcptls_session->fd = desc->accept_fd; 00497 tcptls_session->parent = desc; 00498 tcptls_session->parent->worker_fn = NULL; 00499 ast_sockaddr_copy(&tcptls_session->remote_address, 00500 &desc->remote_address); 00501 00502 /* Set current info */ 00503 ast_sockaddr_copy(&desc->old_address, &desc->remote_address); 00504 return tcptls_session; 00505 00506 error: 00507 close(desc->accept_fd); 00508 desc->accept_fd = -1; 00509 if (tcptls_session) 00510 ao2_ref(tcptls_session, -1); 00511 return NULL; 00512 }
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 416 of file tcptls.c.
References __ssl_setup(), ao2_ref, ast_connect(), ast_log(), ast_sockaddr_stringify(), desc, errno, handle_tcptls_connection(), LOG_ERROR, and ast_tcptls_session_instance::parent.
Referenced by _sip_tcp_helper_thread().
00417 { 00418 struct ast_tcptls_session_args *desc; 00419 int flags; 00420 00421 if (!(desc = tcptls_session->parent)) { 00422 goto client_start_error; 00423 } 00424 00425 if (ast_connect(desc->accept_fd, &desc->remote_address)) { 00426 ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", 00427 desc->name, 00428 ast_sockaddr_stringify(&desc->remote_address), 00429 strerror(errno)); 00430 goto client_start_error; 00431 } 00432 00433 flags = fcntl(desc->accept_fd, F_GETFL); 00434 fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK); 00435 00436 if (desc->tls_cfg) { 00437 desc->tls_cfg->enabled = 1; 00438 __ssl_setup(desc->tls_cfg, 1); 00439 } 00440 00441 return handle_tcptls_connection(tcptls_session); 00442 00443 client_start_error: 00444 if (desc) { 00445 close(desc->accept_fd); 00446 desc->accept_fd = -1; 00447 } 00448 ao2_ref(tcptls_session, -1); 00449 return NULL; 00450 00451 }
void ast_tcptls_close_session_file | ( | struct ast_tcptls_session_instance * | tcptls_session | ) |
Closes a tcptls session instance's file and/or file descriptor. The tcptls_session will be set to NULL and it's file descriptor will be set to -1 by this function.
Definition at line 583 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::f, ast_tcptls_session_instance::fd, and LOG_ERROR.
Referenced by ast_tcptls_server_root(), handle_tcptls_connection(), and sip_prepare_socket().
00584 { 00585 if (tcptls_session->f) { 00586 if (fclose(tcptls_session->f)) { 00587 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); 00588 } 00589 tcptls_session->f = NULL; 00590 tcptls_session->fd = -1; 00591 } else if (tcptls_session->fd != -1) { 00592 if (close(tcptls_session->fd)) { 00593 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00594 } 00595 tcptls_session->fd = -1; 00596 } else { 00597 ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); 00598 } 00599 }
HOOK_T ast_tcptls_server_read | ( | struct ast_tcptls_session_instance * | ser, | |
void * | buf, | |||
size_t | count | |||
) |
Definition at line 104 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_read().
00105 { 00106 if (tcptls_session->fd == -1) { 00107 ast_log(LOG_ERROR, "server_read called with an fd of -1\n"); 00108 errno = EIO; 00109 return -1; 00110 } 00111 00112 #ifdef DO_SSL 00113 if (tcptls_session->ssl) 00114 return ssl_read(tcptls_session->ssl, buf, count); 00115 #endif 00116 return read(tcptls_session->fd, buf, count); 00117 }
void* ast_tcptls_server_root | ( | void * | ) |
Definition at line 256 of file tcptls.c.
References ao2_alloc, ao2_ref, ast_accept(), ast_log(), ast_mutex_init, ast_pthread_create_detached_background, ast_sockaddr_copy(), ast_tcptls_close_session_file(), ast_wait_for_input(), desc, errno, handle_tcptls_connection(), LOG_ERROR, LOG_WARNING, and session_instance_destructor().
00257 { 00258 struct ast_tcptls_session_args *desc = data; 00259 int fd; 00260 struct ast_sockaddr addr; 00261 struct ast_tcptls_session_instance *tcptls_session; 00262 pthread_t launched; 00263 00264 for (;;) { 00265 int i, flags; 00266 00267 if (desc->periodic_fn) 00268 desc->periodic_fn(desc); 00269 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); 00270 if (i <= 0) 00271 continue; 00272 fd = ast_accept(desc->accept_fd, &addr); 00273 if (fd < 0) { 00274 if ((errno != EAGAIN) && (errno != EINTR)) 00275 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); 00276 continue; 00277 } 00278 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); 00279 if (!tcptls_session) { 00280 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); 00281 if (close(fd)) { 00282 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00283 } 00284 continue; 00285 } 00286 00287 ast_mutex_init(&tcptls_session->lock); 00288 00289 flags = fcntl(fd, F_GETFL); 00290 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 00291 tcptls_session->fd = fd; 00292 tcptls_session->parent = desc; 00293 ast_sockaddr_copy(&tcptls_session->remote_address, &addr); 00294 00295 tcptls_session->client = 0; 00296 00297 /* This thread is now the only place that controls the single ref to tcptls_session */ 00298 if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { 00299 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno)); 00300 ast_tcptls_close_session_file(tcptls_session); 00301 ao2_ref(tcptls_session, -1); 00302 } 00303 } 00304 return NULL; 00305 }
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().
Definition at line 514 of file tcptls.c.
References ast_bind(), ast_debug, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_sockaddr_cmp(), ast_sockaddr_copy(), ast_sockaddr_is_ipv6(), ast_sockaddr_isnull(), ast_sockaddr_setnull(), ast_sockaddr_stringify(), desc, errno, and LOG_ERROR.
00515 { 00516 int flags; 00517 int x = 1; 00518 00519 /* Do nothing if nothing has changed */ 00520 if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { 00521 ast_debug(1, "Nothing changed in %s\n", desc->name); 00522 return; 00523 } 00524 00525 /* If we return early, there is no one listening */ 00526 ast_sockaddr_setnull(&desc->old_address); 00527 00528 /* Shutdown a running server if there is one */ 00529 if (desc->master != AST_PTHREADT_NULL) { 00530 pthread_cancel(desc->master); 00531 pthread_kill(desc->master, SIGURG); 00532 pthread_join(desc->master, NULL); 00533 } 00534 00535 if (desc->accept_fd != -1) 00536 close(desc->accept_fd); 00537 00538 /* If there's no new server, stop here */ 00539 if (ast_sockaddr_isnull(&desc->local_address)) { 00540 ast_debug(2, "Server disabled: %s\n", desc->name); 00541 return; 00542 } 00543 00544 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? 00545 AF_INET6 : AF_INET, SOCK_STREAM, 0); 00546 if (desc->accept_fd < 0) { 00547 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); 00548 return; 00549 } 00550 00551 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00552 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00553 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00554 desc->name, 00555 ast_sockaddr_stringify(&desc->local_address), 00556 strerror(errno)); 00557 goto error; 00558 } 00559 if (listen(desc->accept_fd, 10)) { 00560 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); 00561 goto error; 00562 } 00563 flags = fcntl(desc->accept_fd, F_GETFL); 00564 fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); 00565 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { 00566 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", 00567 desc->name, 00568 ast_sockaddr_stringify(&desc->local_address), 00569 strerror(errno)); 00570 goto error; 00571 } 00572 00573 /* Set current info */ 00574 ast_sockaddr_copy(&desc->old_address, &desc->local_address); 00575 00576 return; 00577 00578 error: 00579 close(desc->accept_fd); 00580 desc->accept_fd = -1; 00581 }
void ast_tcptls_server_stop | ( | struct ast_tcptls_session_args * | desc | ) |
Shutdown a running server if there is one.
Definition at line 601 of file tcptls.c.
References ast_debug, AST_PTHREADT_NULL, and desc.
Referenced by unload_module().
00602 { 00603 if (desc->master != AST_PTHREADT_NULL) { 00604 pthread_cancel(desc->master); 00605 pthread_kill(desc->master, SIGURG); 00606 pthread_join(desc->master, NULL); 00607 desc->master = AST_PTHREADT_NULL; 00608 } 00609 if (desc->accept_fd != -1) 00610 close(desc->accept_fd); 00611 desc->accept_fd = -1; 00612 ast_debug(2, "Stopped server :: %s\n", desc->name); 00613 }
HOOK_T ast_tcptls_server_write | ( | struct ast_tcptls_session_instance * | ser, | |
const void * | buf, | |||
size_t | count | |||
) |
Definition at line 119 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_write().
00120 { 00121 if (tcptls_session->fd == -1) { 00122 ast_log(LOG_ERROR, "server_write called with an fd of -1\n"); 00123 errno = EIO; 00124 return -1; 00125 } 00126 00127 #ifdef DO_SSL 00128 if (tcptls_session->ssl) 00129 return ssl_write(tcptls_session->ssl, buf, count); 00130 #endif 00131 return write(tcptls_session->fd, buf, count); 00132 }
int ast_tls_read_conf | ( | struct ast_tls_config * | tls_cfg, | |
struct ast_tcptls_session_args * | tls_desc, | |||
const char * | varname, | |||
const char * | value | |||
) |
Used to parse conf files containing tls/ssl options.
Definition at line 615 of file tcptls.c.
References ast_clear_flag, ast_free, ast_log(), ast_parse_arg(), ast_set2_flag, ast_set_flag, AST_SSL_DONT_VERIFY_SERVER, AST_SSL_SSLV2_CLIENT, AST_SSL_SSLV3_CLIENT, AST_SSL_TLSV1_CLIENT, AST_SSL_VERIFY_CLIENT, ast_strdup, ast_true(), ast_tls_config::cafile, ast_tls_config::capath, ast_tls_config::certfile, ast_tls_config::cipher, ast_tls_config::enabled, ast_tls_config::flags, ast_tcptls_session_args::local_address, LOG_WARNING, PARSE_ADDR, and ast_tls_config::pvtfile.
Referenced by __ast_http_load(), __init_manager(), and reload_config().
00616 { 00617 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { 00618 tls_cfg->enabled = ast_true(value) ? 1 : 0; 00619 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { 00620 ast_free(tls_cfg->certfile); 00621 tls_cfg->certfile = ast_strdup(value); 00622 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) { 00623 ast_free(tls_cfg->pvtfile); 00624 tls_cfg->pvtfile = ast_strdup(value); 00625 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) { 00626 ast_free(tls_cfg->cipher); 00627 tls_cfg->cipher = ast_strdup(value); 00628 } else if (!strcasecmp(varname, "tlscafile")) { 00629 ast_free(tls_cfg->cafile); 00630 tls_cfg->cafile = ast_strdup(value); 00631 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) { 00632 ast_free(tls_cfg->capath); 00633 tls_cfg->capath = ast_strdup(value); 00634 } else if (!strcasecmp(varname, "tlsverifyclient")) { 00635 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT); 00636 } else if (!strcasecmp(varname, "tlsdontverifyserver")) { 00637 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); 00638 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { 00639 if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) 00640 ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); 00641 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { 00642 if (!strcasecmp(value, "tlsv1")) { 00643 ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00644 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00645 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00646 } else if (!strcasecmp(value, "sslv3")) { 00647 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00648 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00649 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00650 } else if (!strcasecmp(value, "sslv2")) { 00651 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00652 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00653 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00654 } 00655 } else { 00656 return -1; 00657 } 00658 00659 return 0; 00660 }