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 |
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) |
Generic support for tcp/tls servers in Asterisk.
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.
Definition in file tcptls.h.
| #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().
| enum ast_ssl_flags |
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 };
| 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().
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.
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().
| 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 }
1.6.1