#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) |
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 | ) |
Definition at line 382 of file tcptls.c.
References __ssl_setup().
00383 { 00384 return __ssl_setup(cfg, 0); 00385 }
struct ast_tcptls_session_instance* ast_tcptls_client_create | ( | struct ast_tcptls_session_args * | desc | ) |
Definition at line 424 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().
00425 { 00426 int x = 1; 00427 struct ast_tcptls_session_instance *tcptls_session = NULL; 00428 00429 /* Do nothing if nothing has changed */ 00430 if (!ast_sockaddr_cmp(&desc->old_address, &desc->remote_address)) { 00431 ast_debug(1, "Nothing changed in %s\n", desc->name); 00432 return NULL; 00433 } 00434 00435 /* If we return early, there is no connection */ 00436 ast_sockaddr_setnull(&desc->old_address); 00437 00438 if (desc->accept_fd != -1) 00439 close(desc->accept_fd); 00440 00441 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->remote_address) ? 00442 AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); 00443 if (desc->accept_fd < 0) { 00444 ast_log(LOG_WARNING, "Unable to allocate socket for %s: %s\n", 00445 desc->name, strerror(errno)); 00446 return NULL; 00447 } 00448 00449 /* if a local address was specified, bind to it so the connection will 00450 originate from the desired address */ 00451 if (!ast_sockaddr_isnull(&desc->local_address)) { 00452 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00453 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00454 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00455 desc->name, 00456 ast_sockaddr_stringify(&desc->local_address), 00457 strerror(errno)); 00458 goto error; 00459 } 00460 } 00461 00462 if (!(tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor))) 00463 goto error; 00464 00465 ast_mutex_init(&tcptls_session->lock); 00466 tcptls_session->client = 1; 00467 tcptls_session->fd = desc->accept_fd; 00468 tcptls_session->parent = desc; 00469 tcptls_session->parent->worker_fn = NULL; 00470 ast_sockaddr_copy(&tcptls_session->remote_address, 00471 &desc->remote_address); 00472 00473 /* Set current info */ 00474 ast_sockaddr_copy(&desc->old_address, &desc->remote_address); 00475 return tcptls_session; 00476 00477 error: 00478 close(desc->accept_fd); 00479 desc->accept_fd = -1; 00480 if (tcptls_session) 00481 ao2_ref(tcptls_session, -1); 00482 return NULL; 00483 }
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 387 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().
00388 { 00389 struct ast_tcptls_session_args *desc; 00390 int flags; 00391 00392 if (!(desc = tcptls_session->parent)) { 00393 goto client_start_error; 00394 } 00395 00396 if (ast_connect(desc->accept_fd, &desc->remote_address)) { 00397 ast_log(LOG_ERROR, "Unable to connect %s to %s: %s\n", 00398 desc->name, 00399 ast_sockaddr_stringify(&desc->remote_address), 00400 strerror(errno)); 00401 goto client_start_error; 00402 } 00403 00404 flags = fcntl(desc->accept_fd, F_GETFL); 00405 fcntl(desc->accept_fd, F_SETFL, flags & ~O_NONBLOCK); 00406 00407 if (desc->tls_cfg) { 00408 desc->tls_cfg->enabled = 1; 00409 __ssl_setup(desc->tls_cfg, 1); 00410 } 00411 00412 return handle_tcptls_connection(tcptls_session); 00413 00414 client_start_error: 00415 close(desc->accept_fd); 00416 desc->accept_fd = -1; 00417 if (tcptls_session) { 00418 ao2_ref(tcptls_session, -1); 00419 } 00420 return NULL; 00421 00422 }
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 554 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().
00555 { 00556 if (tcptls_session->f) { 00557 if (fclose(tcptls_session->f)) { 00558 ast_log(LOG_ERROR, "fclose() failed: %s\n", strerror(errno)); 00559 } 00560 tcptls_session->f = NULL; 00561 tcptls_session->fd = -1; 00562 } else if (tcptls_session->fd != -1) { 00563 if (close(tcptls_session->fd)) { 00564 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00565 } 00566 tcptls_session->fd = -1; 00567 } else { 00568 ast_log(LOG_ERROR, "ast_tcptls_close_session_file invoked on session instance without file or file descriptor\n"); 00569 } 00570 }
HOOK_T ast_tcptls_server_read | ( | 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_read().
00101 { 00102 if (tcptls_session->fd == -1) { 00103 ast_log(LOG_ERROR, "server_read 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_read(tcptls_session->ssl, buf, count); 00111 #endif 00112 return read(tcptls_session->fd, buf, count); 00113 }
void* ast_tcptls_server_root | ( | void * | ) |
Definition at line 251 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().
00252 { 00253 struct ast_tcptls_session_args *desc = data; 00254 int fd; 00255 struct ast_sockaddr addr; 00256 struct ast_tcptls_session_instance *tcptls_session; 00257 pthread_t launched; 00258 00259 for (;;) { 00260 int i, flags; 00261 00262 if (desc->periodic_fn) 00263 desc->periodic_fn(desc); 00264 i = ast_wait_for_input(desc->accept_fd, desc->poll_timeout); 00265 if (i <= 0) 00266 continue; 00267 fd = ast_accept(desc->accept_fd, &addr); 00268 if (fd < 0) { 00269 if ((errno != EAGAIN) && (errno != EINTR)) 00270 ast_log(LOG_WARNING, "Accept failed: %s\n", strerror(errno)); 00271 continue; 00272 } 00273 tcptls_session = ao2_alloc(sizeof(*tcptls_session), session_instance_destructor); 00274 if (!tcptls_session) { 00275 ast_log(LOG_WARNING, "No memory for new session: %s\n", strerror(errno)); 00276 if (close(fd)) { 00277 ast_log(LOG_ERROR, "close() failed: %s\n", strerror(errno)); 00278 } 00279 continue; 00280 } 00281 00282 ast_mutex_init(&tcptls_session->lock); 00283 00284 flags = fcntl(fd, F_GETFL); 00285 fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); 00286 tcptls_session->fd = fd; 00287 tcptls_session->parent = desc; 00288 ast_sockaddr_copy(&tcptls_session->remote_address, &addr); 00289 00290 tcptls_session->client = 0; 00291 00292 /* This thread is now the only place that controls the single ref to tcptls_session */ 00293 if (ast_pthread_create_detached_background(&launched, NULL, handle_tcptls_connection, tcptls_session)) { 00294 ast_log(LOG_WARNING, "Unable to launch helper thread: %s\n", strerror(errno)); 00295 ast_tcptls_close_session_file(tcptls_session); 00296 ao2_ref(tcptls_session, -1); 00297 } 00298 } 00299 return NULL; 00300 }
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 485 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.
00486 { 00487 int flags; 00488 int x = 1; 00489 00490 /* Do nothing if nothing has changed */ 00491 if (!ast_sockaddr_cmp(&desc->old_address, &desc->local_address)) { 00492 ast_debug(1, "Nothing changed in %s\n", desc->name); 00493 return; 00494 } 00495 00496 /* If we return early, there is no one listening */ 00497 ast_sockaddr_setnull(&desc->old_address); 00498 00499 /* Shutdown a running server if there is one */ 00500 if (desc->master != AST_PTHREADT_NULL) { 00501 pthread_cancel(desc->master); 00502 pthread_kill(desc->master, SIGURG); 00503 pthread_join(desc->master, NULL); 00504 } 00505 00506 if (desc->accept_fd != -1) 00507 close(desc->accept_fd); 00508 00509 /* If there's no new server, stop here */ 00510 if (ast_sockaddr_isnull(&desc->local_address)) { 00511 ast_debug(2, "Server disabled: %s\n", desc->name); 00512 return; 00513 } 00514 00515 desc->accept_fd = socket(ast_sockaddr_is_ipv6(&desc->local_address) ? 00516 AF_INET6 : AF_INET, SOCK_STREAM, 0); 00517 if (desc->accept_fd < 0) { 00518 ast_log(LOG_ERROR, "Unable to allocate socket for %s: %s\n", desc->name, strerror(errno)); 00519 return; 00520 } 00521 00522 setsockopt(desc->accept_fd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 00523 if (ast_bind(desc->accept_fd, &desc->local_address)) { 00524 ast_log(LOG_ERROR, "Unable to bind %s to %s: %s\n", 00525 desc->name, 00526 ast_sockaddr_stringify(&desc->local_address), 00527 strerror(errno)); 00528 goto error; 00529 } 00530 if (listen(desc->accept_fd, 10)) { 00531 ast_log(LOG_ERROR, "Unable to listen for %s!\n", desc->name); 00532 goto error; 00533 } 00534 flags = fcntl(desc->accept_fd, F_GETFL); 00535 fcntl(desc->accept_fd, F_SETFL, flags | O_NONBLOCK); 00536 if (ast_pthread_create_background(&desc->master, NULL, desc->accept_fn, desc)) { 00537 ast_log(LOG_ERROR, "Unable to launch thread for %s on %s: %s\n", 00538 desc->name, 00539 ast_sockaddr_stringify(&desc->local_address), 00540 strerror(errno)); 00541 goto error; 00542 } 00543 00544 /* Set current info */ 00545 ast_sockaddr_copy(&desc->old_address, &desc->local_address); 00546 00547 return; 00548 00549 error: 00550 close(desc->accept_fd); 00551 desc->accept_fd = -1; 00552 }
void ast_tcptls_server_stop | ( | struct ast_tcptls_session_args * | desc | ) |
Shutdown a running server if there is one.
Definition at line 572 of file tcptls.c.
References ast_debug, AST_PTHREADT_NULL, and desc.
Referenced by unload_module().
00573 { 00574 if (desc->master != AST_PTHREADT_NULL) { 00575 pthread_cancel(desc->master); 00576 pthread_kill(desc->master, SIGURG); 00577 pthread_join(desc->master, NULL); 00578 desc->master = AST_PTHREADT_NULL; 00579 } 00580 if (desc->accept_fd != -1) 00581 close(desc->accept_fd); 00582 desc->accept_fd = -1; 00583 ast_debug(2, "Stopped server :: %s\n", desc->name); 00584 }
HOOK_T ast_tcptls_server_write | ( | struct ast_tcptls_session_instance * | ser, | |
const void * | buf, | |||
size_t | count | |||
) |
Definition at line 115 of file tcptls.c.
References ast_log(), errno, ast_tcptls_session_instance::fd, LOG_ERROR, ast_tcptls_session_instance::ssl, and ssl_write().
00116 { 00117 if (tcptls_session->fd == -1) { 00118 ast_log(LOG_ERROR, "server_write called with an fd of -1\n"); 00119 errno = EIO; 00120 return -1; 00121 } 00122 00123 #ifdef DO_SSL 00124 if (tcptls_session->ssl) 00125 return ssl_write(tcptls_session->ssl, buf, count); 00126 #endif 00127 return write(tcptls_session->fd, buf, count); 00128 }
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 586 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().
00587 { 00588 if (!strcasecmp(varname, "tlsenable") || !strcasecmp(varname, "sslenable")) { 00589 tls_cfg->enabled = ast_true(value) ? 1 : 0; 00590 } else if (!strcasecmp(varname, "tlscertfile") || !strcasecmp(varname, "sslcert") || !strcasecmp(varname, "tlscert")) { 00591 ast_free(tls_cfg->certfile); 00592 tls_cfg->certfile = ast_strdup(value); 00593 } else if (!strcasecmp(varname, "tlsprivatekey") || !strcasecmp(varname, "sslprivatekey")) { 00594 ast_free(tls_cfg->pvtfile); 00595 tls_cfg->pvtfile = ast_strdup(value); 00596 } else if (!strcasecmp(varname, "tlscipher") || !strcasecmp(varname, "sslcipher")) { 00597 ast_free(tls_cfg->cipher); 00598 tls_cfg->cipher = ast_strdup(value); 00599 } else if (!strcasecmp(varname, "tlscafile")) { 00600 ast_free(tls_cfg->cafile); 00601 tls_cfg->cafile = ast_strdup(value); 00602 } else if (!strcasecmp(varname, "tlscapath") || !strcasecmp(varname, "tlscadir")) { 00603 ast_free(tls_cfg->capath); 00604 tls_cfg->capath = ast_strdup(value); 00605 } else if (!strcasecmp(varname, "tlsverifyclient")) { 00606 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_VERIFY_CLIENT); 00607 } else if (!strcasecmp(varname, "tlsdontverifyserver")) { 00608 ast_set2_flag(&tls_cfg->flags, ast_true(value), AST_SSL_DONT_VERIFY_SERVER); 00609 } else if (!strcasecmp(varname, "tlsbindaddr") || !strcasecmp(varname, "sslbindaddr")) { 00610 if (ast_parse_arg(value, PARSE_ADDR, &tls_desc->local_address)) 00611 ast_log(LOG_WARNING, "Invalid %s '%s'\n", varname, value); 00612 } else if (!strcasecmp(varname, "tlsclientmethod") || !strcasecmp(varname, "sslclientmethod")) { 00613 if (!strcasecmp(value, "tlsv1")) { 00614 ast_set_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00615 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00616 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00617 } else if (!strcasecmp(value, "sslv3")) { 00618 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00619 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00620 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00621 } else if (!strcasecmp(value, "sslv2")) { 00622 ast_set_flag(&tls_cfg->flags, AST_SSL_SSLV2_CLIENT); 00623 ast_clear_flag(&tls_cfg->flags, AST_SSL_TLSV1_CLIENT); 00624 ast_clear_flag(&tls_cfg->flags, AST_SSL_SSLV3_CLIENT); 00625 } 00626 } else { 00627 return -1; 00628 } 00629 00630 return 0; 00631 }