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